varname


Namevarname JSON
Version 0.13.5 PyPI version JSON
download
home_pagehttps://github.com/pwwang/python-varname
SummaryDark magics about variable names in python.
upload_time2024-10-11 18:27:51
maintainerNone
docs_urlNone
authorpwwang
requires_python<4.0,>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ![varname][7]

[![Pypi][3]][4] [![Github][5]][6] [![PythonVers][8]][4] ![Building][10]
[![Docs and API][9]][15] [![Codacy][12]][13] [![Codacy coverage][14]][13]
![Downloads][17]

Dark magics about variable names in python

[CHANGELOG][16] | [API][15] | [Playground][11] | :fire: [StackOverflow answer][20]

## Installation

```shell
pip install -U varname
```

Note if you use `python < 3.8`, install `varname < 0.11`

## Features

- Core features:

  - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`.
  - Retrieving variable names directly, using `nameof`
  - Detecting next immediate attribute name, using `will`
  - Fetching argument names/sources passed to a function using `argname`

- Other helper APIs (built based on core features):

  - A value wrapper to store the variable name that a value is assigned to, using `Wrapper`
  - A decorator to register `__varname__` to functions/classes, using `register`
  - A helper function to create dict without explicitly specifying the key-value pairs, using `jsobj`
  - A `debug` function to print variables with their names and values
  - `exec_code` to replace `exec` where source code is available at runtime

## Credits

Thanks goes to these awesome people/projects:

<table>
  <tr>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/alexmojaki/executing">
        <img src="https://ui-avatars.com/api/?color=3333ff&background=ffffff&bold=true&name=e&size=400" width="50px;" alt=""/>
        <br /><sub><b>executing</b></sub>
      </a>
    </td>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/alexmojaki">
        <img src="https://avatars0.githubusercontent.com/u/3627481?s=400&v=4" width="50px;" alt=""/>
        <br /><sub><b>@alexmojaki</b></sub>
      </a>
    </td>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/breuleux">
        <img src="https://avatars.githubusercontent.com/u/599820?s=400&v=4" width="50px;" alt=""/>
        <br /><sub><b>@breuleux</b></sub>
      </a>
    </td>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/ElCuboNegro">
        <img src="https://avatars.githubusercontent.com/u/5524219?s=400&v=4" width="50px;" alt=""/>
        <br /><sub><b>@ElCuboNegro</b></sub>
      </a>
    </td>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/thewchan">
        <img src="https://avatars.githubusercontent.com/u/49702524?s=400&v=4" width="50px;" alt=""/>
        <br /><sub><b>@thewchan</b></sub>
      </a>
    </td>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/LawsOfSympathy">
        <img src="https://avatars.githubusercontent.com/u/96355982?s=400&v=4" width="50px;" alt=""/>
        <br /><sub><b>@LawsOfSympathy</b></sub>
      </a>
    </td>
    <td align="center" style="min-width: 75px">
      <a href="https://github.com/elliotgunton">
        <img src="https://avatars.githubusercontent.com/u/17798778?s=400&v=4" width="50px;" alt=""/>
        <br /><sub><b>@elliotgunton</b></sub>
      </a>
    </td>
  </tr>
</table>

Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this project.

## Usage

### Retrieving the variable names using `varname(...)`

- From inside a function

    ```python
    from varname import varname
    def function():
        return varname()

    func = function()  # func == 'func'
    ```

    When there are intermediate frames:

    ```python
    def wrapped():
        return function()

    def function():
        # retrieve the variable name at the 2nd frame from this one
        return varname(frame=2)

    func = wrapped() # func == 'func'
    ```

    Or use `ignore` to ignore the wrapped frame:

    ```python
    def wrapped():
        return function()

    def function():
        return varname(ignore=wrapped)

    func = wrapped() # func == 'func'
    ```

    Calls from standard libraries are ignored by default:

    ```python
    import asyncio

    async def function():
        return varname()

    func = asyncio.run(function()) # func == 'func'
    ```

    Use `strict` to control whether the call should be assigned to
    the variable directly:

    ```python
    def function(strict):
        return varname(strict=strict)

    func = function(True)     # OK, direct assignment, func == 'func'

    func = [function(True)]   # Not a direct assignment, raises ImproperUseError
    func = [function(False)]  # OK, func == ['func']

    func = function(False), function(False)   # OK, func = ('func', 'func')
    ```

- Retrieving name of a class instance

    ```python
    class Foo:
        def __init__(self):
            self.id = varname()

        def copy(self):
            # also able to fetch inside a method call
            copied = Foo() # copied.id == 'copied'
            copied.id = varname() # assign id to whatever variable name
            return copied

    foo = Foo()   # foo.id == 'foo'

    foo2 = foo.copy() # foo2.id == 'foo2'
    ```

- Multiple variables on Left-hand side

    ```python
    # since v0.5.4
    def func():
        return varname(multi_vars=True)

    a = func() # a == ('a',)
    a, b = func() # (a, b) == ('a', 'b')
    [a, b] = func() # (a, b) == ('a', 'b')

    # hierarchy is also possible
    a, (b, c) = func() # (a, b, c) == ('a', 'b', 'c')
    ```

- Some unusual use

    ```python
    def function(**kwargs):
        return varname(strict=False)

    func = func1 = function()  # func == func1 == 'func1'
    # if varname < 0.8: func == func1 == 'func'
    # a warning will be shown
    # since you may not want func to be 'func1'

    x = function(y = function())  # x == 'x'

    # get part of the name
    func_abc = function()[-3:]  # func_abc == 'abc'

    # function alias supported now
    function2 = function
    func = function2()  # func == 'func'

    a = lambda: 0
    a.b = function() # a.b == 'a.b'
    ```

### The decorator way to register `__varname__` to functions/classes

- Registering `__varname__` to functions

    ```python
    from varname.helpers import register

    @register
    def function():
        return __varname__

    func = function() # func == 'func'
    ```

    ```python
    # arguments also allowed (frame, ignore and raise_exc)
    @register(frame=2)
    def function():
        return __varname__

    def wrapped():
        return function()

    func = wrapped() # func == 'func'
    ```

- Registering `__varname__` as a class property

    ```python
    @register
    class Foo:
        ...

    foo = Foo()
    # foo.__varname__ == 'foo'
    ```

### Getting variable names directly using `nameof`

```python
from varname import varname, nameof

a = 1
nameof(a) # 'a'

b = 2
nameof(a, b) # ('a', 'b')

def func():
    return varname() + '_suffix'

f = func() # f == 'f_suffix'
nameof(f)  # 'f'

# get full names of (chained) attribute calls
func.a = func
nameof(func.a, vars_only=False) # 'func.a'

func.a.b = 1
nameof(func.a.b, vars_only=False) # 'func.a.b'
```

### Detecting next immediate attribute name

```python
from varname import will
class AwesomeClass:
    def __init__(self):
        self.will = None

    def permit(self):
        self.will = will(raise_exc=False)
        if self.will == 'do':
            # let self handle do
            return self
        raise AttributeError('Should do something with AwesomeClass object')

    def do(self):
        if self.will != 'do':
            raise AttributeError("You don't have permission to do")
        return 'I am doing!'

awesome = AwesomeClass()
awesome.do() # AttributeError: You don't have permission to do
awesome.permit() # AttributeError: Should do something with AwesomeClass object
awesome.permit().do() == 'I am doing!'
```

### Fetching argument names/sources using `argname`

```python
from varname import argname

def func(a, b=1):
    print(argname('a'))

x = y = z = 2
func(x) # prints: x


def func2(a, b=1):
    print(argname('a', 'b'))
func2(y, b=x) # prints: ('y', 'x')


# allow expressions
def func3(a, b=1):
    print(argname('a', 'b', vars_only=False))
func3(x+y, y+x) # prints: ('x+y', 'y+x')


# positional and keyword arguments
def func4(*args, **kwargs):
    print(argname('args[1]', 'kwargs[c]'))
func4(y, x, c=z) # prints: ('x', 'z')


# As of 0.9.0 (see: https://pwwang.github.io/python-varname/CHANGELOG/#v090)
# Can also fetch the source of the argument for
# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc.
class Foo:
    def __setattr__(self, name, value):
        print(argname("name", "value", func=self.__setattr__))

Foo().a = 1 # prints: ("'a'", '1')

```

### Value wrapper

```python
from varname.helpers import Wrapper

foo = Wrapper(True)
# foo.name == 'foo'
# foo.value == True
bar = Wrapper(False)
# bar.name == 'bar'
# bar.value == False

def values_to_dict(*args):
    return {val.name: val.value for val in args}

mydict = values_to_dict(foo, bar)
# {'foo': True, 'bar': False}
```

### Creating dictionary using `jsobj`

```python
from varname.helpers import jsobj

a = 1
b = 2
jsobj(a, b) # {'a': 1, 'b': 2}
jsobj(a, b, c=3) # {'a': 1, 'b': 2, 'c': 3}
```

### Debugging with `debug`

```python
from varname.helpers import debug

a = 'value'
b = ['val']
debug(a)
# "DEBUG: a='value'\n"
debug(b)
# "DEBUG: b=['val']\n"
debug(a, b)
# "DEBUG: a='value'\nDEBUG: b=['val']\n"
debug(a, b, merge=True)
# "DEBUG: a='value', b=['val']\n"
debug(a, repr=False, prefix='')
# 'a=value\n'
# also debug an expression
debug(a+a)
# "DEBUG: a+a='valuevalue'\n"
# If you want to disable it:
debug(a+a, vars_only=True) # ImproperUseError
```

### Replacing `exec` with `exec_code`

```python
from varname import argname
from varname.helpers import exec_code

class Obj:
    def __init__(self):
        self.argnames = []

    def receive(self, arg):
        self.argnames.append(argname('arg', func=self.receive))

obj = Obj()
# exec('obj.receive(1)')  # Error
exec_code('obj.receive(1)')
exec_code('obj.receive(2)')
obj.argnames # ['1', '2']
```

## Reliability and limitations

`varname` is all depending on `executing` package to look for the node.
The node `executing` detects is ensured to be the correct one (see [this][19]).

It partially works with environments where other AST magics apply, including
`pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither
`executing` nor `varname` is 100% working with those environments. Use
it at your own risk.

For example:

- This will not work with `pytest`:

  ```python
  a = 1
  assert nameof(a) == 'a' # pytest manipulated the ast here

  # do this instead
  name_a = nameof(a)
  assert name_a == 'a'
  ```

[1]: https://github.com/pwwang/python-varname
[2]: https://github.com/HanyuuLu
[3]: https://img.shields.io/pypi/v/varname?style=flat-square
[4]: https://pypi.org/project/varname/
[5]: https://img.shields.io/github/tag/pwwang/python-varname?style=flat-square
[6]: https://github.com/pwwang/python-varname
[7]: logo.png
[8]: https://img.shields.io/pypi/pyversions/varname?style=flat-square
[9]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/docs.yml?branch=master
[10]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/build.yml?branch=master
[11]: https://mybinder.org/v2/gh/pwwang/python-varname/dev?filepath=playground%2Fplayground.ipynb
[12]: https://img.shields.io/codacy/grade/6fdb19c845f74c5c92056e88d44154f7?style=flat-square
[13]: https://app.codacy.com/gh/pwwang/python-varname/dashboard
[14]: https://img.shields.io/codacy/coverage/6fdb19c845f74c5c92056e88d44154f7?style=flat-square
[15]: https://pwwang.github.io/python-varname/api/varname
[16]: https://pwwang.github.io/python-varname/CHANGELOG/
[17]: https://img.shields.io/pypi/dm/varname?style=flat-square
[19]: https://github.com/alexmojaki/executing#is-it-reliable
[20]: https://stackoverflow.com/a/59364138/5088165

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/pwwang/python-varname",
    "name": "varname",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.8",
    "maintainer_email": null,
    "keywords": null,
    "author": "pwwang",
    "author_email": "pwwang@pwwang.com",
    "download_url": "https://files.pythonhosted.org/packages/34/b1/0867a112a538a6275960e2a0995a8aec15325927bb1f60fa92a4fca9b561/varname-0.13.5.tar.gz",
    "platform": null,
    "description": "![varname][7]\n\n[![Pypi][3]][4] [![Github][5]][6] [![PythonVers][8]][4] ![Building][10]\n[![Docs and API][9]][15] [![Codacy][12]][13] [![Codacy coverage][14]][13]\n![Downloads][17]\n\nDark magics about variable names in python\n\n[CHANGELOG][16] | [API][15] | [Playground][11] | :fire: [StackOverflow answer][20]\n\n## Installation\n\n```shell\npip install -U varname\n```\n\nNote if you use `python < 3.8`, install `varname < 0.11`\n\n## Features\n\n- Core features:\n\n  - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`.\n  - Retrieving variable names directly, using `nameof`\n  - Detecting next immediate attribute name, using `will`\n  - Fetching argument names/sources passed to a function using `argname`\n\n- Other helper APIs (built based on core features):\n\n  - A value wrapper to store the variable name that a value is assigned to, using `Wrapper`\n  - A decorator to register `__varname__` to functions/classes, using `register`\n  - A helper function to create dict without explicitly specifying the key-value pairs, using `jsobj`\n  - A `debug` function to print variables with their names and values\n  - `exec_code` to replace `exec` where source code is available at runtime\n\n## Credits\n\nThanks goes to these awesome people/projects:\n\n<table>\n  <tr>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/alexmojaki/executing\">\n        <img src=\"https://ui-avatars.com/api/?color=3333ff&background=ffffff&bold=true&name=e&size=400\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>executing</b></sub>\n      </a>\n    </td>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/alexmojaki\">\n        <img src=\"https://avatars0.githubusercontent.com/u/3627481?s=400&v=4\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>@alexmojaki</b></sub>\n      </a>\n    </td>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/breuleux\">\n        <img src=\"https://avatars.githubusercontent.com/u/599820?s=400&v=4\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>@breuleux</b></sub>\n      </a>\n    </td>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/ElCuboNegro\">\n        <img src=\"https://avatars.githubusercontent.com/u/5524219?s=400&v=4\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>@ElCuboNegro</b></sub>\n      </a>\n    </td>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/thewchan\">\n        <img src=\"https://avatars.githubusercontent.com/u/49702524?s=400&v=4\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>@thewchan</b></sub>\n      </a>\n    </td>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/LawsOfSympathy\">\n        <img src=\"https://avatars.githubusercontent.com/u/96355982?s=400&v=4\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>@LawsOfSympathy</b></sub>\n      </a>\n    </td>\n    <td align=\"center\" style=\"min-width: 75px\">\n      <a href=\"https://github.com/elliotgunton\">\n        <img src=\"https://avatars.githubusercontent.com/u/17798778?s=400&v=4\" width=\"50px;\" alt=\"\"/>\n        <br /><sub><b>@elliotgunton</b></sub>\n      </a>\n    </td>\n  </tr>\n</table>\n\nSpecial thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this project.\n\n## Usage\n\n### Retrieving the variable names using `varname(...)`\n\n- From inside a function\n\n    ```python\n    from varname import varname\n    def function():\n        return varname()\n\n    func = function()  # func == 'func'\n    ```\n\n    When there are intermediate frames:\n\n    ```python\n    def wrapped():\n        return function()\n\n    def function():\n        # retrieve the variable name at the 2nd frame from this one\n        return varname(frame=2)\n\n    func = wrapped() # func == 'func'\n    ```\n\n    Or use `ignore` to ignore the wrapped frame:\n\n    ```python\n    def wrapped():\n        return function()\n\n    def function():\n        return varname(ignore=wrapped)\n\n    func = wrapped() # func == 'func'\n    ```\n\n    Calls from standard libraries are ignored by default:\n\n    ```python\n    import asyncio\n\n    async def function():\n        return varname()\n\n    func = asyncio.run(function()) # func == 'func'\n    ```\n\n    Use `strict` to control whether the call should be assigned to\n    the variable directly:\n\n    ```python\n    def function(strict):\n        return varname(strict=strict)\n\n    func = function(True)     # OK, direct assignment, func == 'func'\n\n    func = [function(True)]   # Not a direct assignment, raises ImproperUseError\n    func = [function(False)]  # OK, func == ['func']\n\n    func = function(False), function(False)   # OK, func = ('func', 'func')\n    ```\n\n- Retrieving name of a class instance\n\n    ```python\n    class Foo:\n        def __init__(self):\n            self.id = varname()\n\n        def copy(self):\n            # also able to fetch inside a method call\n            copied = Foo() # copied.id == 'copied'\n            copied.id = varname() # assign id to whatever variable name\n            return copied\n\n    foo = Foo()   # foo.id == 'foo'\n\n    foo2 = foo.copy() # foo2.id == 'foo2'\n    ```\n\n- Multiple variables on Left-hand side\n\n    ```python\n    # since v0.5.4\n    def func():\n        return varname(multi_vars=True)\n\n    a = func() # a == ('a',)\n    a, b = func() # (a, b) == ('a', 'b')\n    [a, b] = func() # (a, b) == ('a', 'b')\n\n    # hierarchy is also possible\n    a, (b, c) = func() # (a, b, c) == ('a', 'b', 'c')\n    ```\n\n- Some unusual use\n\n    ```python\n    def function(**kwargs):\n        return varname(strict=False)\n\n    func = func1 = function()  # func == func1 == 'func1'\n    # if varname < 0.8: func == func1 == 'func'\n    # a warning will be shown\n    # since you may not want func to be 'func1'\n\n    x = function(y = function())  # x == 'x'\n\n    # get part of the name\n    func_abc = function()[-3:]  # func_abc == 'abc'\n\n    # function alias supported now\n    function2 = function\n    func = function2()  # func == 'func'\n\n    a = lambda: 0\n    a.b = function() # a.b == 'a.b'\n    ```\n\n### The decorator way to register `__varname__` to functions/classes\n\n- Registering `__varname__` to functions\n\n    ```python\n    from varname.helpers import register\n\n    @register\n    def function():\n        return __varname__\n\n    func = function() # func == 'func'\n    ```\n\n    ```python\n    # arguments also allowed (frame, ignore and raise_exc)\n    @register(frame=2)\n    def function():\n        return __varname__\n\n    def wrapped():\n        return function()\n\n    func = wrapped() # func == 'func'\n    ```\n\n- Registering `__varname__` as a class property\n\n    ```python\n    @register\n    class Foo:\n        ...\n\n    foo = Foo()\n    # foo.__varname__ == 'foo'\n    ```\n\n### Getting variable names directly using `nameof`\n\n```python\nfrom varname import varname, nameof\n\na = 1\nnameof(a) # 'a'\n\nb = 2\nnameof(a, b) # ('a', 'b')\n\ndef func():\n    return varname() + '_suffix'\n\nf = func() # f == 'f_suffix'\nnameof(f)  # 'f'\n\n# get full names of (chained) attribute calls\nfunc.a = func\nnameof(func.a, vars_only=False) # 'func.a'\n\nfunc.a.b = 1\nnameof(func.a.b, vars_only=False) # 'func.a.b'\n```\n\n### Detecting next immediate attribute name\n\n```python\nfrom varname import will\nclass AwesomeClass:\n    def __init__(self):\n        self.will = None\n\n    def permit(self):\n        self.will = will(raise_exc=False)\n        if self.will == 'do':\n            # let self handle do\n            return self\n        raise AttributeError('Should do something with AwesomeClass object')\n\n    def do(self):\n        if self.will != 'do':\n            raise AttributeError(\"You don't have permission to do\")\n        return 'I am doing!'\n\nawesome = AwesomeClass()\nawesome.do() # AttributeError: You don't have permission to do\nawesome.permit() # AttributeError: Should do something with AwesomeClass object\nawesome.permit().do() == 'I am doing!'\n```\n\n### Fetching argument names/sources using `argname`\n\n```python\nfrom varname import argname\n\ndef func(a, b=1):\n    print(argname('a'))\n\nx = y = z = 2\nfunc(x) # prints: x\n\n\ndef func2(a, b=1):\n    print(argname('a', 'b'))\nfunc2(y, b=x) # prints: ('y', 'x')\n\n\n# allow expressions\ndef func3(a, b=1):\n    print(argname('a', 'b', vars_only=False))\nfunc3(x+y, y+x) # prints: ('x+y', 'y+x')\n\n\n# positional and keyword arguments\ndef func4(*args, **kwargs):\n    print(argname('args[1]', 'kwargs[c]'))\nfunc4(y, x, c=z) # prints: ('x', 'z')\n\n\n# As of 0.9.0 (see: https://pwwang.github.io/python-varname/CHANGELOG/#v090)\n# Can also fetch the source of the argument for\n# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc.\nclass Foo:\n    def __setattr__(self, name, value):\n        print(argname(\"name\", \"value\", func=self.__setattr__))\n\nFoo().a = 1 # prints: (\"'a'\", '1')\n\n```\n\n### Value wrapper\n\n```python\nfrom varname.helpers import Wrapper\n\nfoo = Wrapper(True)\n# foo.name == 'foo'\n# foo.value == True\nbar = Wrapper(False)\n# bar.name == 'bar'\n# bar.value == False\n\ndef values_to_dict(*args):\n    return {val.name: val.value for val in args}\n\nmydict = values_to_dict(foo, bar)\n# {'foo': True, 'bar': False}\n```\n\n### Creating dictionary using `jsobj`\n\n```python\nfrom varname.helpers import jsobj\n\na = 1\nb = 2\njsobj(a, b) # {'a': 1, 'b': 2}\njsobj(a, b, c=3) # {'a': 1, 'b': 2, 'c': 3}\n```\n\n### Debugging with `debug`\n\n```python\nfrom varname.helpers import debug\n\na = 'value'\nb = ['val']\ndebug(a)\n# \"DEBUG: a='value'\\n\"\ndebug(b)\n# \"DEBUG: b=['val']\\n\"\ndebug(a, b)\n# \"DEBUG: a='value'\\nDEBUG: b=['val']\\n\"\ndebug(a, b, merge=True)\n# \"DEBUG: a='value', b=['val']\\n\"\ndebug(a, repr=False, prefix='')\n# 'a=value\\n'\n# also debug an expression\ndebug(a+a)\n# \"DEBUG: a+a='valuevalue'\\n\"\n# If you want to disable it:\ndebug(a+a, vars_only=True) # ImproperUseError\n```\n\n### Replacing `exec` with `exec_code`\n\n```python\nfrom varname import argname\nfrom varname.helpers import exec_code\n\nclass Obj:\n    def __init__(self):\n        self.argnames = []\n\n    def receive(self, arg):\n        self.argnames.append(argname('arg', func=self.receive))\n\nobj = Obj()\n# exec('obj.receive(1)')  # Error\nexec_code('obj.receive(1)')\nexec_code('obj.receive(2)')\nobj.argnames # ['1', '2']\n```\n\n## Reliability and limitations\n\n`varname` is all depending on `executing` package to look for the node.\nThe node `executing` detects is ensured to be the correct one (see [this][19]).\n\nIt partially works with environments where other AST magics apply, including\n`pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither\n`executing` nor `varname` is 100% working with those environments. Use\nit at your own risk.\n\nFor example:\n\n- This will not work with `pytest`:\n\n  ```python\n  a = 1\n  assert nameof(a) == 'a' # pytest manipulated the ast here\n\n  # do this instead\n  name_a = nameof(a)\n  assert name_a == 'a'\n  ```\n\n[1]: https://github.com/pwwang/python-varname\n[2]: https://github.com/HanyuuLu\n[3]: https://img.shields.io/pypi/v/varname?style=flat-square\n[4]: https://pypi.org/project/varname/\n[5]: https://img.shields.io/github/tag/pwwang/python-varname?style=flat-square\n[6]: https://github.com/pwwang/python-varname\n[7]: logo.png\n[8]: https://img.shields.io/pypi/pyversions/varname?style=flat-square\n[9]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/docs.yml?branch=master\n[10]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/build.yml?branch=master\n[11]: https://mybinder.org/v2/gh/pwwang/python-varname/dev?filepath=playground%2Fplayground.ipynb\n[12]: https://img.shields.io/codacy/grade/6fdb19c845f74c5c92056e88d44154f7?style=flat-square\n[13]: https://app.codacy.com/gh/pwwang/python-varname/dashboard\n[14]: https://img.shields.io/codacy/coverage/6fdb19c845f74c5c92056e88d44154f7?style=flat-square\n[15]: https://pwwang.github.io/python-varname/api/varname\n[16]: https://pwwang.github.io/python-varname/CHANGELOG/\n[17]: https://img.shields.io/pypi/dm/varname?style=flat-square\n[19]: https://github.com/alexmojaki/executing#is-it-reliable\n[20]: https://stackoverflow.com/a/59364138/5088165\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Dark magics about variable names in python.",
    "version": "0.13.5",
    "project_urls": {
        "Homepage": "https://github.com/pwwang/python-varname",
        "Repository": "https://github.com/pwwang/python-varname"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "3a9f7fe9de6b51d368682a9c896261523759ebc84eca14a91b8ae2b111b62810",
                "md5": "e6c8675ec205bcc970ffc182561809c0",
                "sha256": "55bc967573215ff93cbf77d6fe979c353b199080eac660adfb3b35b303f6eda2"
            },
            "downloads": -1,
            "filename": "varname-0.13.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e6c8675ec205bcc970ffc182561809c0",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.8",
            "size": 25075,
            "upload_time": "2024-10-11T18:27:50",
            "upload_time_iso_8601": "2024-10-11T18:27:50.017157Z",
            "url": "https://files.pythonhosted.org/packages/3a/9f/7fe9de6b51d368682a9c896261523759ebc84eca14a91b8ae2b111b62810/varname-0.13.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "34b10867a112a538a6275960e2a0995a8aec15325927bb1f60fa92a4fca9b561",
                "md5": "a35d1e8f80b3d4a23d04965b31daa10b",
                "sha256": "82076a5c08e1b8b4fd0c9b5b1bf4a211a86d5367f97aa7f91d8eccb84017b3bf"
            },
            "downloads": -1,
            "filename": "varname-0.13.5.tar.gz",
            "has_sig": false,
            "md5_digest": "a35d1e8f80b3d4a23d04965b31daa10b",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.8",
            "size": 27432,
            "upload_time": "2024-10-11T18:27:51",
            "upload_time_iso_8601": "2024-10-11T18:27:51.432784Z",
            "url": "https://files.pythonhosted.org/packages/34/b1/0867a112a538a6275960e2a0995a8aec15325927bb1f60fa92a4fca9b561/varname-0.13.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-11 18:27:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "pwwang",
    "github_project": "python-varname",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "varname"
}
        
Elapsed time: 0.89248s