Tiny utilities for raising exceptions on a condition and rendering them as readable strings
Project description
exceptly
Tiny utilities for raising exceptions on a condition and rendering them as readable strings.
Installation
pip install exceptly
Requires Python 3.11+.
Why exceptly?
Two small annoyances show up in every Python codebase:
- Guard clauses take three lines.
if not value: raise ValueError("missing")is four tokens of logic wrapped in ceremony.raise_if_not(value, ValueError, "missing")is the same thing on one line, with the exception type spelled out up front where the reader can see it. repr(e)andstr(e)are both wrong for logs.repr(e)gives youValueError('missing')(quoted, parenthesised, noisy).str(e)gives you'missing'— no type at all.repr_exception(e)gives youValueError: missing— the form humans actually want in log lines and assertion messages.
No dependencies, no configuration, no magic — three functions that do one thing each.
Quick Start
from exceptly import raise_if, raise_if_not, repr_exception
def set_positive(value: int) -> None:
raise_if_not(isinstance(value, int), TypeError, f"expected int, got {type(value).__qualname__}")
raise_if(value <= 0, ValueError, "expected a positive value, got", value)
# ... actual work
try:
set_positive(None)
except TypeError as e:
assert repr_exception(e) == "TypeError: expected int, got NoneType"
try:
set_positive(0)
except ValueError as e:
assert repr_exception(e) == "ValueError: ('expected a positive value, got', 0)"
Overview
raise_if | raise_if_not | repr_exception
raise_if
Raises the given exception when condition is truthy; does nothing otherwise.
Use when: you want an inline guard clause without the if ...: raise ... boilerplate, and you want the exception type to be visible at the start of the call rather than buried inside the if body.
from exceptly import raise_if
# Pass a pre-built exception instance:
raise_if(x < 0, ValueError("negative value"))
# Or pass the class and its constructor args — the instance is only built if the condition fires:
raise_if(x < 0, ValueError, "negative value")
raise_if(x < 0, ValueError, "negative value", x) # ValueError('negative value', -1)
The two forms are equivalent, but the class-plus-args form avoids constructing the exception when the guard does not trip — useful when the message is expensive to format (e.g. repr of a large object).
raise_if_not
Inverse of raise_if: raises when condition is falsy.
Use when: the natural phrasing of the guard is positive ("must be non-empty", "must be an int") rather than negative. Also a drop-in replacement for assert in code paths where assert is unreliable (stripped by python -O, silent in production configs).
from exceptly import raise_if_not
raise_if_not(isinstance(value, int), TypeError, f"expected int, got {type(value).__qualname__}")
raise_if_not(items, ValueError("items must not be empty"))
repr_exception
Renders an exception as "ClassName: message", or "ClassName" when the exception carries no message.
Use when: writing log lines, assertion messages, or error responses. repr(e) is cluttered (ValueError('missing')); str(e) loses the type ('missing'); f"{type(e).__name__}: {e}" is the hand-rolled version you end up writing anyway.
from exceptly import repr_exception
repr_exception(ValueError("not found")) # "ValueError: not found"
repr_exception(RuntimeError()) # "RuntimeError"
repr_exception(ValueError(1, 2, 3)) # "ValueError: (1, 2, 3)"
class DomainError(Exception):
pass
repr_exception(DomainError("boom")) # "DomainError: boom"
The output is plain text, safe for logs and assertion messages, and never raises.
License
Project details
Release history Release notifications | RSS feed
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 exceptly-1.0.0.tar.gz.
File metadata
- Download URL: exceptly-1.0.0.tar.gz
- Upload date:
- Size: 5.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33af87b0b0d99db28066fc5ac0cf7405980492ee1792e46c1e9fb4d5ab6bde83
|
|
| MD5 |
f0c4ae3053b0ba4a515b64d6eef6bdf8
|
|
| BLAKE2b-256 |
99561057876729b66f14dff39a7d654434686491685e2b0b9730b9876564c823
|
Provenance
The following attestation bundles were made for exceptly-1.0.0.tar.gz:
Publisher:
publish-pypi.yml on miriada-io/exceptly
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exceptly-1.0.0.tar.gz -
Subject digest:
33af87b0b0d99db28066fc5ac0cf7405980492ee1792e46c1e9fb4d5ab6bde83 - Sigstore transparency entry: 1357779056
- Sigstore integration time:
-
Permalink:
miriada-io/exceptly@3ef4b3071ebcca7459429541c32120e9f64a6643 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/miriada-io
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3ef4b3071ebcca7459429541c32120e9f64a6643 -
Trigger Event:
release
-
Statement type:
File details
Details for the file exceptly-1.0.0-py3-none-any.whl.
File metadata
- Download URL: exceptly-1.0.0-py3-none-any.whl
- Upload date:
- Size: 4.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
372e3e9bddd4b83336e9a51009b00f576c18736663211baf381c08a3c052b52d
|
|
| MD5 |
ee732639715abf844b93d8c2f780333e
|
|
| BLAKE2b-256 |
87ffec02b539144fcf042226d6f8f7ebf233259565a9cd94e86fb16e0cba4b85
|
Provenance
The following attestation bundles were made for exceptly-1.0.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on miriada-io/exceptly
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exceptly-1.0.0-py3-none-any.whl -
Subject digest:
372e3e9bddd4b83336e9a51009b00f576c18736663211baf381c08a3c052b52d - Sigstore transparency entry: 1357779184
- Sigstore integration time:
-
Permalink:
miriada-io/exceptly@3ef4b3071ebcca7459429541c32120e9f64a6643 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/miriada-io
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@3ef4b3071ebcca7459429541c32120e9f64a6643 -
Trigger Event:
release
-
Statement type: