Metadata-Version: 2.1
Name: funchacks
Version: 1.0.1
Summary: UNKNOWN
Home-page: https://github.com/Animatea/funchacks
Author: DenyS
License: Apache License, Version 2.0
Download-URL: https://github.com/Animatea/funchacks/archive/refs/heads/main.zip
Project-URL: GitHub, https://github.com/Animatea/funchacks
Project-URL: Bug Tracker, https://github.com/Animatea/funchacks/issues
Keywords: FUNCTIONAL PROGRAMMING,FUNCTION TOOLS,FUNCTION UTILS,UTILS
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Libraries
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Intended Audience :: Other Audience
Classifier: Typing :: Typed
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE.md

<h1 align="center">funchacks</h1>
<p align="center">
<a href="https://github.com/psf/black"><img height="20" alt="PyPI version" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
<a href="https://pycqa.github.io/isort/"><img height="20" alt="Supported python versions" src="https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336"></a>
<br>
<a href="https://www.python.org/dev/peps/pep-0008/"><img height="20" alt="CI status" src="https://img.shields.io/badge/flake8-checked-blue.svg"></a>
<a href="https://pypi.org/project/mypy/"><img height="20" alt="Mypy badge" src="http://www.mypy-lang.org/static/mypy_badge.svg"></a>

<div align="center">
    <a href="https://discord.com/invite/KKUFRZCt4f"><img src="https://discordapp.com/api/guilds/744099317836677161/widget.png?style=banner2" alt="" /></a>
</div>

# 👋 Introduction
Funchacks is a fun module that provides a small package of utilities.

**Dynamic signature change without compile, eval and exec?**
That was the main idea of the project! But this path is a little dangerous,
so the part could not be implemented, but if possible it will be implemented in the next versions!

**So is it worth using funchacks signature utilities?**
More likely no than yes. If you want a really optimized and safe implementation of this idea, it's better to
look into `makefun` (this was another reason why I wanted to do a dynamic signature change without compile, eval and exec).

# ⚙️ Installation
```bash
pip install funchacks
```

# 🚀 Quick start

- ### 🔎 Function locals
```py
from funchacks import inspections


def foo() -> None:
    some_local_var = 1
    other_var = 2

>>> dict(inspections.getlocals(foo.__code__))
{"some_local_var": 1, "other_var": 2}
```

- ### 🔗 Dynamic function signature
> `(!)` Note: if you add *positional only* or *positional arguments*, then there must be `*args` in the function signature.
> Accordingly, if you add *keyword only* or *keyword arguments* - `**kwargs`.

```py
import inspect
from typing import Any

from funchacks import sig
```

```py
@sig.change_args(
    sig.posonly("first"),
    sig.arg("second"),
)
def foo(*args: Any) -> None:
    """
    !!! Note:
        Temporarily positional only arguments are available only for
        the signature, there may be errors when calling the function.
    """

>>> inspect.Signature.from_callable(foo)
(first, /, second, *args)
```

```py
@sig.change_args(
    sig.kwarg("first", None),
    sig.kwonly("second"),
)
def bar(**kwargs: Any) -> None:
    """
    !!! Note:
        Temporarily keyword only arguments are available only for
        the signature, there may be errors when calling the function.
    """

>>> inspect.Signature.from_callable(bar)
(first=None, *, second, **kwargs)
```

```py
@sig.change_args(
    sig.arg("first"),
    sig.kwarg("second", None)
)
def baz(*args: Any, **kwargs: Any) -> None:
    """This should work.

    But how to access the arguments? locals?...
    """
    # All wrapped function has __sig__ attribute
    # that contains function signature.
    lvars = sig.Bind.from_locals(locals(), in_=baz)

    assert lvars.args() == ["first"]
    assert lvars.kwargs() == ["second"]

    return lvars.get("first") + lvars.get("second")

>>> inspect.Signature.from_callable(baz)
(first, second=None, *args, **kwargs)

>>> baz(1, 2)
3
```

#### Signature from function.
```py
def spam(a, /, b, c=None, *, d) -> None:
    pass


@sig.from_function(spam)
def eggs(*args: Any, **kwargs: Any) -> None:
    pass

>>> inspect.Signature.from_callable(eggs)
(a, /, b, c=None, *, d)
```


