{"id":13816676,"url":"https://github.com/pwwang/python-varname","last_synced_at":"2025-05-14T21:06:48.756Z","repository":{"id":41124942,"uuid":"228448368","full_name":"pwwang/python-varname","owner":"pwwang","description":"Dark magics about variable names in python","archived":false,"fork":false,"pushed_at":"2025-01-15T20:02:14.000Z","size":783,"stargazers_count":326,"open_issues_count":1,"forks_count":25,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-13T17:46:56.149Z","etag":null,"topics":["debugging-tool","nameof","python-variables","python-varname","variable-name-recovery","variables"],"latest_commit_sha":null,"homepage":"https://pwwang.github.io/python-varname/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pwwang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-16T18:20:08.000Z","updated_at":"2025-04-13T14:11:29.000Z","dependencies_parsed_at":"2023-01-30T19:45:33.659Z","dependency_job_id":"5531cb8f-dd0b-4de1-bbcb-ab6f2a73a2fd","html_url":"https://github.com/pwwang/python-varname","commit_stats":{"total_commits":159,"total_committers":8,"mean_commits":19.875,"dds":0.3836477987421384,"last_synced_commit":"13bc550169f9d2538b9cf999ec2b6d44e3d71bb5"},"previous_names":[],"tags_count":51,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwwang%2Fpython-varname","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwwang%2Fpython-varname/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwwang%2Fpython-varname/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pwwang%2Fpython-varname/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pwwang","download_url":"https://codeload.github.com/pwwang/python-varname/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254227611,"owners_count":22035669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debugging-tool","nameof","python-variables","python-varname","variable-name-recovery","variables"],"created_at":"2024-08-04T05:00:49.366Z","updated_at":"2025-05-14T21:06:43.740Z","avatar_url":"https://github.com/pwwang.png","language":"Python","readme":"![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 \u003c 3.8`, install `varname \u003c 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  - 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\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/alexmojaki/executing\"\u003e\n        \u003cimg src=\"https://ui-avatars.com/api/?color=3333ff\u0026background=ffffff\u0026bold=true\u0026name=e\u0026size=400\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003eexecuting\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/alexmojaki\"\u003e\n        \u003cimg src=\"https://avatars0.githubusercontent.com/u/3627481?s=400\u0026v=4\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003e@alexmojaki\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/breuleux\"\u003e\n        \u003cimg src=\"https://avatars.githubusercontent.com/u/599820?s=400\u0026v=4\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003e@breuleux\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/ElCuboNegro\"\u003e\n        \u003cimg src=\"https://avatars.githubusercontent.com/u/5524219?s=400\u0026v=4\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003e@ElCuboNegro\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/thewchan\"\u003e\n        \u003cimg src=\"https://avatars.githubusercontent.com/u/49702524?s=400\u0026v=4\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003e@thewchan\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/LawsOfSympathy\"\u003e\n        \u003cimg src=\"https://avatars.githubusercontent.com/u/96355982?s=400\u0026v=4\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003e@LawsOfSympathy\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n    \u003ctd align=\"center\" style=\"min-width: 75px\"\u003e\n      \u003ca href=\"https://github.com/elliotgunton\"\u003e\n        \u003cimg src=\"https://avatars.githubusercontent.com/u/17798778?s=400\u0026v=4\" width=\"50px;\" alt=\"\"/\u003e\n        \u003cbr /\u003e\u003csub\u003e\u003cb\u003e@elliotgunton\u003c/b\u003e\u003c/sub\u003e\n      \u003c/a\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\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 \u003c 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### 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 [`exec`][24] function,\n[`macropy`][21], [`birdseye`][22], [`reticulate`][23] 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:\n\n  ```python\n  from varname import argname\n\n  def getname(x):\n      print(argname(\"x\"))\n\n  a = 1\n  exec(\"getname(a)\")  # Cannot retrieve the node where the function is called.\n\n  ## instead\n  # from varname.helpers import exec_code\n  # exec_code(\"getname(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[21]: https://github.com/lihaoyi/macropy\n[22]: https://github.com/alexmojaki/birdseye\n[23]: https://rstudio.github.io/reticulate/\n[24]: https://docs.python.org/3/library/functions.html#exec\n","funding_links":[],"categories":["Topics Index"],"sub_categories":["QoL Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpwwang%2Fpython-varname","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpwwang%2Fpython-varname","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpwwang%2Fpython-varname/lists"}