Skip to main content

Lightweight utilities for dynamic and declarative function signature manipulation, inspection, and validation.

Project description

⚠️ DEPRECATED — Use simplibs instead

This package is deprecated and no longer maintained.

Please migrate to: simplibs-signature

This older version remains available for backward compatibility, but new projects should use the simplibs ecosystem instead.

simple-signature

Lightweight utilities for dynamic and declarative function signature manipulation. Inspect, copy, assemble, and apply inspect.Signature objects — with a clean API and no magic.

Python Licence PyPI

@signature_from(extra_param, base_func_first=False)
def my_func(*args, **kwargs):
    ...

@signature_copy(MyClass.__init__, return_type=MyClass)
def create(*args, **kwargs):
    ...

Contents


Installation

pip install simple-signature
from simple_signature import signature_from, signature_copy

Note: This library automatically installs simple-exception as a core dependency.


Quick start

Python's inspect.Signature is powerful — but working with it directly is verbose. simple-signature gives you a small set of focused tools for the most common scenarios: copying a signature from one function to another, assembling a signature from multiple sources, and applying it as a decorator.

Copy a signature from an existing function

The most common use case — take the signature from one callable and apply it to another. signature_copy always normalises the result: removes self/cls and appends **kwargs:

from simple_signature import signature_copy

class MyClass:
    def __init__(self, name: str, value: int = 0):
        ...

@signature_copy(MyClass.__init__, return_type=MyClass)
def create(*args, **kwargs):
    return MyClass(*args, **kwargs)

# create now reports: (name: str, value: int = 0, **kwargs) -> MyClass

Assemble a signature from multiple sources

signature_from turns the decorated function itself into the base — then merges in additional parameters from adds:

from simple_signature import signature_from, create_keyword_parameter

extra = create_keyword_parameter("timeout", annotation=int, default=30)

@signature_from(extra)
def connect(host: str, port: int):
    ...

# connect now reports: (host: str, port: int, *, timeout: int = 30)

Decorators

The two main decorators — the primary public interface of the library.

signature_copy

Copies and normalises a signature from an existing callable onto the decorated function. Always removes self/cls and appends **kwargs.

@signature_copy(base_func, return_type=MyClass)
def my_func(*args, **kwargs):
    ...
Parameter Type Description
base_func Callable The function or method whose signature is copied
return_type type | None | UNSET Override the return annotation. UNSET preserves the original, None removes it

signature_from

Assembles a new signature from the decorated function and any additional parameter sources. The decorated function becomes base_func.

@signature_from(param_or_func, ..., base_func_first=True)
def my_func(*args, **kwargs):
    ...
Parameter Type Description
*adds inspect.Parameter | Callable Parameters or callables to merge into the signature
excluded_names tuple[str, ...] Parameter names to exclude
return_type type | Callable | None | UNSET Return annotation. If UNSET and base_func has one, it is inherited
base_func_first bool If True, decorated function's parameters come first (default: True)
accept_double bool If True, duplicate parameter names are silently skipped (default: True)

Signature operations

Lower-level tools for working with inspect.Signature objects directly.

get_signature

Safely retrieves an inspect.Signature from any callable. Converts Python's raw ValueError and TypeError into structured SignatureBuildError instances:

from simple_signature import get_signature

sig = get_signature(my_func)

set_signature

Assigns an inspect.Signature directly to a function via __signature__. Returns the original function — allows inline assignment:

from simple_signature import set_signature

set_signature(my_func, my_signature)

create_copy_signature

Creates a modified copy of a signature from a callable — the lower-level counterpart to signature_copy. Use when you need full control over normalisation or want the inspect.Signature object directly rather than a decorator:

from simple_signature import create_copy_signature, UNSET

sig = create_copy_signature(
    MyClass.__init__,
    return_type = MyClass,   # override return annotation
    normalize   = True,      # remove self/cls, append **kwargs (default: True)
)

apply_signature_to_wraps

Creates a new wrapper around a function and assigns a custom signature to it. The building block for decorators — use when you need a new callable, not just a modified one:

from simple_signature import apply_signature_to_wraps

wrapped = apply_signature_to_wraps(my_func, my_signature)

create_signature_decorator

Produces a reusable decorator from an inspect.Signature. Use when the same signature needs to be applied to multiple functions:

from simple_signature import create_signature_decorator

decorator = create_signature_decorator(my_signature)

@decorator
def func_a(*args, **kwargs): ...

@decorator
def func_b(*args, **kwargs): ...

Parameter creators

Convenience factories for building inspect.Parameter instances without touching the inspect module directly.

create_positional_parameter

from simple_signature import create_positional_parameter

param = create_positional_parameter("name", annotation=str)
param = create_positional_parameter("x", annotation=int, default=0, positional_only=True)

create_keyword_parameter

from simple_signature import create_keyword_parameter

param = create_keyword_parameter("timeout", annotation=int, default=30)

Both factories accept:

Parameter Type Description
name str Parameter name
annotation type Type annotation — omit for no annotation
default Any Default value — omit for no default
positional_only bool create_positional_parameter only — produces POSITIONAL_ONLY if True

SignatureCreator

The engine behind signature_from and create_signature — assembles an inspect.Signature from any combination of callables and inspect.Parameter instances. Use it directly when you need the builder instance itself, or reach for create_signature for the one-liner functional form:

from simple_signature import SignatureCreator, create_signature

# Builder form — access the instance if needed
creator = SignatureCreator(extra_param, base_func=my_func)
sig = creator.signature

# Functional form — when only the signature is needed
sig = create_signature(extra_param, base_func=my_func)
Parameter Type Description
*adds inspect.Parameter | Callable Parameters or callables to merge in
excluded_names tuple[str, ...] Parameter names to exclude
return_type type | Callable | None | UNSET Return annotation source — type, callable, None, or UNSET
base_func Callable | None Base function — its parameters and return type are the starting point
base_func_first bool If True, base_func parameters come first (default: True)
accept_double bool If True, duplicate names are silently skipped (default: True)

return_type priority

Value Behaviour
a type Used directly as the return annotation
a callable Its return annotation is extracted and used
None Return annotation is removed
UNSET Inherited from base_func if available, otherwise empty

Constants

Pre-built inspect.Parameter instances and a frozenset of default exclusions — ready to use without touching the inspect module:

from simple_signature import ARGS, KWARGS, EXCLUDED

# ARGS   — *args  (VAR_POSITIONAL)
# KWARGS — **kwargs (VAR_KEYWORD)
# EXCLUDED — frozenset({"self", "cls"})

EXCLUDED is the default exclusion set used by ParameterCollector and create_copy_signatureself and cls are always skipped automatically.


About the Simple ecosystem

simple-signature is part of the Simple ecosystem — a collection of small, self-contained Python libraries, each solving exactly one thing.

The Simple ecosystem is built on simple-exception — a structured exception that communicates with the developer: describing not just what went wrong, but pointing towards a fix. All errors raised by simple-signature are structured SimpleException subclasses, catchable as SignatureError or the more specific SignatureParameterError and SignatureBuildError:

from simple_signature import SignatureError, SignatureBuildError, SignatureParameterError

try:
    create_signature()  # no sources provided
except SignatureBuildError:
    ...  # signature could not be built

try:
    create_keyword_parameter(name=123)  # wrong type
except SignatureParameterError:
    ...  # invalid argument

try:
    ...
except SignatureError:
    ...  # catches all simple-signature errors

All libraries in the Simple ecosystem share a common philosophy:

Dyslexia-friendly — minimise mental load. Atomise code into self-contained units, name files after the logic they contain, write explanations that describe why — not just what.

Programmer's zen — nothing should be missing and nothing should be superfluous. The journey is the destination: code should be fully understood; better to go slowly and correctly than quickly and with mistakes. The crystallisation approach — not perfection on the first try, but gradual refinement towards it.

Defensive style — anticipate all possible failure modes so that only safe paths remain. Never raise unexpected errors; degrade gracefully.

Minimalism — find the path to the goal in as few steps as possible, but leave nothing out. Each file has one responsibility.

Code as craft — code should be pleasant to look at and evoke a sense of harmony. Treat code as a small work of art — like a carpenter carving a sculpture. Optimise for the user: everything should make sense without having to study the documentation at length.

These are aspirations — a sense of direction. And that is exactly what the note about the journey becoming the destination is all about. 🙂


The library is covered by unit tests across all modules. Tests are part of the repository and serve as living documentation of the expected behaviour.

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

simple_signature-0.1.2.tar.gz (37.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

simple_signature-0.1.2-py3-none-any.whl (56.1 kB view details)

Uploaded Python 3

File details

Details for the file simple_signature-0.1.2.tar.gz.

File metadata

  • Download URL: simple_signature-0.1.2.tar.gz
  • Upload date:
  • Size: 37.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for simple_signature-0.1.2.tar.gz
Algorithm Hash digest
SHA256 365eb65dbda970c29a6388bf4becdd949720859905971c551e50f326442d560b
MD5 36172115d3ae5ecaf02871fd38f1ce50
BLAKE2b-256 73d99eb4a4a8581c9bc8df6b9929edef268c45ed9af2f0609fdb5b582c8918b8

See more details on using hashes here.

File details

Details for the file simple_signature-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for simple_signature-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 928cafac764a71eda3cbdd780545c2db4d35635e163989c87b2935bb03d784a9
MD5 0b9ba202019c9f2d0518522157458f2b
BLAKE2b-256 869093be83e37a308b8692fecc8ebec76fe87f7f13725300ee638bc2b7e7a242

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page