python-crimes
Small, typed-enough Python syntax crimes that form one deliberately coherent ecosystem with typed-errs: pipe values, defer cleanup, and match rich values without falling back to nullable match results.
uv add python-crimes
Examples
Runnable examples live in examples: pipes, deferred
cleanup, structural matching and typed-errs variants, plus reusable dispatch.
python_crimes/
├── pipe.py @pipe and value @ function
├── defer.py DeferStack, with defer(), @deferred, terminate()
├── patterns.py reusable and composable patterns
├── match.py bound matching and reusable Dispatch
└── typed.py Result and Option patterns backed by typed-errs
Pipes
@pipe preserves normal calls while allowing the left-to-right form.
from python_crimes import pipe
@pipe
def parse(raw: str) -> dict[str, object]: ...
@pipe
def validate(config: dict[str, object]) -> Config: ...
config = raw @ parse @ validate
For a function with configuration after its piped first argument, use the
explicit partial form: score @ clamp.with_(lo=0, hi=100).
Deferred cleanup
DeferStack is the boring LIFO implementation. defer and @deferred are
just convenient frontends over it.
from python_crimes import deferred, terminate
from typed_errs import Result, catch_bubble
@catch_bubble
@deferred
def write_report(d, path) -> Result[None, WriteError]:
writer = write_text(path).q
d << terminate(writer)
writer("started\\n")
return Ok(None)
The cleanup still runs when .q bubbles an Err, because normal Python stack
unwinding reaches the deferred scope first.
Matching
Patterns return typed_errs.Option[Match]: successful matching is
Some(Match(...)), and failure is Nothing(). The matcher itself therefore
does not use Match | None as an internal failure protocol.
from python_crimes import capture, ge, gt, match_, type_
with match_(data) as m:
m.case(200, 201, 204) << "success"
m.case(type_(int)).when(gt(0)) << (lambda number: number * 2)
m.regex(r"(\d+)x(\d+)") << (lambda width, height: (int(width), int(height)))
m.case(
{
"type": "user",
"payload": {"name": capture(str), "age": capture(int)},
}
) << (lambda name, age: (name, age))
m.default << "unknown"
result = m.value
Fluent matching
The context manager is convenient for a visually large decision tree. For a
small match inside an expression or function return, use the exact same engine
without with:
level = (
match_(raw_level)
.case(type_(int))
.when(gt(0))
.then(lambda value: value * 2)
.regex(r"level:(\d+)")
.then(int)
.default.then(0)
.value
)
<< and .then(...) are equivalent. A callable result is a handler; use
const(callable_value) when a callable itself is the wanted result.
Patterns compose with &, |, and ~; helpers include eq, type_, when,
gt/ge/lt/le, in_, contains, is_, regex, attr, length, ANY,
and REST. Lists and mappings are structural patterns recursively, and
capture(...) passes values to the selected handler in traversal order.
typed-errs is first class
Result and Option variants have dedicated arms with payload capture:
with match_(read(path)) as m:
m.ok << process
m.err << report
with match_(find_user()) as m:
m.some << (lambda user: user.name)
m.nothing << "anonymous"
No optional adapter is needed: python-crimes depends on typed-errs and
ships these patterns as part of its public API.
The special arms deliberately unwrap only when their variant matched:
Ok(value) -> m.ok handler(value)
Err(error) -> m.err handler(error)
Some(value) -> m.some handler(value)
Nothing() -> m.nothing constant or handler(subject)
For ordinary structural matching, failed patterns are Nothing() and
successful patterns are Some(Match(captures)); this is the same explicit
absence vocabulary used everywhere else in the ecosystem.
Reusable dispatch
from python_crimes import ge, matcher, type_
status = (
matcher()
.case(200)
.then("ok")
.case(404)
.then("missing")
.case(type_(int) & ge(500))
.then("server error")
.default.then("unknown")
)
message = 503 @ status
Ecosystem
- typed-errs supplies
Result,Option, and.qbubbling. - typed-file-io supplies typed file
callbacks; pair a callback writer with
deferandterminate. - sqlite-callback-store supplies short-lived typed SQLite callbacks.
Dependencies
typed-errs
Use and contributions
This is a personal library, but it is not private or locked to my projects. You may use it in general Python work and in 42 projects under the MIT license; just follow the rules that apply to your campus and assignment.
Contributions are welcome: open an issue or send a pull request. I do not care whether a contribution is written by hand, AI-assisted, or generated another way; I care about whether it is correct, tested, understandable, and a good fit. Because this is opinionated personal infrastructure, pull requests are reviewed selectively and are likely to be rejected unless they clearly improve the library without making it harder to maintain.
Development and release
Run mise run check. Every push to master publishes a unique 0.0.<CI run> ZeroVer
version through PyPI Trusted Publishing. mise run publish remains available.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_crimes-0.0.4.tar.gz.
File metadata
- Download URL: python_crimes-0.0.4.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b3684cd7781a6f43ffb47ca8bab672b0bc6909fa27a993b9e3af782b5b4ae9c
|
|
| MD5 |
afa30242443a8fa941e0b8e5a47e068d
|
|
| BLAKE2b-256 |
7eca85e586002da76329c5e269a5ef7be3c81dac5b8eb9f05eb38fe191be813a
|
Provenance
The following attestation bundles were made for python_crimes-0.0.4.tar.gz:
Publisher:
release.yml on 0xveya/python-crimes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_crimes-0.0.4.tar.gz -
Subject digest:
6b3684cd7781a6f43ffb47ca8bab672b0bc6909fa27a993b9e3af782b5b4ae9c - Sigstore transparency entry: 2425388334
- Sigstore integration time:
-
Permalink:
0xveya/python-crimes@3d068fa15d1e291305ebb139ede7255631a819e9 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/0xveya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3d068fa15d1e291305ebb139ede7255631a819e9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file python_crimes-0.0.4-py3-none-any.whl.
File metadata
- Download URL: python_crimes-0.0.4-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
235665a3250a551ca6e6f407f15a30fb2185a55b31ea8bce8aa865790a222031
|
|
| MD5 |
d9c523afd7b673ef8233d156a619d20a
|
|
| BLAKE2b-256 |
e81553d0a0eee1f13c1bebc1ed16535cc9bb40a8b99e6ce91ddaf52938777c69
|
Provenance
The following attestation bundles were made for python_crimes-0.0.4-py3-none-any.whl:
Publisher:
release.yml on 0xveya/python-crimes
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_crimes-0.0.4-py3-none-any.whl -
Subject digest:
235665a3250a551ca6e6f407f15a30fb2185a55b31ea8bce8aa865790a222031 - Sigstore transparency entry: 2425388428
- Sigstore integration time:
-
Permalink:
0xveya/python-crimes@3d068fa15d1e291305ebb139ede7255631a819e9 -
Branch / Tag:
refs/heads/master - Owner: https://github.com/0xveya
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3d068fa15d1e291305ebb139ede7255631a819e9 -
Trigger Event:
push
-
Statement type: