varname 0.13.5__tar.gz → 0.14.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.
- {varname-0.13.5 → varname-0.14.0}/PKG-INFO +21 -37
- {varname-0.13.5 → varname-0.14.0}/README.md +16 -33
- {varname-0.13.5 → varname-0.14.0}/pyproject.toml +3 -2
- varname-0.14.0/setup.py +34 -0
- {varname-0.13.5 → varname-0.14.0}/varname/__init__.py +2 -2
- {varname-0.13.5 → varname-0.14.0}/varname/core.py +2 -130
- {varname-0.13.5 → varname-0.14.0}/varname/utils.py +7 -73
- varname-0.13.5/setup.py +0 -34
- {varname-0.13.5 → varname-0.14.0}/LICENSE +0 -0
- {varname-0.13.5 → varname-0.14.0}/varname/helpers.py +0 -0
- {varname-0.13.5 → varname-0.14.0}/varname/ignore.py +0 -0
- {varname-0.13.5 → varname-0.14.0}/varname/py.typed +0 -0
@@ -1,8 +1,7 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: varname
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.14.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,12 @@ 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 (==
|
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
|
+
Project-URL: Homepage, https://github.com/pwwang/python-varname
|
21
22
|
Project-URL: Repository, https://github.com/pwwang/python-varname
|
22
23
|
Description-Content-Type: text/markdown
|
23
24
|
|
@@ -44,7 +45,6 @@ Note if you use `python < 3.8`, install `varname < 0.11`
|
|
44
45
|
- Core features:
|
45
46
|
|
46
47
|
- Retrieving names of variables a function/class call is assigned to from inside it, using `varname`.
|
47
|
-
- Retrieving variable names directly, using `nameof`
|
48
48
|
- Detecting next immediate attribute name, using `will`
|
49
49
|
- Fetching argument names/sources passed to a function using `argname`
|
50
50
|
|
@@ -268,31 +268,6 @@ Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this
|
|
268
268
|
# foo.__varname__ == 'foo'
|
269
269
|
```
|
270
270
|
|
271
|
-
### Getting variable names directly using `nameof`
|
272
|
-
|
273
|
-
```python
|
274
|
-
from varname import varname, nameof
|
275
|
-
|
276
|
-
a = 1
|
277
|
-
nameof(a) # 'a'
|
278
|
-
|
279
|
-
b = 2
|
280
|
-
nameof(a, b) # ('a', 'b')
|
281
|
-
|
282
|
-
def func():
|
283
|
-
return varname() + '_suffix'
|
284
|
-
|
285
|
-
f = func() # f == 'f_suffix'
|
286
|
-
nameof(f) # 'f'
|
287
|
-
|
288
|
-
# get full names of (chained) attribute calls
|
289
|
-
func.a = func
|
290
|
-
nameof(func.a, vars_only=False) # 'func.a'
|
291
|
-
|
292
|
-
func.a.b = 1
|
293
|
-
nameof(func.a.b, vars_only=False) # 'func.a.b'
|
294
|
-
```
|
295
|
-
|
296
271
|
### Detecting next immediate attribute name
|
297
272
|
|
298
273
|
```python
|
@@ -438,22 +413,27 @@ obj.argnames # ['1', '2']
|
|
438
413
|
`varname` is all depending on `executing` package to look for the node.
|
439
414
|
The node `executing` detects is ensured to be the correct one (see [this][19]).
|
440
415
|
|
441
|
-
It partially works with environments where other AST magics apply, including
|
442
|
-
`
|
416
|
+
It partially works with environments where other AST magics apply, including [`exec`][24] function,
|
417
|
+
[`macropy`][21], [`birdseye`][22], [`reticulate`][23] with `R`, etc. Neither
|
443
418
|
`executing` nor `varname` is 100% working with those environments. Use
|
444
419
|
it at your own risk.
|
445
420
|
|
446
421
|
For example:
|
447
422
|
|
448
|
-
- This will not work
|
423
|
+
- This will not work:
|
449
424
|
|
450
425
|
```python
|
426
|
+
from varname import argname
|
427
|
+
|
428
|
+
def getname(x):
|
429
|
+
print(argname("x"))
|
430
|
+
|
451
431
|
a = 1
|
452
|
-
|
432
|
+
exec("getname(a)") # Cannot retrieve the node where the function is called.
|
453
433
|
|
454
|
-
|
455
|
-
|
456
|
-
|
434
|
+
## instead
|
435
|
+
# from varname.helpers import exec_code
|
436
|
+
# exec_code("getname(a)")
|
457
437
|
```
|
458
438
|
|
459
439
|
[1]: https://github.com/pwwang/python-varname
|
@@ -475,4 +455,8 @@ For example:
|
|
475
455
|
[17]: https://img.shields.io/pypi/dm/varname?style=flat-square
|
476
456
|
[19]: https://github.com/alexmojaki/executing#is-it-reliable
|
477
457
|
[20]: https://stackoverflow.com/a/59364138/5088165
|
458
|
+
[21]: https://github.com/lihaoyi/macropy
|
459
|
+
[22]: https://github.com/alexmojaki/birdseye
|
460
|
+
[23]: https://rstudio.github.io/reticulate/
|
461
|
+
[24]: https://docs.python.org/3/library/functions.html#exec
|
478
462
|
|
@@ -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
|
|
@@ -245,31 +244,6 @@ Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this
|
|
245
244
|
# foo.__varname__ == 'foo'
|
246
245
|
```
|
247
246
|
|
248
|
-
### Getting variable names directly using `nameof`
|
249
|
-
|
250
|
-
```python
|
251
|
-
from varname import varname, nameof
|
252
|
-
|
253
|
-
a = 1
|
254
|
-
nameof(a) # 'a'
|
255
|
-
|
256
|
-
b = 2
|
257
|
-
nameof(a, b) # ('a', 'b')
|
258
|
-
|
259
|
-
def func():
|
260
|
-
return varname() + '_suffix'
|
261
|
-
|
262
|
-
f = func() # f == 'f_suffix'
|
263
|
-
nameof(f) # 'f'
|
264
|
-
|
265
|
-
# get full names of (chained) attribute calls
|
266
|
-
func.a = func
|
267
|
-
nameof(func.a, vars_only=False) # 'func.a'
|
268
|
-
|
269
|
-
func.a.b = 1
|
270
|
-
nameof(func.a.b, vars_only=False) # 'func.a.b'
|
271
|
-
```
|
272
|
-
|
273
247
|
### Detecting next immediate attribute name
|
274
248
|
|
275
249
|
```python
|
@@ -415,22 +389,27 @@ obj.argnames # ['1', '2']
|
|
415
389
|
`varname` is all depending on `executing` package to look for the node.
|
416
390
|
The node `executing` detects is ensured to be the correct one (see [this][19]).
|
417
391
|
|
418
|
-
It partially works with environments where other AST magics apply, including
|
419
|
-
`
|
392
|
+
It partially works with environments where other AST magics apply, including [`exec`][24] function,
|
393
|
+
[`macropy`][21], [`birdseye`][22], [`reticulate`][23] with `R`, etc. Neither
|
420
394
|
`executing` nor `varname` is 100% working with those environments. Use
|
421
395
|
it at your own risk.
|
422
396
|
|
423
397
|
For example:
|
424
398
|
|
425
|
-
- This will not work
|
399
|
+
- This will not work:
|
426
400
|
|
427
401
|
```python
|
402
|
+
from varname import argname
|
403
|
+
|
404
|
+
def getname(x):
|
405
|
+
print(argname("x"))
|
406
|
+
|
428
407
|
a = 1
|
429
|
-
|
408
|
+
exec("getname(a)") # Cannot retrieve the node where the function is called.
|
430
409
|
|
431
|
-
|
432
|
-
|
433
|
-
|
410
|
+
## instead
|
411
|
+
# from varname.helpers import exec_code
|
412
|
+
# exec_code("getname(a)")
|
434
413
|
```
|
435
414
|
|
436
415
|
[1]: https://github.com/pwwang/python-varname
|
@@ -452,3 +431,7 @@ For example:
|
|
452
431
|
[17]: https://img.shields.io/pypi/dm/varname?style=flat-square
|
453
432
|
[19]: https://github.com/alexmojaki/executing#is-it-reliable
|
454
433
|
[20]: https://stackoverflow.com/a/59364138/5088165
|
434
|
+
[21]: https://github.com/lihaoyi/macropy
|
435
|
+
[22]: https://github.com/alexmojaki/birdseye
|
436
|
+
[23]: https://rstudio.github.io/reticulate/
|
437
|
+
[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.
|
7
|
+
version = "0.14.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,14 @@ generate-setup-file = true
|
|
18
18
|
[tool.poetry.dependencies]
|
19
19
|
python = "^3.8"
|
20
20
|
executing = "^2.1"
|
21
|
-
asttokens = { version = "
|
21
|
+
asttokens = { version = "3.*", optional = true }
|
22
22
|
pure_eval = { version = "0.*", optional = true }
|
23
23
|
|
24
24
|
[tool.poetry.dev-dependencies]
|
25
25
|
pytest = "^8"
|
26
26
|
pytest-cov = "^5"
|
27
27
|
coverage = { version = "^7", extras = ["toml"] }
|
28
|
+
ipykernel = "^6.29.5"
|
28
29
|
|
29
30
|
[tool.poetry.extras]
|
30
31
|
all = ["asttokens", "pure_eval"]
|
varname-0.14.0/setup.py
ADDED
@@ -0,0 +1,34 @@
|
|
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==3.*', 'pure_eval==0.*']}
|
15
|
+
|
16
|
+
setup_kwargs = {
|
17
|
+
'name': 'varname',
|
18
|
+
'version': '0.14.0',
|
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 - 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### 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',
|
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)
|
@@ -1,13 +1,13 @@
|
|
1
1
|
"""Provide core features for varname"""
|
2
|
+
from __future__ import annotations
|
2
3
|
import ast
|
3
4
|
import re
|
4
5
|
import warnings
|
5
|
-
from typing import
|
6
|
+
from typing import List, Union, Tuple, Type, Callable, overload
|
6
7
|
|
7
8
|
from executing import Source
|
8
9
|
|
9
10
|
from .utils import (
|
10
|
-
bytecode_nameof,
|
11
11
|
get_node,
|
12
12
|
get_node_by_frame,
|
13
13
|
lookfor_parent_assign,
|
@@ -217,134 +217,6 @@ def will(frame: int = 1, raise_exc: bool = True) -> str:
|
|
217
217
|
return node.attr
|
218
218
|
|
219
219
|
|
220
|
-
@overload
|
221
|
-
def nameof(
|
222
|
-
var: Any,
|
223
|
-
*,
|
224
|
-
frame: int = 1,
|
225
|
-
vars_only: bool = True,
|
226
|
-
) -> str: # pragma: no cover
|
227
|
-
...
|
228
|
-
|
229
|
-
|
230
|
-
@overload
|
231
|
-
def nameof(
|
232
|
-
var: Any,
|
233
|
-
more_var: Any,
|
234
|
-
/, # introduced in python 3.8
|
235
|
-
*more_vars: Any,
|
236
|
-
frame: int = 1,
|
237
|
-
vars_only: bool = True,
|
238
|
-
) -> Tuple[str, ...]: # pragma: no cover
|
239
|
-
...
|
240
|
-
|
241
|
-
|
242
|
-
def nameof(
|
243
|
-
var: Any,
|
244
|
-
*more_vars: Any,
|
245
|
-
frame: int = 1,
|
246
|
-
vars_only: bool = True,
|
247
|
-
) -> Union[str, Tuple[str, ...]]:
|
248
|
-
"""Get the names of the variables passed in
|
249
|
-
|
250
|
-
Examples:
|
251
|
-
>>> a = 1
|
252
|
-
>>> nameof(a) # 'a'
|
253
|
-
|
254
|
-
>>> b = 2
|
255
|
-
>>> nameof(a, b) # ('a', 'b')
|
256
|
-
|
257
|
-
>>> x = lambda: None
|
258
|
-
>>> x.y = 1
|
259
|
-
>>> nameof(x.y, vars_only=False) # 'x.y'
|
260
|
-
|
261
|
-
Note:
|
262
|
-
This function works with the environments where source code is
|
263
|
-
available, in other words, the callee's node can be retrieved by
|
264
|
-
`executing`. In some cases, for example, running code from python
|
265
|
-
shell/REPL or from `exec`/`eval`, we try to fetch the variable name
|
266
|
-
from the bytecode. This requires only a single variable name is passed
|
267
|
-
to this function and no keyword arguments, meaning that getting full
|
268
|
-
names of attribute calls are not supported in such cases.
|
269
|
-
|
270
|
-
Args:
|
271
|
-
var: The variable to retrieve the name of
|
272
|
-
*more_vars: Other variables to retrieve the names of
|
273
|
-
frame: The this function is called from the wrapper of it. `frame=1`
|
274
|
-
means no wrappers.
|
275
|
-
Note that the calls from standard libraries are ignored.
|
276
|
-
Also note that the wrapper has to have signature as this one.
|
277
|
-
vars_only: Whether only allow variables/attributes as arguments or
|
278
|
-
any expressions. If `False`, then the sources of the arguments
|
279
|
-
will be returned.
|
280
|
-
|
281
|
-
Returns:
|
282
|
-
The names/sources of variables/expressions passed in.
|
283
|
-
If a single argument is passed, return the name/source of it.
|
284
|
-
If multiple variables are passed, return a tuple of their
|
285
|
-
names/sources.
|
286
|
-
If the argument is an attribute (e.g. `a.b`) and `vars_only` is
|
287
|
-
`True`, only `"b"` will returned. Set `vars_only` to `False` to
|
288
|
-
get `"a.b"`.
|
289
|
-
|
290
|
-
Raises:
|
291
|
-
VarnameRetrievingError: When the callee's node cannot be retrieved or
|
292
|
-
trying to retrieve the full name of non attribute series calls.
|
293
|
-
"""
|
294
|
-
warnings.warn(
|
295
|
-
"`nameof` is deprecated and will be removed in the future. "
|
296
|
-
"Please use `argname` instead.",
|
297
|
-
DeprecationWarning,
|
298
|
-
)
|
299
|
-
# Frame is anyway used in get_node
|
300
|
-
frameobj = IgnoreList.create(
|
301
|
-
ignore_lambda=False,
|
302
|
-
ignore_varname=False,
|
303
|
-
).get_frame(frame)
|
304
|
-
|
305
|
-
node = get_node_by_frame(frameobj, raise_exc=True)
|
306
|
-
if not node:
|
307
|
-
# We can't retrieve the node by executing.
|
308
|
-
# It can be due to running code from python/shell, exec/eval or
|
309
|
-
# other environments where sourcecode cannot be reached
|
310
|
-
# make sure we keep it simple (only single variable passed and no
|
311
|
-
# full passed) to use bytecode_nameof
|
312
|
-
#
|
313
|
-
# We don't have to check keyword arguments here, as the instruction
|
314
|
-
# will then be CALL_FUNCTION_KW.
|
315
|
-
if not more_vars:
|
316
|
-
return bytecode_nameof(frameobj.f_code, frameobj.f_lasti)
|
317
|
-
|
318
|
-
# We are anyway raising exceptions, no worries about additional burden
|
319
|
-
# of frame retrieval again
|
320
|
-
source = frameobj.f_code.co_filename
|
321
|
-
if source == "<stdin>":
|
322
|
-
raise VarnameRetrievingError(
|
323
|
-
"Are you trying to call nameof in REPL/python shell? "
|
324
|
-
"In such a case, nameof can only be called with single "
|
325
|
-
"argument and no keyword arguments."
|
326
|
-
)
|
327
|
-
if source == "<string>":
|
328
|
-
raise VarnameRetrievingError(
|
329
|
-
"Are you trying to call nameof from exec/eval? "
|
330
|
-
"In such a case, nameof can only be called with single "
|
331
|
-
"argument and no keyword arguments."
|
332
|
-
)
|
333
|
-
raise VarnameRetrievingError(
|
334
|
-
"Source code unavailable, nameof can only retrieve the name of "
|
335
|
-
"a single variable, and argument `full` should not be specified."
|
336
|
-
)
|
337
|
-
|
338
|
-
out = argname(
|
339
|
-
"var",
|
340
|
-
"*more_vars",
|
341
|
-
func=nameof,
|
342
|
-
frame=frame,
|
343
|
-
vars_only=vars_only,
|
344
|
-
)
|
345
|
-
return out if more_vars else out[0] # type: ignore
|
346
|
-
|
347
|
-
|
348
220
|
@overload
|
349
221
|
def argname(
|
350
222
|
arg: str,
|
@@ -10,7 +10,6 @@ Attributes:
|
|
10
10
|
`inspect.getmodule(frame)`
|
11
11
|
"""
|
12
12
|
import sys
|
13
|
-
import dis
|
14
13
|
import ast
|
15
14
|
import warnings
|
16
15
|
import inspect
|
@@ -18,7 +17,7 @@ from os import path
|
|
18
17
|
from pathlib import Path
|
19
18
|
from functools import lru_cache, singledispatch
|
20
19
|
from types import ModuleType, FunctionType, CodeType, FrameType
|
21
|
-
from typing import Tuple, Union, List, Mapping, Callable
|
20
|
+
from typing import Tuple, Union, List, Mapping, Callable
|
22
21
|
|
23
22
|
from executing import Source
|
24
23
|
|
@@ -163,11 +162,11 @@ def get_node_by_frame(frame: FrameType, raise_exc: bool = True) -> ast.AST:
|
|
163
162
|
exect.node.__frame__ = frame
|
164
163
|
return exect.node
|
165
164
|
|
166
|
-
if exect.source.text and exect.source.tree and raise_exc:
|
165
|
+
if exect.source.text and exect.source.tree and raise_exc: # pragma: no cover
|
167
166
|
raise VarnameRetrievingError(
|
168
167
|
"Couldn't retrieve the call node. "
|
169
168
|
"This may happen if you're using some other AST magic at the "
|
170
|
-
"same time, such as pytest,
|
169
|
+
"same time, such as pytest, macropy, or birdseye."
|
171
170
|
)
|
172
171
|
|
173
172
|
return None
|
@@ -244,71 +243,6 @@ def node_name(
|
|
244
243
|
)
|
245
244
|
|
246
245
|
|
247
|
-
@lru_cache()
|
248
|
-
def bytecode_nameof(code: CodeType, offset: int) -> str:
|
249
|
-
"""Cached Bytecode version of nameof
|
250
|
-
|
251
|
-
We are trying this version only when the sourcecode is unavisible. In most
|
252
|
-
cases, this will happen when user is trying to run a script in REPL/
|
253
|
-
python shell, with `eval`, or other circumstances where the code is
|
254
|
-
manipulated to run but sourcecode is not available.
|
255
|
-
"""
|
256
|
-
kwargs: Dict[str, bool] = (
|
257
|
-
{"show_caches": True} if sys.version_info[:2] >= (3, 11) else {}
|
258
|
-
)
|
259
|
-
|
260
|
-
instructions = list(dis.get_instructions(code, **kwargs))
|
261
|
-
((current_instruction_index, current_instruction),) = (
|
262
|
-
(index, instruction)
|
263
|
-
for index, instruction in enumerate(instructions)
|
264
|
-
if instruction.offset == offset
|
265
|
-
)
|
266
|
-
|
267
|
-
while current_instruction.opname == "CACHE": # pragma: no cover
|
268
|
-
current_instruction_index -= 1
|
269
|
-
current_instruction = instructions[current_instruction_index]
|
270
|
-
|
271
|
-
pos_only_error = VarnameRetrievingError(
|
272
|
-
"'nameof' can only be called with a single positional argument "
|
273
|
-
"when source code is not avaiable."
|
274
|
-
)
|
275
|
-
if current_instruction.opname in ( # pragma: no cover
|
276
|
-
"CALL_FUNCTION_EX",
|
277
|
-
"CALL_FUNCTION_KW",
|
278
|
-
):
|
279
|
-
raise pos_only_error
|
280
|
-
|
281
|
-
if current_instruction.opname not in (
|
282
|
-
"CALL_FUNCTION",
|
283
|
-
"CALL_METHOD",
|
284
|
-
"CALL",
|
285
|
-
"CALL_KW",
|
286
|
-
):
|
287
|
-
raise VarnameRetrievingError("Did you call 'nameof' in a weird way?")
|
288
|
-
|
289
|
-
current_instruction_index -= 1
|
290
|
-
name_instruction = instructions[current_instruction_index]
|
291
|
-
while name_instruction.opname in ("CACHE", "PRECALL"): # pragma: no cover
|
292
|
-
current_instruction_index -= 1
|
293
|
-
name_instruction = instructions[current_instruction_index]
|
294
|
-
|
295
|
-
if name_instruction.opname in ("KW_NAMES", "LOAD_CONST"): # LOAD_CONST python 3.13
|
296
|
-
raise pos_only_error
|
297
|
-
|
298
|
-
if not name_instruction.opname.startswith("LOAD_"):
|
299
|
-
raise VarnameRetrievingError("Argument must be a variable or attribute")
|
300
|
-
|
301
|
-
name = name_instruction.argrepr
|
302
|
-
if not name.isidentifier():
|
303
|
-
raise VarnameRetrievingError(
|
304
|
-
f"Found the variable name {name!r} which is obviously wrong. "
|
305
|
-
"This may happen if you're using some other AST magic at the "
|
306
|
-
"same time, such as pytest, ipython, macropy, or birdseye."
|
307
|
-
)
|
308
|
-
|
309
|
-
return name
|
310
|
-
|
311
|
-
|
312
246
|
def attach_ignore_id_to_module(module: ModuleType) -> None:
|
313
247
|
"""Attach the ignore id to module
|
314
248
|
|
@@ -550,7 +484,7 @@ def _(node: Union[ast.Attribute, ast.Subscript]) -> ast.Call:
|
|
550
484
|
args=[keynode],
|
551
485
|
keywords=[],
|
552
486
|
)
|
553
|
-
else:
|
487
|
+
else: # pragma: no cover
|
554
488
|
return ast.Call( # type: ignore
|
555
489
|
func=ast.Attribute(
|
556
490
|
value=node.value,
|
@@ -597,7 +531,7 @@ def _(node: Union[ast.Attribute, ast.Subscript]) -> ast.Call:
|
|
597
531
|
args=[keynode, node.parent.value], # type: ignore
|
598
532
|
keywords=[],
|
599
533
|
)
|
600
|
-
else:
|
534
|
+
else: # pragma: no cover
|
601
535
|
return ast.Call(
|
602
536
|
func=ast.Attribute(
|
603
537
|
value=node.value,
|
@@ -638,7 +572,7 @@ def _(node: ast.Compare) -> ast.Call:
|
|
638
572
|
args=[node.comparators[0]],
|
639
573
|
keywords=[],
|
640
574
|
)
|
641
|
-
else:
|
575
|
+
else: # pragma: no cover
|
642
576
|
return ast.Call( # type: ignore
|
643
577
|
func=ast.Attribute(
|
644
578
|
value=node.left,
|
@@ -672,7 +606,7 @@ def _(node: ast.BinOp) -> ast.Call:
|
|
672
606
|
args=[node.right],
|
673
607
|
keywords=[],
|
674
608
|
)
|
675
|
-
else:
|
609
|
+
else: # pragma: no cover
|
676
610
|
return ast.Call( # type: ignore
|
677
611
|
func=ast.Attribute(
|
678
612
|
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
|