varname 0.13.5__tar.gz → 0.14.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {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
|