C Outputs and Errors¶
An authored contract decides which C pointer parameters are visible Python arguments, returned values, or native-only status storage.
Return several C outputs¶
Use a named Return(...) slot for every native output pointer that should
become part of the Python return value.
Create stats.c:
#include <stddef.h>
void stats_compute(size_t count, const double *values, double *mean, double *total) {
double sum = 0.0;
for (size_t index = 0; index < count; ++index) {
sum += values[index];
}
*total = sum;
*mean = count ? sum / (double)count : 0.0;
}
Create stats.pyi:
from prik.contracts import Arg, Float64, Return, Returns, bind, native_call
@bind("stats_compute")
@native_call([Arg(0).shape[0], Arg(0), Return("mean", 0), Return("total", 1)])
def summarize(values: Float64[:]) -> tuple[Returns["mean", Float64], Returns["total", Float64]]: ...
python3 -m prik --language c stats.pyi \
--native-c-sources stats.c \
--compiler cc \
--out stats \
--out-dir build
import sys
import numpy as np
sys.path.insert(0, "build")
import stats
mean, total = stats.summarize(np.array([1.0, 2.0, 3.0, 4.0], dtype=np.float64))
print(mean, total)
2.5 10.0
See Calls and Results for the complete shared contract vocabulary.
Hide native outputs and raise Python exceptions¶
Use Hidden(name, T) for C output storage that Python should not return. A
common case is a status value and diagnostic message consumed by @raises.
Create checked.c:
#include <string.h>
void checked_sqrt(double value, double *root, int *status, char *message) {
if (value < 0.0) {
*status = -1;
*root = 0.0;
strcpy(message, "value must not be negative");
return;
}
*status = 0;
message[0] = '\0';
*root = value == 4.0 ? 2.0 : value;
}
Create checked.pyi:
from prik.contracts import Arg, Float64, Hidden, Int32, Return, Returns, String, native_call, raises
@raises(status="status", message="message", success=0)
@native_call([Arg(0), Return("root", 0), Hidden("status", Int32), Hidden("message", String[64])])
def checked_sqrt(value: Float64) -> Returns["root", Float64]: ...
python3 -m prik --language c checked.pyi \
--native-c-sources checked.c \
--compiler cc \
--out checked \
--out-dir build
import sys
import numpy as np
sys.path.insert(0, "build")
import checked
print(checked.checked_sqrt(np.float64(4.0)))
try:
checked.checked_sqrt(np.float64(-1.0))
except RuntimeError as error:
print(error)
2.0
value must not be negative
The function returns only root; status and message produce a
RuntimeError on failure. A hidden message needs a fixed capacity because
PRIK allocates its native storage.
A caller-owned visible message buffer uses rank-zero NumPy storage:
@raises(status="status", message="message", success=0)
@native_call([Arg(0), Arg(1), Hidden("status", Int32)])
def checked(value: Float64, message: String[64][()]) -> None: ...
The caller can inspect the S64 array after the call or exception.
Next¶
Continue with Symbols, Headers, and Dependencies for larger native APIs and libraries.