Skip to main content

Simplified Introspection

Project description

<style> @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap'); .orbitron-title { font-family: "Orbitron", sans-serif; font-optical-sizing: auto; font-weight: 400; font-style: normal; } .side-by-side { display: flex; } .image-stuff { border-radius: 25px; width: 125px; height: 125px; margin-right: 15px; } </style>

callsign: simplified introspection


callsign; a python package that abstracts away boilerplate from the standard library's inspect module. Made for practitioners of DDD (decorator driven development); minimizing tedium and keeping things DRY is what we're all about.

Only dependency is python 3 .

Installation

pip install callsign

Usage

>>> import callsign

>>> def f(x, y: int): return x, y

>>> params = callsign(f, 'hi', y=2)
>>> params  # a dict of namedtuples
{
    'x': Paramattrs(name='x',
                    arg='hi',
                    default=inspect._empty,
                    kind=ParamKinds.POSITIONAL_OR_KEYWORD,
                    defaulted=False,
                    annotation=inspect._empty),
    'y': Paramattrs(name='y',
                    arg=2,
                    default=inspect._empty,
                    kind=ParamKinds.POSITIONAL_OR_KEYWORD,
                    defaulted=False,
                    annotation=<class 'int'>),
}

>>> params['x'].arg
'hi'

>>> params['x'].annotation
inspect._empty
>>> callsign.isempty(params['x'].annotation)
True

>>> params['y'].annotation
<class 'int'>

Any time you do a callsign of a function and its positional + keyword arguments, you'll get a python dictionary back of each parameter name mapped to its Paramattrs (the param's attributes).

Recipes

Basic DDD

import callsign

def decorator(fn: Callable) -> Callable:
    @functools.wraps(fn)
    def newfn(*args, **kwargs) -> Any:

        # introspection!
        params = callsign(fn, *args, **kwargs)

        if params['x'].defaulted:
            return fn(*args, **kwargs)
        elif params['y'].arg == 'something else':
            return fn('doing something with y')

        ...
    return newfn  # and bob's your uncle

Build a rudimentary type checker

import callsign

def type_checker(fn: Callable[..., [Any]]) -> Callable[..., [Any | NoReturn]]:
    @functools.wraps(fn)
    def typedfn(*args, **kwargs) -> Any:
    
        params = callsign(fn, *args, **kwargs)

        for param in params:
            if param.annotation and type(param.arg) != param.annotation:
                raise TypeError()

        return fn(*args, **kwargs)  # and bob's your uncle!
    return typedfn

Advanced DDD

import callsign

def decorator(fn: Callable) -> Callable:
    @functools.wraps(fn)
    def newfn(*args, **kwargs) -> Any:
        params = callsign(fn, *args, **kwargs)
       
        mut = {'x': 2, 'y': 3}
        positionals, keywords = callsign.arguments(params, mut, safe=True)
        return fn(*positionals, **keywords)
    return newfn

@decorator
def crazy_signature(x, /, *args, y=10, **kwargs): return x, args, y, kwargs

x, _, y, _ = crazy_signature(10, y=20)
print(x)  # 2
print(y)  # 3

Paramattrs

The Paramattrs object is a pure python namedtuple, nothing fancy. It defines the following attributes:

  • name: the parameter's name
  • arg: the given argument
  • default: if a default value was assigned to the function's signature, it's preserved here, otherwise it's inspect.empty
  • kind: one of a ParamKinds Enum
  • defaulted: this is True if no argument is given and a default is being used
  • annotation: this will be inspect._empty if no type hint is written in the function signature, otherwise it will be whatever was provided as a type hint

ParamKinds

These are taken from the standard library's inspect module, but we've added one: ParamKinds.VULNERABLE_DEFAULT.

VULNERABLE_DEFAULT is interchangeable with POSITIONAL_OR_KEYWORD; but also, it is a parameter that was given a default value, and that default has been overridden by a VARARGS parameter, e.g.:

>>> def hello(x=10, *args): return x, args

>>> print( hello() )
(10, ())

>>> print( hello(1, 2, 3) )
(1, (2, 3))  # x = 10 was overridden, x is now 1

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

callsign-0.1.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

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

callsign-0.1.0-py3-none-any.whl (5.9 kB view details)

Uploaded Python 3

File details

Details for the file callsign-0.1.0.tar.gz.

File metadata

  • Download URL: callsign-0.1.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.12.3

File hashes

Hashes for callsign-0.1.0.tar.gz
Algorithm Hash digest
SHA256 afa4c594e8aa3228e94edee5256bcf0d01adf294c339118941bc090371eec124
MD5 ba4b817d66e1c4ff3a0cb75b8b6e9a7a
BLAKE2b-256 1c0afed204b26b1de939b296acecdbd876cc94803faf8a4239d0ec8ee45ea610

See more details on using hashes here.

File details

Details for the file callsign-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: callsign-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 5.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.12.3

File hashes

Hashes for callsign-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5aacbb9235990e18c4f260623bef15a60be4a341bc34bb1fe16cf2efdec43573
MD5 78926ac544a3d8d85d586ad504be5ce8
BLAKE2b-256 7d8394b30a31488afb94dd632766415ec920f1bd4280a93c1a6542d5d6dfadb4

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