varname 0.13.5__tar.gz → 0.15.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: varname
3
- Version: 0.13.5
3
+ Version: 0.15.0
4
4
  Summary: Dark magics about variable names in python.
5
- Home-page: https://github.com/pwwang/python-varname
6
5
  License: MIT
7
6
  Author: pwwang
8
7
  Author-email: pwwang@pwwang.com
@@ -14,10 +13,13 @@ Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
17
  Provides-Extra: all
18
- Requires-Dist: asttokens (==2.*) ; extra == "all"
18
+ Requires-Dist: asttokens (==3.*) ; extra == "all"
19
19
  Requires-Dist: executing (>=2.1,<3.0)
20
20
  Requires-Dist: pure_eval (==0.*) ; extra == "all"
21
+ Requires-Dist: typing_extensions (>=4.13,<5.0) ; python_version < "3.10"
22
+ Project-URL: Homepage, https://github.com/pwwang/python-varname
21
23
  Project-URL: Repository, https://github.com/pwwang/python-varname
22
24
  Description-Content-Type: text/markdown
23
25
 
@@ -44,7 +46,6 @@ Note if you use `python < 3.8`, install `varname < 0.11`
44
46
  - Core features:
45
47
 
46
48
  - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`.
47
- - Retrieving variable names directly, using `nameof`
48
49
  - Detecting next immediate attribute name, using `will`
49
50
  - Fetching argument names/sources passed to a function using `argname`
50
51
 
@@ -438,22 +439,27 @@ obj.argnames # ['1', '2']
438
439
  `varname` is all depending on `executing` package to look for the node.
439
440
  The node `executing` detects is ensured to be the correct one (see [this][19]).
440
441
 
441
- It partially works with environments where other AST magics apply, including
442
- `pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither
442
+ It partially works with environments where other AST magics apply, including [`exec`][24] function,
443
+ [`macropy`][21], [`birdseye`][22], [`reticulate`][23] with `R`, etc. Neither
443
444
  `executing` nor `varname` is 100% working with those environments. Use
444
445
  it at your own risk.
445
446
 
446
447
  For example:
447
448
 
448
- - This will not work with `pytest`:
449
+ - This will not work:
449
450
 
450
451
  ```python
452
+ from varname import argname
453
+
454
+ def getname(x):
455
+ print(argname("x"))
456
+
451
457
  a = 1
452
- assert nameof(a) == 'a' # pytest manipulated the ast here
458
+ exec("getname(a)") # Cannot retrieve the node where the function is called.
453
459
 
454
- # do this instead
455
- name_a = nameof(a)
456
- assert name_a == 'a'
460
+ ## instead
461
+ # from varname.helpers import exec_code
462
+ # exec_code("getname(a)")
457
463
  ```
458
464
 
459
465
  [1]: https://github.com/pwwang/python-varname
@@ -475,4 +481,8 @@ For example:
475
481
  [17]: https://img.shields.io/pypi/dm/varname?style=flat-square
476
482
  [19]: https://github.com/alexmojaki/executing#is-it-reliable
477
483
  [20]: https://stackoverflow.com/a/59364138/5088165
484
+ [21]: https://github.com/lihaoyi/macropy
485
+ [22]: https://github.com/alexmojaki/birdseye
486
+ [23]: https://rstudio.github.io/reticulate/
487
+ [24]: https://docs.python.org/3/library/functions.html#exec
478
488
 
@@ -21,7 +21,6 @@ Note if you use `python < 3.8`, install `varname < 0.11`
21
21
  - Core features:
22
22
 
23
23
  - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`.
24
- - Retrieving variable names directly, using `nameof`
25
24
  - Detecting next immediate attribute name, using `will`
26
25
  - Fetching argument names/sources passed to a function using `argname`
27
26
 
@@ -415,22 +414,27 @@ obj.argnames # ['1', '2']
415
414
  `varname` is all depending on `executing` package to look for the node.
416
415
  The node `executing` detects is ensured to be the correct one (see [this][19]).
417
416
 
418
- It partially works with environments where other AST magics apply, including
419
- `pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither
417
+ It partially works with environments where other AST magics apply, including [`exec`][24] function,
418
+ [`macropy`][21], [`birdseye`][22], [`reticulate`][23] with `R`, etc. Neither
420
419
  `executing` nor `varname` is 100% working with those environments. Use
421
420
  it at your own risk.
422
421
 
423
422
  For example:
424
423
 
425
- - This will not work with `pytest`:
424
+ - This will not work:
426
425
 
427
426
  ```python
427
+ from varname import argname
428
+
429
+ def getname(x):
430
+ print(argname("x"))
431
+
428
432
  a = 1
429
- assert nameof(a) == 'a' # pytest manipulated the ast here
433
+ exec("getname(a)") # Cannot retrieve the node where the function is called.
430
434
 
431
- # do this instead
432
- name_a = nameof(a)
433
- assert name_a == 'a'
435
+ ## instead
436
+ # from varname.helpers import exec_code
437
+ # exec_code("getname(a)")
434
438
  ```
435
439
 
436
440
  [1]: https://github.com/pwwang/python-varname
@@ -452,3 +456,7 @@ For example:
452
456
  [17]: https://img.shields.io/pypi/dm/varname?style=flat-square
453
457
  [19]: https://github.com/alexmojaki/executing#is-it-reliable
454
458
  [20]: https://stackoverflow.com/a/59364138/5088165
459
+ [21]: https://github.com/lihaoyi/macropy
460
+ [22]: https://github.com/alexmojaki/birdseye
461
+ [23]: https://rstudio.github.io/reticulate/
462
+ [24]: https://docs.python.org/3/library/functions.html#exec
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "varname"
7
- version = "0.13.5"
7
+ version = "0.15.0"
8
8
  description = "Dark magics about variable names in python."
9
9
  authors = [ "pwwang <pwwang@pwwang.com>",]
10
10
  license = "MIT"
@@ -18,13 +18,15 @@ generate-setup-file = true
18
18
  [tool.poetry.dependencies]
19
19
  python = "^3.8"
20
20
  executing = "^2.1"
21
- asttokens = { version = "2.*", optional = true }
21
+ asttokens = { version = "3.*", optional = true }
22
22
  pure_eval = { version = "0.*", optional = true }
23
+ typing_extensions = { version = "^4.13", markers = "python_version < '3.10'" }
23
24
 
24
- [tool.poetry.dev-dependencies]
25
+ [tool.poetry.group.dev.dependencies]
25
26
  pytest = "^8"
26
27
  pytest-cov = "^5"
27
28
  coverage = { version = "^7", extras = ["toml"] }
29
+ ipykernel = "^6.29.5"
28
30
 
29
31
  [tool.poetry.extras]
30
32
  all = ["asttokens", "pure_eval"]
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ from setuptools import setup
3
+
4
+ packages = \
5
+ ['varname']
6
+
7
+ package_data = \
8
+ {'': ['*']}
9
+
10
+ install_requires = \
11
+ ['executing>=2.1,<3.0']
12
+
13
+ extras_require = \
14
+ {':python_version < "3.10"': ['typing_extensions>=4.13,<5.0'],
15
+ 'all': ['asttokens==3.*', 'pure_eval==0.*']}
16
+
17
+ setup_kwargs = {
18
+ 'name': 'varname',
19
+ 'version': '0.15.0',
20
+ 'description': 'Dark magics about variable names in python.',
21
+ 'long_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 - 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 [`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',
22
+ 'author': 'pwwang',
23
+ 'author_email': 'pwwang@pwwang.com',
24
+ 'maintainer': 'None',
25
+ 'maintainer_email': 'None',
26
+ 'url': 'https://github.com/pwwang/python-varname',
27
+ 'packages': packages,
28
+ 'package_data': package_data,
29
+ 'install_requires': install_requires,
30
+ 'extras_require': extras_require,
31
+ 'python_requires': '>=3.8,<4.0',
32
+ }
33
+
34
+
35
+ setup(**setup_kwargs)
@@ -13,4 +13,4 @@ from .utils import (
13
13
  )
14
14
  from .core import varname, nameof, will, argname
15
15
 
16
- __version__ = "0.13.5"
16
+ __version__ = "0.15.0"
@@ -1,4 +1,5 @@
1
1
  """Provide core features for varname"""
2
+ from __future__ import annotations
2
3
  import ast
3
4
  import re
4
5
  import warnings
@@ -291,11 +292,6 @@ def nameof(
291
292
  VarnameRetrievingError: When the callee's node cannot be retrieved or
292
293
  trying to retrieve the full name of non attribute series calls.
293
294
  """
294
- warnings.warn(
295
- "`nameof` is deprecated and will be removed in the future. "
296
- "Please use `argname` instead.",
297
- DeprecationWarning,
298
- )
299
295
  # Frame is anyway used in get_node
300
296
  frameobj = IgnoreList.create(
301
297
  ignore_lambda=False,
@@ -20,6 +20,11 @@ from functools import lru_cache, singledispatch
20
20
  from types import ModuleType, FunctionType, CodeType, FrameType
21
21
  from typing import Tuple, Union, List, Mapping, Callable, Dict
22
22
 
23
+ if sys.version_info < (3, 10):
24
+ from typing_extensions import TypeAlias # pragma: no cover
25
+ else:
26
+ from typing import TypeAlias
27
+
23
28
  from executing import Source
24
29
 
25
30
  OP2MAGIC = {
@@ -63,16 +68,16 @@ IgnoreElemType = Union[
63
68
  ]
64
69
  IgnoreType = Union[IgnoreElemType, List[IgnoreElemType]]
65
70
 
66
- ArgSourceType = Union[ast.AST, str]
67
- ArgSourceType = Union[ArgSourceType, Tuple[ArgSourceType, ...]]
68
- ArgSourceType = Union[ArgSourceType, Mapping[str, ArgSourceType]]
71
+ ArgSourceType: TypeAlias = Union[ast.AST, str]
72
+ ArgSourceType: TypeAlias = Union[ArgSourceType, Tuple[ArgSourceType, ...]]
73
+ ArgSourceType: TypeAlias = Union[ArgSourceType, Mapping[str, ArgSourceType]]
69
74
 
70
75
  if sys.version_info >= (3, 8):
71
76
  ASSIGN_TYPES = (ast.Assign, ast.AnnAssign, ast.NamedExpr)
72
- AssignType = Union[ASSIGN_TYPES] # type: ignore
73
- else: # pragma: no cover
77
+ AssignType: TypeAlias = Union[ASSIGN_TYPES] # type: ignore
78
+ else: # pragma: no cover # Python < 3.8
74
79
  ASSIGN_TYPES = (ast.Assign, ast.AnnAssign)
75
- AssignType = Union[ASSIGN_TYPES] # type: ignore
80
+ AssignType: TypeAlias = Union[ASSIGN_TYPES] # type: ignore
76
81
 
77
82
  PY311 = sys.version_info >= (3, 11)
78
83
  MODULE_IGNORE_ID_NAME = "__varname_ignore_id__"
@@ -163,7 +168,7 @@ def get_node_by_frame(frame: FrameType, raise_exc: bool = True) -> ast.AST:
163
168
  exect.node.__frame__ = frame
164
169
  return exect.node
165
170
 
166
- if exect.source.text and exect.source.tree and raise_exc:
171
+ if exect.source.text and exect.source.tree and raise_exc: # pragma: no cover
167
172
  raise VarnameRetrievingError(
168
173
  "Couldn't retrieve the call node. "
169
174
  "This may happen if you're using some other AST magic at the "
@@ -550,7 +555,7 @@ def _(node: Union[ast.Attribute, ast.Subscript]) -> ast.Call:
550
555
  args=[keynode],
551
556
  keywords=[],
552
557
  )
553
- else:
558
+ else: # pragma: no cover
554
559
  return ast.Call( # type: ignore
555
560
  func=ast.Attribute(
556
561
  value=node.value,
@@ -597,7 +602,7 @@ def _(node: Union[ast.Attribute, ast.Subscript]) -> ast.Call:
597
602
  args=[keynode, node.parent.value], # type: ignore
598
603
  keywords=[],
599
604
  )
600
- else:
605
+ else: # pragma: no cover
601
606
  return ast.Call(
602
607
  func=ast.Attribute(
603
608
  value=node.value,
@@ -638,7 +643,7 @@ def _(node: ast.Compare) -> ast.Call:
638
643
  args=[node.comparators[0]],
639
644
  keywords=[],
640
645
  )
641
- else:
646
+ else: # pragma: no cover
642
647
  return ast.Call( # type: ignore
643
648
  func=ast.Attribute(
644
649
  value=node.left,
@@ -672,7 +677,7 @@ def _(node: ast.BinOp) -> ast.Call:
672
677
  args=[node.right],
673
678
  keywords=[],
674
679
  )
675
- else:
680
+ else: # pragma: no cover
676
681
  return ast.Call( # type: ignore
677
682
  func=ast.Attribute(
678
683
  value=node.left,
varname-0.13.5/setup.py DELETED
@@ -1,34 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from setuptools import setup
3
-
4
- packages = \
5
- ['varname']
6
-
7
- package_data = \
8
- {'': ['*']}
9
-
10
- install_requires = \
11
- ['executing>=2.1,<3.0']
12
-
13
- extras_require = \
14
- {'all': ['asttokens==2.*', 'pure_eval==0.*']}
15
-
16
- setup_kwargs = {
17
- 'name': 'varname',
18
- 'version': '0.13.5',
19
- 'description': 'Dark magics about variable names in python.',
20
- 'long_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',
21
- 'author': 'pwwang',
22
- 'author_email': 'pwwang@pwwang.com',
23
- 'maintainer': 'None',
24
- 'maintainer_email': 'None',
25
- 'url': 'https://github.com/pwwang/python-varname',
26
- 'packages': packages,
27
- 'package_data': package_data,
28
- 'install_requires': install_requires,
29
- 'extras_require': extras_require,
30
- 'python_requires': '>=3.8,<4.0',
31
- }
32
-
33
-
34
- setup(**setup_kwargs)
File without changes
File without changes
File without changes
File without changes