varname 0.13.3__tar.gz → 0.13.5__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {varname-0.13.3 → varname-0.13.5}/PKG-INFO +2 -2
- {varname-0.13.3 → varname-0.13.5}/pyproject.toml +5 -5
- {varname-0.13.3 → varname-0.13.5}/setup.py +2 -2
- {varname-0.13.3 → varname-0.13.5}/varname/__init__.py +1 -1
- {varname-0.13.3 → varname-0.13.5}/varname/core.py +5 -0
- {varname-0.13.3 → varname-0.13.5}/varname/utils.py +114 -55
- {varname-0.13.3 → varname-0.13.5}/LICENSE +0 -0
- {varname-0.13.3 → varname-0.13.5}/README.md +0 -0
- {varname-0.13.3 → varname-0.13.5}/varname/helpers.py +0 -0
- {varname-0.13.3 → varname-0.13.5}/varname/ignore.py +0 -0
- {varname-0.13.3 → varname-0.13.5}/varname/py.typed +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: varname
|
3
|
-
Version: 0.13.
|
3
|
+
Version: 0.13.5
|
4
4
|
Summary: Dark magics about variable names in python.
|
5
5
|
Home-page: https://github.com/pwwang/python-varname
|
6
6
|
License: MIT
|
@@ -16,7 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: asttokens (==2.*) ; extra == "all"
|
19
|
-
Requires-Dist: executing (>=2.
|
19
|
+
Requires-Dist: executing (>=2.1,<3.0)
|
20
20
|
Requires-Dist: pure_eval (==0.*) ; extra == "all"
|
21
21
|
Project-URL: Repository, https://github.com/pwwang/python-varname
|
22
22
|
Description-Content-Type: text/markdown
|
@@ -1,10 +1,10 @@
|
|
1
1
|
[build-system]
|
2
|
-
requires = [
|
3
|
-
build-backend = "poetry.masonry.api"
|
2
|
+
requires = ["poetry-core"]
|
3
|
+
build-backend = "poetry.core.masonry.api"
|
4
4
|
|
5
5
|
[tool.poetry]
|
6
6
|
name = "varname"
|
7
|
-
version = "0.13.
|
7
|
+
version = "0.13.5"
|
8
8
|
description = "Dark magics about variable names in python."
|
9
9
|
authors = [ "pwwang <pwwang@pwwang.com>",]
|
10
10
|
license = "MIT"
|
@@ -17,7 +17,7 @@ generate-setup-file = true
|
|
17
17
|
|
18
18
|
[tool.poetry.dependencies]
|
19
19
|
python = "^3.8"
|
20
|
-
executing = "^2.
|
20
|
+
executing = "^2.1"
|
21
21
|
asttokens = { version = "2.*", optional = true }
|
22
22
|
pure_eval = { version = "0.*", optional = true }
|
23
23
|
|
@@ -43,5 +43,5 @@ strict_optional = false
|
|
43
43
|
|
44
44
|
[tool.black]
|
45
45
|
line-length = 88
|
46
|
-
target-version = ['
|
46
|
+
target-version = ['py38', 'py39', 'py310', 'py311', 'py312', 'py313']
|
47
47
|
include = '\.pyi?$'
|
@@ -8,14 +8,14 @@ package_data = \
|
|
8
8
|
{'': ['*']}
|
9
9
|
|
10
10
|
install_requires = \
|
11
|
-
['executing>=2.
|
11
|
+
['executing>=2.1,<3.0']
|
12
12
|
|
13
13
|
extras_require = \
|
14
14
|
{'all': ['asttokens==2.*', 'pure_eval==0.*']}
|
15
15
|
|
16
16
|
setup_kwargs = {
|
17
17
|
'name': 'varname',
|
18
|
-
'version': '0.13.
|
18
|
+
'version': '0.13.5',
|
19
19
|
'description': 'Dark magics about variable names in python.',
|
20
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
21
|
'author': 'pwwang',
|
@@ -291,6 +291,11 @@ def nameof(
|
|
291
291
|
VarnameRetrievingError: When the callee's node cannot be retrieved or
|
292
292
|
trying to retrieve the full name of non attribute series calls.
|
293
293
|
"""
|
294
|
+
warnings.warn(
|
295
|
+
"`nameof` is deprecated and will be removed in the future. "
|
296
|
+
"Please use `argname` instead.",
|
297
|
+
DeprecationWarning,
|
298
|
+
)
|
294
299
|
# Frame is anyway used in get_node
|
295
300
|
frameobj = IgnoreList.create(
|
296
301
|
ignore_lambda=False,
|
@@ -74,6 +74,7 @@ else: # pragma: no cover
|
|
74
74
|
ASSIGN_TYPES = (ast.Assign, ast.AnnAssign)
|
75
75
|
AssignType = Union[ASSIGN_TYPES] # type: ignore
|
76
76
|
|
77
|
+
PY311 = sys.version_info >= (3, 11)
|
77
78
|
MODULE_IGNORE_ID_NAME = "__varname_ignore_id__"
|
78
79
|
|
79
80
|
|
@@ -281,6 +282,7 @@ def bytecode_nameof(code: CodeType, offset: int) -> str:
|
|
281
282
|
"CALL_FUNCTION",
|
282
283
|
"CALL_METHOD",
|
283
284
|
"CALL",
|
285
|
+
"CALL_KW",
|
284
286
|
):
|
285
287
|
raise VarnameRetrievingError("Did you call 'nameof' in a weird way?")
|
286
288
|
|
@@ -290,7 +292,7 @@ def bytecode_nameof(code: CodeType, offset: int) -> str:
|
|
290
292
|
current_instruction_index -= 1
|
291
293
|
name_instruction = instructions[current_instruction_index]
|
292
294
|
|
293
|
-
if name_instruction.opname
|
295
|
+
if name_instruction.opname in ("KW_NAMES", "LOAD_CONST"): # LOAD_CONST python 3.13
|
294
296
|
raise pos_only_error
|
295
297
|
|
296
298
|
if not name_instruction.opname.startswith("LOAD_"):
|
@@ -533,22 +535,38 @@ def _(node: Union[ast.Attribute, ast.Subscript]) -> ast.Call:
|
|
533
535
|
|
534
536
|
# x[1], x.a
|
535
537
|
if isinstance(node.ctx, ast.Load):
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
538
|
+
if PY311:
|
539
|
+
return ast.Call(
|
540
|
+
func=ast.Attribute(
|
541
|
+
value=node.value,
|
542
|
+
attr=(
|
543
|
+
"__getitem__"
|
544
|
+
if isinstance(node, ast.Subscript)
|
545
|
+
else "__getattr__"
|
546
|
+
),
|
547
|
+
ctx=ast.Load(),
|
548
|
+
**nodemeta,
|
543
549
|
),
|
544
|
-
|
545
|
-
|
546
|
-
)
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
550
|
+
args=[keynode],
|
551
|
+
keywords=[],
|
552
|
+
)
|
553
|
+
else:
|
554
|
+
return ast.Call( # type: ignore
|
555
|
+
func=ast.Attribute(
|
556
|
+
value=node.value,
|
557
|
+
attr=(
|
558
|
+
"__getitem__"
|
559
|
+
if isinstance(node, ast.Subscript)
|
560
|
+
else "__getattr__"
|
561
|
+
),
|
562
|
+
ctx=ast.Load(),
|
563
|
+
**nodemeta,
|
564
|
+
),
|
565
|
+
args=[keynode],
|
566
|
+
keywords=[],
|
567
|
+
starargs=None,
|
568
|
+
kwargs=None,
|
569
|
+
)
|
552
570
|
|
553
571
|
# x[a] = b, x.a = b
|
554
572
|
if (
|
@@ -564,22 +582,38 @@ def _(node: Union[ast.Attribute, ast.Subscript]) -> ast.Call:
|
|
564
582
|
)
|
565
583
|
)
|
566
584
|
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
585
|
+
if PY311:
|
586
|
+
return ast.Call(
|
587
|
+
func=ast.Attribute(
|
588
|
+
value=node.value,
|
589
|
+
attr=(
|
590
|
+
"__setitem__"
|
591
|
+
if isinstance(node, ast.Subscript)
|
592
|
+
else "__setattr__"
|
593
|
+
),
|
594
|
+
ctx=ast.Load(),
|
595
|
+
**nodemeta,
|
574
596
|
),
|
575
|
-
|
576
|
-
|
577
|
-
)
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
597
|
+
args=[keynode, node.parent.value], # type: ignore
|
598
|
+
keywords=[],
|
599
|
+
)
|
600
|
+
else:
|
601
|
+
return ast.Call(
|
602
|
+
func=ast.Attribute(
|
603
|
+
value=node.value,
|
604
|
+
attr=(
|
605
|
+
"__setitem__"
|
606
|
+
if isinstance(node, ast.Subscript)
|
607
|
+
else "__setattr__"
|
608
|
+
),
|
609
|
+
ctx=ast.Load(),
|
610
|
+
**nodemeta,
|
611
|
+
),
|
612
|
+
args=[keynode, node.parent.value], # type: ignore
|
613
|
+
keywords=[],
|
614
|
+
starargs=None,
|
615
|
+
kwargs=None,
|
616
|
+
)
|
583
617
|
|
584
618
|
|
585
619
|
@reconstruct_func_node.register(ast.Compare)
|
@@ -593,18 +627,30 @@ def _(node: ast.Compare) -> ast.Call:
|
|
593
627
|
"lineno": node.lineno,
|
594
628
|
"col_offset": node.col_offset,
|
595
629
|
}
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
630
|
+
if PY311:
|
631
|
+
return ast.Call(
|
632
|
+
func=ast.Attribute(
|
633
|
+
value=node.left,
|
634
|
+
attr=CMP2MAGIC[type(node.ops[0])],
|
635
|
+
ctx=ast.Load(),
|
636
|
+
**nodemeta,
|
637
|
+
),
|
638
|
+
args=[node.comparators[0]],
|
639
|
+
keywords=[],
|
640
|
+
)
|
641
|
+
else:
|
642
|
+
return ast.Call( # type: ignore
|
643
|
+
func=ast.Attribute(
|
644
|
+
value=node.left,
|
645
|
+
attr=CMP2MAGIC[type(node.ops[0])],
|
646
|
+
ctx=ast.Load(),
|
647
|
+
**nodemeta,
|
648
|
+
),
|
649
|
+
args=[node.comparators[0]],
|
650
|
+
keywords=[],
|
651
|
+
starargs=None,
|
652
|
+
kwargs=None,
|
653
|
+
)
|
608
654
|
|
609
655
|
|
610
656
|
@reconstruct_func_node.register(ast.BinOp)
|
@@ -614,18 +660,31 @@ def _(node: ast.BinOp) -> ast.Call:
|
|
614
660
|
"lineno": node.lineno,
|
615
661
|
"col_offset": node.col_offset,
|
616
662
|
}
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
663
|
+
|
664
|
+
if PY311:
|
665
|
+
return ast.Call(
|
666
|
+
func=ast.Attribute(
|
667
|
+
value=node.left,
|
668
|
+
attr=OP2MAGIC[type(node.op)],
|
669
|
+
ctx=ast.Load(),
|
670
|
+
**nodemeta,
|
671
|
+
),
|
672
|
+
args=[node.right],
|
673
|
+
keywords=[],
|
674
|
+
)
|
675
|
+
else:
|
676
|
+
return ast.Call( # type: ignore
|
677
|
+
func=ast.Attribute(
|
678
|
+
value=node.left,
|
679
|
+
attr=OP2MAGIC[type(node.op)],
|
680
|
+
ctx=ast.Load(),
|
681
|
+
**nodemeta,
|
682
|
+
),
|
683
|
+
args=[node.right],
|
684
|
+
keywords=[],
|
685
|
+
starargs=None,
|
686
|
+
kwargs=None,
|
687
|
+
)
|
629
688
|
|
630
689
|
|
631
690
|
def rich_exc_message(msg: str, node: ast.AST, context_lines: int = 4) -> str:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|