title: kain description: Runtime introspection, dynamic imports, and monkey-patching utilities for Python
[ref: #kain]
kain
kain is a small Python toolbox for runtime introspection, dynamic imports, and controlled monkey-patching.
It gives you several public entry points:
Is— type and shape predicates.Who— introspection helpers for names, modules, and inheritance.Monkey— runtime patching, binding, and exception suppression.required,optional,add_path— dynamic imports andsys.pathmanagement.to_ascii,to_bytes,unique— small text and iteration helpers.
[ref: #installation]
Installation
Install with uv:
uv add kain
Or with any PEP 517-compatible tool:
pip install kain
[ref: #is]
Type and shape checks with Is
Is is a namespace of predicates for classes, collections, primitives, mappings, and more.
from zx.core import Is
assert Is.Class(int) is True
assert Is.Class(42) is False
assert Is.collection([1, 2, 3]) is True
assert Is.mapping({"a": 1}) is True
assert Is.primitive(42) is True
assert Is.subclass(42, int | str) is True
[ref: #who]
Introspection with Who
Who gives you readable names, source files, argument lists, and inheritance chains.
from zx.core import Who
assert Who.Is(42) == "int"
assert Who.Name(str) == "str"
assert Who.Cast(42) == "(int)42"
assert Who.Args(1, 2, a=3) == "'1', '2', a=3"
class A:
pass
class B(A):
pass
assert A in Who.Inheritance(B)
assert Who.Inheritance(B, glue=" -> ") == "__main__.A"
[ref: #importer]
Dynamic imports with required, optional, and add_path
required imports by dotted path and raises on failure; optional returns a default instead.
add_path resolves a directory or file path and appends it to sys.path.
from zx.core import add_path, optional, required
assert required("os.path.join") is __import__("os").path.join
assert optional("nonexistent_package_xyz") is None
assert optional("nonexistent_package_xyz", default="fallback") == "fallback"
# Add a directory or a file's parent directory to sys.path.
add_path(".")
[ref: #monkey]
Runtime patching with Monkey
Monkey provides helpers for suppressing exceptions, attaching functions to objects, and replacing attributes while preserving the original in Monkey.mapping.
from zx.core import Monkey
assert Parser.parse("not-a-number") is None
assert Parser.parse("42") == 42
node = type("Node", (), {})()
@Monkey.bind(node)
def greet(name: str) -> str:
return f"hi {name}"
assert node.greet("world") == "hi world"
[ref: #text-and-unique]
Text coercion and deduplication with to_ascii, to_bytes, and unique
to_ascii and to_bytes coerce between str and bytes with an optional charset.
unique yields distinct items from an iterable, optionally by a key function.
from zx.core import to_ascii, to_bytes, unique
assert to_ascii(b"hello") == "hello"
assert to_bytes("hello") == b"hello"
assert to_ascii("é".encode("utf-8"), charset="utf-8") == "é"
assert list(unique([1, 2, 2, 3, 1])) == [1, 2, 3]
assert list(unique(["a", "A", "b"], key=str.lower)) == ["a", "b"]
[ref: #full-example]
Full example
from zx.core import Is, Monkey, Who, add_path, optional, required, to_ascii, unique
class Config:
def port(cls, raw: str) -> int | None:
return int(raw)
assert Config.port("8080") == 8080
assert Is.primitive("hello") is True
assert Who.Is(Config.port).endswith("Config.port")
join = required("os.path.join")
assert callable(join)
parser = optional("nonexistent_parser", default=str)
assert parser is str
add_path(".")
assert to_ascii(b"kain") == "kain"
assert list(unique(["x", "x", "y"])) == ["x", "y"]
Metadata
Release files for kain 2.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| kain-2.0.1.tar.gz | 45.0 kB | Without provenance | Details for kain-2.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| kain-2.0.1-py3-none-any.whl | Python 3 | none | any | Details for kain-2.0.1-py3-none-any.whl |
Total release size: 65.4 kB
Release files / kain-2.0.1.tar.gz
| Download URL | kain-2.0.1.tar.gz |
|---|---|
| Size | 45.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5c89b164a5ce1ec4c16559edcb9592c50a56647dcf82ff5aa0a04581d7c9732c
|
|
BLAKE2b-256 checksum How to use checksums |
dfa4beca2db5067d5635591ae9d58339007acf307c180ad63153bda4b607aeaf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / kain-2.0.1-py3-none-any.whl
| Download URL | kain-2.0.1-py3-none-any.whl |
|---|---|
| Size | 20.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
56e0cd7c5d94b5850955f963a989fe910dd07644ba66b4e4a94c2e3afe0d8ecc
|
|
BLAKE2b-256 checksum How to use checksums |
bb0ffeedc16e10ef2d472835e475dd077a243651223a2cff0d2a7003d2bf0475
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for kain 2.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.