Exports and Modules

The entry __init__.pyi controls the extension's Python namespace. Leaf .pyi files describe native modules and their declarations.

Choose the Package Shape

Generated entry contract:

from . import module1
from . import module2

Python then uses package.module1 and package.module2. To place both modules' public names directly in package, edit the entry contract:

from .module1 import *
from .module2 import *

Selective imports and aliases also work:

from .module1 import solve
from .module2 import reset as clear

Changing entry imports changes only the Python namespace. It does not rename a native module or select a native object file.

Only declarations reachable from __init__.pyi are public. Missing files, import cycles, and two different exports using the same Python name are errors. Explicit aliases share the same native target, but Python object identity is not guaranteed for every read.

Remove or Hide a Declaration

Delete a declaration to remove it from the Python API:

from prik.contracts import Int32

counter: Int32

def summarize() -> Int32: ...

The removed declaration is not regenerated during this build. This works for functions, variables, classes, methods, fields, constructors, and individual overload candidates.

Use @private for a function or class that another contract declaration still needs:

from prik.contracts import Float64, private

@private
def scaled_counter() -> Float64: ...

Use private[...] for a variable or argument:

from prik.contracts import Float64, private

scale: private[Float64]

Both forms keep the declaration in the contract while hiding it from Python.

Add or Rename a Native Procedure

You may add a declaration when the procedure already exists in the supplied native implementation:

from prik.contracts import Float64

def norm2(values: Float64[:]) -> Float64: ...

In a module leaf, the filename identifies the native module and the function name selects the native procedure. Use @bind(...) when the Python name differs:

from prik.contracts import Float64, Int32, bind

@bind("solver_step")
def step(values: Float64[:]) -> Int32: ...

For a standalone external symbol, also use @external:

from prik.contracts import Float64, bind, external

@external
@bind("vendor_norm2")
def norm2(values: Float64[:]) -> Float64: ...

The declaration must include the correct native arguments, types, ranks, and call shape. Adding Python syntax cannot create a native procedure that is not present in the linked implementation.

Set Module Values at Import

A writable scalar module variable may have a literal initial value:

from prik.contracts import Int32

counter: Int32 = 41

prik sets the module variable when the extension is imported. It remains writable. This works only when prik can write that native variable, and the initializer must be a literal rather than a call, name, or expression.

Use Final[...] only for a true read-only constant:

from prik.contracts import Final, Int32

nmax: Final[Int32] = 12

See Wrapping Modules for the resulting Python usage.

Next

Use Functions and Classes to add methods, overloads, or a custom constructor.