Function Signature Tools
Project description
signia
Signature tools for Python
Mirror, compare, merge, and compose callables — IDE-friendly and type-aware.
✨ What is Signia?
Signia is a lightweight toolkit for working with Python function signatures.
It makes your wrappers, decorators, and composed functions look and feel right to IDEs, linters, and help().
With Signia you can:
- Mirror another function’s signature (
mirror_signature) - Compare signatures for equality or compatibility (
same_signature) - Merge multiple signatures into a single
inspect.Signature(merge_signatures) - Combine functions with merged signatures and real argument routing (
combine)
Perfect for decorators, adapters, and function composition.
📦 Installation
Signia targets Python 3.9+ and is published to PyPI.
python -m pip install signia
Add it to your project's dependencies (pyproject.toml/requirements.txt)
and you are ready to work with signatures in a type-friendly way.
🚀 Quickstart
Below are concise examples of each public helper exported from
signia. All snippets can be copied into a Python REPL or script.
mirror_signature
from signia import mirror_signature
def greet(name: str, excited: bool = False) -> str:
return f"Hello {name}{'!' if excited else ''}"
@mirror_signature(greet)
def wrapper(*args, **kwargs):
return greet(*args, **kwargs)
assert wrapper.__name__ == "greet"
assert wrapper.__signature__.parameters["name"].annotation is str
The decorator mirrors the wrapped callable's name, documentation, and
inspect.Signature so IDEs and type checkers understand the wrapper.
same_signature
from signia import same_signature
def source(x: int, y: int = 1) -> int:
return x + y
def mirror(x: int, y: int = 1) -> int:
return source(x, y)
assert same_signature(source, mirror)
assert same_signature(source, mirror, strict=False)
def variant(x: int, y: int = 2) -> int:
return x + y
assert not same_signature(source, variant)
assert same_signature(source, variant, strict=False)
assert same_signature(source, variant, strict=False, ignore_annotations=True)
Pass callables (or inspect.Signature instances) to test for strict equality or
structural compatibility, optionally ignoring default mismatches or annotations.
merge_signatures
from signia import merge_signatures
def left(x: int, *, limit: int = 10) -> None:
...
def right(y: str, *, limit: int = 10, verbose: bool = False) -> None:
...
merged = merge_signatures(left, right)
assert str(merged) == "(x: int, y: str, *, limit: int = 10, verbose: bool = False)"
custom_policy = merge_signatures(
left,
right,
policy="prefer-last", # choose metadata from later callables when possible
)
The merger walks parameters in kind order, keeping metadata according to the
selected policy ("prefer-first" by default) and returning a new
inspect.Signature. Return annotations come from the right-most callable with
a non-empty annotation.
combine
from signia import combine
def load(path: str, *, encoding: str = "utf-8") -> str:
return path.upper()
def audit(*, logger: list[str]) -> None:
logger.append("load called")
calls: list[str] = []
wrapped = combine(load, audit)
assert wrapped("demo.txt", logger=calls) == "DEMO.TXT"
assert calls == ["load called"]
# Inspect what each callable received
assert load.vars.args == ("demo.txt",)
assert audit.vars.kwargs == {"logger": calls}
combine uses merge_signatures under the hood so that a single callable can
forward keyword-only arguments to later helpers while keeping the primary
signature intact.
🧩 Handling Signature Conflicts
When merging or combining callables, Signia compares parameter kind, default
values, and annotations. Differing metadata is reported through
SignatureConflictError unless a resolver strategy is supplied.
from inspect import Parameter
from signia import merge_signatures, SignatureConflictError
def alpha(x: int, y: int = 1):
...
def beta(x: int, y: int = 2):
...
try:
merge_signatures(alpha, beta)
except SignatureConflictError as exc:
assert "default 1 vs 2" in str(exc)
merge_signatures(alpha, beta, compare_defaults=False) # tolerates default mismatch
prefer_defaults = merge_signatures(alpha, beta, on_conflict="prefer-defaulted", policy="prefer-last")
assert prefer_defaults.parameters["y"].default == 2
def resolver(name, existing, incoming, conflicts):
# Keep whichever side is annotated, otherwise fall back to the default policy.
if any(kind == "annotation" for kind, *_ in conflicts):
return incoming if incoming.annotation is not Parameter.empty else existing
return incoming
custom = merge_signatures(alpha, beta, on_conflict=resolver)
Custom resolvers receive the conflicting inspect.Parameter objects alongside
their metadata differences and must return a replacement Parameter. This
allows fine-grained reconciliation that aligns perfectly with your project's
needs.
Project details
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 signia-0.1.1.tar.gz.
File metadata
- Download URL: signia-0.1.1.tar.gz
- Upload date:
- Size: 22.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b4b6ef882c2aff4adc9457803e4627912ca91087feb9a622ff901ba65741f98
|
|
| MD5 |
72cdf30c95f0f1d6f35f1a9eb6477eef
|
|
| BLAKE2b-256 |
9d922d6d8c8ab8388a0f305dd8a89dd6554db55eaac5667ca2f0f0f474704022
|
File details
Details for the file signia-0.1.1-py3-none-any.whl.
File metadata
- Download URL: signia-0.1.1-py3-none-any.whl
- Upload date:
- Size: 15.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffabebe94efe157bc5a1bccf1963271a457d7d488f32b98f48b89d732d6ccec4
|
|
| MD5 |
4d27d290b1dd5691a0e677ccc1c20a50
|
|
| BLAKE2b-256 |
4c3d72e3c78fb3cffc7069508ebf87d1fc3c4c00017f185c5fa1f122039109d3
|