Skip to content
Pyrula

Core

Generated from the type stubs and docstrings. Do not edit by hand.

check_compatibility(self, schema: str, version: Optional[str] = None) -> Ok[bool] | Err[SerdeError]
delete_version(self, version: int) -> Ok[bool] | Err[SerdeError]
deserialize(self, data: bytes) -> Ok[Any] | Err[SerdeError]

Deserialize Confluent wire-format bytes, fetching schema from registry by ID.

deserialize_many(self, bytes_list: BytesList) -> IList

Deserialize BytesList to IList[Either[DeserializationError, obj]].

deserialize_many_objects(self, bytes_list: BytesList) -> IList

Deserialize BytesList directly to IList[obj], raising DeserializationError on first failure.

for_topic(registry_url: str, topic: str, schema: str, is_key: bool = False, username: Optional[str] = None, password: Optional[str] = None, ca_path: Optional[str] = None, cert_path: Optional[str] = None, key_path: Optional[str] = None) -> AvroRegistrySerde

Convenience constructor - derives subject as “{topic}-value” or “{topic}-key”.

get_schema_by_version(self, version: int) -> Ok[str] | Err[SerdeError]
list_versions(self) -> Ok[list[int]] | Err[SerdeError]
register(self) -> Ok[int] | Err[SerdeError]

Eagerly register this serde’s schema with the registry. Returns Either[SerializationError, int] where int is the assigned schema ID. Not required - serialize() registers lazily on first call.

serialize(self, obj: Any) -> Ok[bytes] | Err[SerdeError]
serialize_many(self, items: IList) -> IList
serialize_many_bytes(self, items: IList) -> BytesList

Serialize IList directly to BytesList, raising SerializationError on first failure.

subject(self) -> str

deserialize(self, data: bytes) -> Ok[Any] | Err[SerdeError]
deserialize_many(self, bytes_list: BytesList) -> IList
serialize(self, obj: Any) -> Ok[bytes] | Err[SerdeError]
serialize_many(self, items: IList) -> IList
serialize_many_bytes(self, items: IList) -> BytesList

Serialize IList directly to BytesList, raising SerializationError on first failure.


Immutable list of byte sequences (Vec<Vec<u8>>).

Each element is a bytes object in Python. Supports conversion to IList[bytes] via to_ilist().

append(self, item: bytes) -> BytesList
empty() -> BytesList
from_packed(buf, count)

Build from one length-framed buffer: count records, each a little-endian u32 length followed by that many bytes. Lets the Kafka consumer hand the whole batch across the extension boundary as a single bytes object - one copy + one parse - instead of allocating a bytes per record and re-extracting each. count lets us pre-size inner.

get(self, index: int) -> Some[bytes] | _Nothing
is_empty(self) -> bool
length(self) -> int
to_ilist(self) -> IList[bytes]
to_list(self) -> list[bytes]
to_packed(self) -> bytes

Export as one length-framed bytes object: count * (u32 little-endian length + payload).



A typed time-span value backed by an i64 nanosecond count.

Mirrors Scala’s FiniteDuration - a precise, immutable quantity of time with unit-converting constructors and full arithmetic support.

from pyrula import Duration
d = Duration.seconds(1) + Duration.millis(500)
assert d.to_millis() == 1500
import datetime
assert Duration.seconds(1).to_timedelta() == datetime.timedelta(seconds=1)
days(n: float) -> Duration

Create a Duration from a number of days (fractional days allowed).

from_timedelta(td: Any) -> Duration

Create a Duration from a Python datetime.timedelta.

hours(n: float) -> Duration

Create a Duration from a number of hours (fractional hours allowed).

micros(n: int) -> Duration

Create a Duration from a microsecond count.

millis(n: int) -> Duration

Create a Duration from a millisecond count.

minutes(n: float) -> Duration

Create a Duration from a number of minutes (fractional minutes allowed).

nanos(n: int) -> Duration

Create a Duration from a nanosecond count.

seconds(n: float) -> Duration

Create a Duration from a number of seconds (fractional seconds allowed).

to_millis(self) -> int

Milliseconds, truncating sub-millisecond precision.

to_nanos(self) -> int

The raw nanosecond count.

to_seconds(self) -> float

Seconds as a float.

to_timedelta(self) -> Any

Convert to a Python datetime.timedelta.

Resolution is microseconds (Python’s timedelta does not support nanosecond precision). Sub-microsecond nanos are truncated.


The base of the Either result type: an Ok value or an Err error.

Ok and Err subclass Either, the same way Scala’s Either is subclassed by Right and Left. So isinstance(x, Either) holds for both cases and Either[A, E] is a real generic alias. Either is abstract: construct values through Either.ok / Either.err (or Ok / Err directly), not Either(...).

cond(condition: bool, ok: T, err: E) -> Either[T, E]

Ok(ok) if condition else Err(err).

err(error: E) -> Err[E]

Err(error).

ok(value: T) -> Ok[T]

Ok(value).

sequence(values: Iterable[Either[T, E]]) -> Either[list[T], E]

Ok of every value, or the first Err encountered.

try_of(f: Callable[[], T]) -> Either[T, Exception]

Ok(f()), or Err(exc) if f raises an Exception. A BaseException (KeyboardInterrupt, SystemExit) propagates rather than being captured.


Fields:

  • error: E
flat_map(self, _f) -> Err[E]
fold(self, err: Callable[..., Any], _ok) -> Any
get_or_else(self, default: Any) -> Any
is_err(self) -> bool
is_ok(self) -> bool
map(self, _f) -> Err[E]
map_err(self, f: Callable[..., Any]) -> Err[Any]
or_else(self, default: Any) -> Any
recover(self, f: Callable[..., Any]) -> Any
to_option(self) -> _Nothing
unwrap_or_raise(self, exc: Any = None) -> Any

With exc: raise it. Without: raise the contained error if it is an exception, else RuntimeError - so result.unwrap_or_raise() replaces the if result.is_err(): raise result.error boilerplate.


Fields:

  • error: BaseException
flat_map(self, _f) -> Failure
fold(self, failure: Callable[..., Any], _success) -> Any
get_or_else(self, default: Any) -> Any
is_failure(self) -> bool
is_success(self) -> bool
map(self, _f) -> Failure
or_else(self, default: Any) -> Any
recover(self, f: Callable[..., Any]) -> Any
to_either(self) -> Err[Any]

Immutable list of f64 values with typed scalar operations.

Scalar methods (add_scalar, mul_scalar, min, max, sum) run on rayon’s thread pool without touching the GIL. Callback-based methods (map_float, filter, fold_left) require the GIL for the Python closure.

abs_vals(self) -> FloatList
add_scalar(self, n: float) -> FloatList
clamp_vals(self, lo: float, hi: float) -> FloatList
div_scalar(self, n: float) -> FloatList
empty() -> FloatList
filter(self, pred: Callable[[float], bool]) -> FloatList
fold_left(self, initial: Any, f: Callable[..., Any]) -> Any
is_empty(self) -> bool
length(self) -> int
map_float(self, f: Callable[[float], float]) -> FloatList
max(self) -> float
mean(self) -> float
min(self) -> float
mul_scalar(self, n: float) -> FloatList
std_dev(self) -> float
sub_scalar(self, n: float) -> FloatList
sum(self) -> float
to_ilist(self) -> IList[float]
to_list(self) -> list[float]
zip_add(self, other: FloatList) -> FloatList
zip_mul(self, other: FloatList) -> FloatList

Immutable persistent list - structural sharing via im-rs. Arc<Py> elements allow im::Vector to clone nodes without the GIL.

append(self, item: T) -> IList[T]
collect_err(self) -> IList[Any]

Extract all Err values from an IList of Either[Ok, Err].

collect_ok(self) -> IList[Any]
concat(self, other: IList[T]) -> IList[T]
distinct(self) -> IList[T]
drop(self, n: int) -> IList[T]
empty() -> IList[Any]
filter(self, pred: Callable[..., bool]) -> IList[T]
find(self, pred: Callable[..., bool]) -> Some[T] | _Nothing
flat_map(self, f: Callable[..., Any]) -> IList[Any]
fold_left(self, initial: Any, f: Callable[..., Any]) -> Any
head(self) -> Some[T] | _Nothing
is_empty(self) -> bool
last(self) -> Some[T] | _Nothing
length(self) -> int
map(self, f: Callable[..., Any]) -> IList[Any]
partition_either(self) -> tuple[IList[Any], IList[Any]]

Partition an IList of Either[Ok, Err] into (oks, errs).

prepend(self, item: T) -> IList[T]
tail(self) -> IList[T]
take(self, n: int) -> IList[T]
to_list(self) -> list[T]
zip(self, other: IList[Any]) -> IList[tuple[T, Any]]

Pair each element with the element at the same index in other, stopping at the shorter of the two lists. Yields (self, other) tuples.


contains(self, key: K) -> bool
empty() -> IMap[Any, Any]
filter_values(self, pred: Callable[[V], bool]) -> IMap[K, V]
get(self, key: K) -> Some[V] | _Nothing

Return the value for key, or nothing() if not present.

is_empty(self) -> bool
items(self) -> IList[tuple[K, V]]
keys(self) -> IList[K]
length(self) -> int
map_values(self, f: Callable[[V], Any]) -> IMap[K, Any]
merge(self, other: IMap[K, V]) -> IMap[K, V]
remove(self, key: K) -> IMap[K, V]
set(self, key: K, value: V) -> IMap[K, V]
to_dict(self) -> dict

Convert to a standard Python dict.

values(self) -> IList[V]

Immutable persistent set - structural sharing via im-rs HashSet.

add(self, item: T) -> ISet[T]

Return a new ISet with item added. No-op if already present.

contains(self, item: T) -> bool

Return true if item is in this set.

difference(self, other: ISet[T]) -> ISet[T]

Return a new ISet with elements of this set that are not in other.

empty() -> ISet[Any]
filter(self, pred: Callable[[T], bool]) -> ISet[T]

Return a new ISet containing only elements for which pred returns true.

intersection(self, other: ISet[T]) -> ISet[T]

Return a new ISet containing only elements present in both sets.

is_empty(self) -> bool
is_subset_of(self, other: ISet[T]) -> bool

Return true if every element of this set is also in other.

map(self, f: Callable[[T], Any]) -> ISet[Any]

Apply f to each element and return a new ISet of the results.

remove(self, item: T) -> ISet[T]

Return a new ISet with item removed. No-op if absent.

size(self) -> int

Number of elements in this set.

to_ilist(self) -> IList[T]

Convert to an IList. Order is unspecified (hash set iteration order).

to_set(self) -> set[T]

Convert to a standard Python set.

union(self, other: ISet[T]) -> ISet[T]

Return a new ISet that is the union of this set and other.


Immutable list of i64 values with typed scalar operations.

Scalar methods (add_scalar, mul_scalar, min, max, sum) run on rayon’s thread pool without touching the GIL. Callback-based methods (map_int, filter, fold_left) require the GIL for the Python closure.

abs_vals(self) -> IntList
add_scalar(self, n: int) -> IntList
clamp_vals(self, lo: int, hi: int) -> IntList
div_scalar(self, n: int) -> IntList
empty() -> IntList
filter(self, pred: Callable[[int], bool]) -> IntList
fold_left(self, initial: Any, f: Callable[..., Any]) -> Any
is_empty(self) -> bool
length(self) -> int
map_int(self, f: Callable[[int], int]) -> IntList
max(self) -> int
mean(self) -> float
min(self) -> int
mul_scalar(self, n: int) -> IntList
std_dev(self) -> float
sub_scalar(self, n: int) -> IntList
sum(self) -> int
to_ilist(self) -> IList[int]
to_list(self) -> list[int]
zip_add(self, other: IntList) -> IntList
zip_mul(self, other: IntList) -> IntList

Immutable set of non-negative integers backed by a Roaring bitmap.

Set algebra (union, intersection, difference, cardinality, …) runs entirely in Rust over compressed bitmaps - no per-element Python callbacks and no GIL contention. Construction and to_list cross the boundary once per element, the same as building a Python set; the payoff is the operations.

add(self, value: int) -> IntSet
cardinality(self) -> int
contains(self, value: int) -> bool
difference(self, other: IntSet) -> IntSet
empty() -> IntSet
from_bytes(data: bytes) -> IntSet

Reconstruct an IntSet from to_bytes output (Roaring portable format).

intersection(self, other: IntSet) -> IntSet
is_disjoint(self, other: IntSet) -> bool
is_empty(self) -> bool
is_subset(self, other: IntSet) -> bool
remove(self, value: int) -> IntSet
symmetric_difference(self, other: IntSet) -> IntSet
to_bytes(self) -> bytes

Serialize to the Roaring portable byte format, suitable for durable checkpoints or interop with other Roaring implementations.

to_list(self) -> list[int]
union(self, other: IntSet) -> IntSet

Fields:

  • errors: list[E] Always a Python list of error values.
fold(self, invalid_fn, _valid_fn)

fold(invalid_fn, valid_fn) - calls invalid_fn(errors).

get_or_else(self, default)

Return default.

is_invalid(self)
is_valid(self)
map(self, _f)

Pass-through: map on Invalid is a no-op (returns a fresh copy).

map_err(self, f)

Invalid(f(errors)). f receives the errors list and must return a new value (usually a list) to use as the new error collection.

to_either(self)

Err(errors_list).

zip(self, other)

Combine with other. Concatenates error lists from both sides. Valid on other contributes no errors.


check_compatibility(self, schema: str, version: Optional[str] = None) -> Ok[bool] | Err[SerdeError]
delete_version(self, version: int) -> Ok[bool] | Err[SerdeError]
deserialize(self, data: bytes) -> Ok[Any] | Err[SerdeError]
deserialize_many(self, bytes_list: BytesList) -> IList
deserialize_many_objects(self, bytes_list: BytesList) -> IList
for_topic(registry_url: str, topic: str, schema: str, is_key: bool = False, username: Optional[str] = None, password: Optional[str] = None, ca_path: Optional[str] = None, cert_path: Optional[str] = None, key_path: Optional[str] = None) -> JsonSchemaRegistrySerde
get_schema_by_version(self, version: int) -> Ok[str] | Err[SerdeError]
list_versions(self) -> Ok[list[int]] | Err[SerdeError]
register(self) -> Ok[int] | Err[SerdeError]
serialize(self, obj: Any) -> Ok[bytes] | Err[SerdeError]
serialize_many(self, items: IList) -> IList
serialize_many_bytes(self, items: IList) -> BytesList
subject(self) -> str

deserialize(self, data: bytes) -> Ok[Any] | Err[SerdeError]
deserialize_many(self, bytes_list: BytesList) -> IList
deserialize_many_raw(self, bytes_list: BytesList) -> IList

Fail-fast deserialization from BytesList returning IList directly.

serialize(self, obj: Any) -> Ok[bytes] | Err[SerdeError]
serialize_many(self, items: IList) -> IList
serialize_many_raw(self, items: IList) -> BytesList

Fail-fast serialization returning BytesList directly.


NonEmptyList - a list provably containing at least one element.

head, last, and reduce are total (return A, never Option) because the non-empty invariant is upheld by the constructor. from_list converts a plain list or IList into Option[NonEmptyList], making the emptiness check explicit at the boundary.

append(self, item: T) -> NonEmptyList[T]

Append an element to the end, returning a new NonEmptyList.

flat_map(self, f: Callable[[T], NonEmptyList[Any]]) -> NonEmptyList[Any]

flat_map - each element maps to a NonEmptyList; results are concatenated. The overall result is still non-empty (at least the first mapped NEL contributes one element).

fold_left(self, init: Any, f: Callable[[Any, T], Any]) -> Any

Left fold with an explicit initial accumulator.

from_list(items: IList[T] | list[T]) -> Option[NonEmptyList[T]]

Convert an IList[T] or list[T] into Option[NonEmptyList[T]].

Returns Some(nel) when the input is non-empty, Nothing otherwise.

head(self) -> T

The first element - total (never Option) because the list is non-empty.

last(self) -> T

The last element - total for the same reason.

length(self) -> int

Number of elements (always >= 1).

map(self, f: Callable[[T], Any]) -> NonEmptyList[Any]

Element-wise map - result is still a NonEmptyList.

of(head: T, *tail: T) -> NonEmptyList[T]

Alias for NonEmptyList(head, *tail).

prepend(self, item: T) -> NonEmptyList[T]

Prepend an element to the front, returning a new NonEmptyList.

reduce(self, f: Callable[[T, T], T]) -> T

Fold the list with f, seeded by head. Total - non-empty list always has at least the head to return.

tail(self) -> IList[T]

All elements except the first, as an IList (may be empty).

to_ilist(self) -> IList[T]

Convert to an IList.

to_list(self) -> list[T]

Convert to a plain Python list.


Fields:

  • value: T
flat_map(self, f: Callable[..., Any]) -> Any
fold(self, _err, ok: Callable[..., Any]) -> Any
get_or_else(self, _default) -> T
is_err(self) -> bool
is_ok(self) -> bool
map(self, f: Callable[..., Any]) -> Ok[Any]
map_err(self, _f) -> Ok[T]
or_else(self, _default) -> Ok[T]
recover(self, _f) -> Ok[T]
to_option(self) -> Some[T]
unwrap_or_raise(self, exc: Any = None) -> T

The base of the Option type: a Some value or Nothing.

Some and Nothing subclass Option, mirroring Scala’s Option subclassed by Some and None. So isinstance(x, Option) holds for both cases and Option[T] is a real generic alias. Option is abstract: construct values through Option.of / Option.when (or Some / Nothing directly), not Option(...).

from_callable(f: Callable[[], T]) -> Option[T]

Some(f()) if f returns a non-None value; Nothing if f returns None or raises an Exception. A BaseException (KeyboardInterrupt, SystemExit) propagates rather than being captured.

of(value: Optional[T]) -> Option[T]

Some(value) if value is not None, else Nothing.

sequence(values: Iterable[Option[T]]) -> Option[list[T]]

Some of every value in the iterable, or Nothing if any element is Nothing.

when(condition: bool, value: T) -> Option[T]

Some(value) if condition is True, else Nothing.


check_compatibility(self, proto_source: str, version: Optional[str] = None) -> Ok[bool] | Err[SerdeError]
delete_version(self, version: int) -> Ok[bool] | Err[SerdeError]
deserialize(self, data: bytes) -> Ok[Any] | Err[SerdeError]
deserialize_many(self, bytes_list: BytesList) -> IList
deserialize_many_objects(self, bytes_list: BytesList) -> IList
for_topic(registry_url: str, topic: str, file_descriptor_set: bytes, message_name: str, is_key: bool = False, proto_source: Optional[str] = None, username: Optional[str] = None, password: Optional[str] = None, ca_path: Optional[str] = None, cert_path: Optional[str] = None, key_path: Optional[str] = None) -> ProtobufRegistrySerde
get_schema_by_version(self, version: int) -> Ok[str] | Err[SerdeError]
list_versions(self) -> Ok[list[int]] | Err[SerdeError]
register(self) -> Ok[int] | Err[SerdeError]
serialize(self, obj: Any) -> Ok[bytes] | Err[SerdeError]
serialize_many(self, items: IList) -> IList
serialize_many_bytes(self, items: IList) -> BytesList
serialize_with_id(self, obj: Any, schema_id: int) -> Ok[bytes] | Err[SerdeError]
subject(self) -> str



Fields:

  • value: T
filter(self, pred: Callable[..., bool]) -> Any
flat_map(self, f: Callable[..., Any]) -> Any
fold(self, _nothing_val, some_fn: Callable[..., Any]) -> Any
get_or_else(self, _default) -> T
is_empty(self) -> bool
is_nothing(self) -> bool
is_some(self) -> bool
map(self, f: Callable[..., Any]) -> Some[Any]
or_else(self, _default) -> Some[T]
to_either(self, _left) -> Ok[T]
to_list(self) -> IList[T]

Fields:

  • value: T
flat_map(self, f: Callable[..., Any]) -> Any
fold(self, _failure, success: Callable[..., Any]) -> Any
get_or_else(self, _default) -> T
is_failure(self) -> bool
is_success(self) -> bool
map(self, f: Callable[..., Any]) -> Any
or_else(self, _default) -> Success[T]
recover(self, _f) -> Success[T]
to_either(self) -> Ok[T]

The base of the Try result type: a Success value or a Failure exception.

Success and Failure subclass Try, the same way Scala’s Try is subclassed by Success and Failure. So isinstance(x, Try) holds for both cases and Try[A] is a real generic alias. Try is abstract: construct values through Try.apply / Try.of (or Success / Failure directly), not Try(...).

apply(f: Callable[[], T]) -> Try[T]

Success(f()), or Failure(exc) if f raises an Exception. A BaseException (KeyboardInterrupt, SystemExit) propagates rather than being captured.

of(f: Callable[[], T]) -> Try[T]

Alias for Try.apply.

sequence(values: Iterable[Try[T]]) -> Try[list[T]]

Success of every value, or the first Failure encountered.


Fields:

  • value: T
fold(self, _invalid_fn, valid_fn)

fold(invalid_fn, valid_fn) - calls valid_fn(value).

get_or_else(self, _default)

Return value directly.

is_invalid(self)
is_valid(self)
map(self, f)

Valid(f(value)).

map_err(self, _f)

Pass-through: map_err on Valid is a no-op.

to_either(self)

Ok(value).

zip(self, other)

Combine with other. Both ValidValid((self.value, other.value)). Any InvalidInvalid with that side’s error list.


Like Either, but zip accumulates errors instead of short-circuiting.

Valid and Invalid subclass Validated just as Scala’s Valid/Invalid subclass Validated. Build values through the factory methods; Validated itself is abstract - constructing it directly is an error.

cond(condition: bool, value: T, error: E) -> Validated[T, E]

Valid(value) if condition, else Invalid([error]).

from_either(either: Either[T, E]) -> Validated[T, E]

Convert an Either into a Validated.

Ok(v)Valid(v); Err(e)Invalid([e]).

invalid(error: E) -> Validated[T, E]

Invalid([error]). If error is already a list it is stored as-is (shallow copy); otherwise it is wrapped: [error].

valid(value: T) -> Validated[T, E]

Valid(value).

map(self, f: Callable[[T], Any]) -> Validated[Any, E]
map_err(self, f: Callable[[list[E]], Any]) -> Validated[T, Any]
zip(self, other: Validated[Any, E]) -> Validated[Any, E]
fold(self, invalid: Callable[[list[E]], Any], valid: Callable[[T], Any]) -> Any
get_or_else(self, default: T) -> T
to_either(self) -> Either[T, list[E]]
is_valid(self) -> bool
is_invalid(self) -> bool
case(cls: type[T]) -> type[T]
do(func: Callable[..., Any]) -> Callable[..., Any]
do_async(func: Callable[..., Any]) -> Callable[..., Any]
flow(*funcs: Callable[..., Any]) -> Callable[..., Any]
match(value: Any) -> Callable[..., Any]
newtype(name: str, base_type: type[T]) -> type[T]
newtype_strict(name: str, base_type: type[T], validate: Optional[Callable[..., bool]] = None, err_msg: Optional[str] = None) -> type[T]
on(typ: type[T], handler: Callable[..., Any]) -> Any
partial(f: Callable[..., Any], *args: Any, **kwargs: Any) -> Callable[..., Any]
pipe(value: Any, *funcs: Callable[..., Any]) -> Any
sealed(cls: type[T]) -> type[T]