callsign


Namecallsign JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummarySimplified Introspection
upload_time2024-06-15 19:33:06
maintainerNone
docs_urlNone
authormuhamuhamuha
requires_python>=3.8
licenseNone
keywords ddd decorator decorator driven development function introspection metaprogramming signature
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap" rel="stylesheet">

<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>

<div class="side-by-side">
  <img src="imgs/mainlogo.png" class="image-stuff"/>
  <h1 class="orbitron-title">callsign: simplified introspection</h1>
</div>
<br>


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

```python
>>> 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

```python
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

```python
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

```python
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.:

```python
>>> 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
```


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "callsign",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "ddd, decorator, decorator driven development, function, introspection, metaprogramming, signature",
    "author": "muhamuhamuha",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/1c/0a/fed204b26b1de939b296acecdbd876cc94803faf8a4239d0ec8ee45ea610/callsign-0.1.0.tar.gz",
    "platform": null,
    "description": "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link href=\"https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap\" rel=\"stylesheet\">\n\n<style>\n\n@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap');\n\n.orbitron-title {\n  font-family: \"Orbitron\", sans-serif;\n  font-optical-sizing: auto;\n  font-weight: 400;\n  font-style: normal;\n}\n\n.side-by-side {\n  display: flex;\n}\n\n.image-stuff {\n  border-radius: 25px;\n  width: 125px;\n  height: 125px;\n  margin-right: 15px;\n}\n\n</style>\n\n<div class=\"side-by-side\">\n  <img src=\"imgs/mainlogo.png\" class=\"image-stuff\"/>\n  <h1 class=\"orbitron-title\">callsign: simplified introspection</h1>\n</div>\n<br>\n\n\ncallsign; a python package that abstracts away boilerplate from the  standard\nlibrary's inspect module. Made for practitioners of DDD \n(decorator driven development); minimizing tedium and keeping things\nDRY is what we're all about.\n\nOnly dependency is python 3 .\n\n\n## Installation\n\n`pip install callsign`\n\n## Usage\n\n```python\n>>> import callsign\n\n>>> def f(x, y: int): return x, y\n\n>>> params = callsign(f, 'hi', y=2)\n>>> params  # a dict of namedtuples\n{\n    'x': Paramattrs(name='x',\n                    arg='hi',\n                    default=inspect._empty,\n                    kind=ParamKinds.POSITIONAL_OR_KEYWORD,\n                    defaulted=False,\n                    annotation=inspect._empty),\n    'y': Paramattrs(name='y',\n                    arg=2,\n                    default=inspect._empty,\n                    kind=ParamKinds.POSITIONAL_OR_KEYWORD,\n                    defaulted=False,\n                    annotation=<class 'int'>),\n}\n\n>>> params['x'].arg\n'hi'\n\n>>> params['x'].annotation\ninspect._empty\n>>> callsign.isempty(params['x'].annotation)\nTrue\n\n>>> params['y'].annotation\n<class 'int'>\n```\n\nAny time you do a callsign of a function and its positional + keyword arguments,\nyou'll get a python dictionary back of each parameter name\nmapped to its _Paramattrs_ (the param's attributes).\n\n### Recipes\n\n#### Basic DDD\n\n```python\nimport callsign\n\ndef decorator(fn: Callable) -> Callable:\n    @functools.wraps(fn)\n    def newfn(*args, **kwargs) -> Any:\n\n        # introspection!\n        params = callsign(fn, *args, **kwargs)\n\n        if params['x'].defaulted:\n            return fn(*args, **kwargs)\n        elif params['y'].arg == 'something else':\n            return fn('doing something with y')\n\n        ...\n    return newfn  # and bob's your uncle\n```\n\n#### Build a rudimentary type checker\n\n```python\nimport callsign\n\ndef type_checker(fn: Callable[..., [Any]]) -> Callable[..., [Any | NoReturn]]:\n    @functools.wraps(fn)\n    def typedfn(*args, **kwargs) -> Any:\n    \n        params = callsign(fn, *args, **kwargs)\n\n        for param in params:\n            if param.annotation and type(param.arg) != param.annotation:\n                raise TypeError()\n\n        return fn(*args, **kwargs)  # and bob's your uncle!\n    return typedfn\n```\n\n#### Advanced DDD\n\n```python\nimport callsign\n\ndef decorator(fn: Callable) -> Callable:\n    @functools.wraps(fn)\n    def newfn(*args, **kwargs) -> Any:\n        params = callsign(fn, *args, **kwargs)\n       \n        mut = {'x': 2, 'y': 3}\n        positionals, keywords = callsign.arguments(params, mut, safe=True)\n        return fn(*positionals, **keywords)\n    return newfn\n\n@decorator\ndef crazy_signature(x, /, *args, y=10, **kwargs): return x, args, y, kwargs\n\nx, _, y, _ = crazy_signature(10, y=20)\nprint(x)  # 2\nprint(y)  # 3\n```\n### Paramattrs\n\nThe _Paramattrs_ object is a pure python namedtuple, nothing fancy. It defines\nthe following attributes:\n\n* name: the parameter's name\n* arg: the given argument\n* default: if a default value was assigned to the function's signature, it's\npreserved here, otherwise it's `inspect.empty`\n* kind: one of a _ParamKinds_ Enum\n* defaulted: this is `True` if no argument is given and a default is being used\n* annotation: this will be `inspect._empty` if no type hint is written\nin the function signature, otherwise it will be whatever was provided as\na type hint\n\n### ParamKinds\n\nThese are taken from the standard library's inspect module, but we've added one:\n`ParamKinds.VULNERABLE_DEFAULT`. \n\nVULNERABLE\\_DEFAULT is interchangeable with POSITIONAL\\_OR\\_KEYWORD; but also,\nit is a parameter that was given a default value, and that default\nhas been overridden by a VARARGS parameter, e.g.:\n\n```python\n>>> def hello(x=10, *args): return x, args\n\n>>> print( hello() )\n(10, ())\n\n>>> print( hello(1, 2, 3) )\n(1, (2, 3))  # x = 10 was overridden, x is now 1\n```\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Simplified Introspection",
    "version": "0.1.0",
    "project_urls": {
        "repository": "https://github.com/muhamuhamuha/callsign"
    },
    "split_keywords": [
        "ddd",
        " decorator",
        " decorator driven development",
        " function",
        " introspection",
        " metaprogramming",
        " signature"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7d8394b30a31488afb94dd632766415ec920f1bd4280a93c1a6542d5d6dfadb4",
                "md5": "78926ac544a3d8d85d586ad504be5ce8",
                "sha256": "5aacbb9235990e18c4f260623bef15a60be4a341bc34bb1fe16cf2efdec43573"
            },
            "downloads": -1,
            "filename": "callsign-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "78926ac544a3d8d85d586ad504be5ce8",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 5861,
            "upload_time": "2024-06-15T19:33:04",
            "upload_time_iso_8601": "2024-06-15T19:33:04.609322Z",
            "url": "https://files.pythonhosted.org/packages/7d/83/94b30a31488afb94dd632766415ec920f1bd4280a93c1a6542d5d6dfadb4/callsign-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1c0afed204b26b1de939b296acecdbd876cc94803faf8a4239d0ec8ee45ea610",
                "md5": "ba4b817d66e1c4ff3a0cb75b8b6e9a7a",
                "sha256": "afa4c594e8aa3228e94edee5256bcf0d01adf294c339118941bc090371eec124"
            },
            "downloads": -1,
            "filename": "callsign-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "ba4b817d66e1c4ff3a0cb75b8b6e9a7a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 1109830,
            "upload_time": "2024-06-15T19:33:06",
            "upload_time_iso_8601": "2024-06-15T19:33:06.743927Z",
            "url": "https://files.pythonhosted.org/packages/1c/0a/fed204b26b1de939b296acecdbd876cc94803faf8a4239d0ec8ee45ea610/callsign-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-06-15 19:33:06",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "muhamuhamuha",
    "github_project": "callsign",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "callsign"
}
        
Elapsed time: 0.29663s