varname 0.12.1__py3-none-any.whl → 0.13.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- varname/__init__.py +1 -1
- varname/helpers.py +75 -0
- varname/utils.py +43 -5
- {varname-0.12.1.dist-info → varname-0.13.0.dist-info}/METADATA +24 -3
- varname-0.13.0.dist-info/RECORD +9 -0
- varname-0.12.1.dist-info/RECORD +0 -9
- {varname-0.12.1.dist-info → varname-0.13.0.dist-info}/LICENSE +0 -0
- {varname-0.12.1.dist-info → varname-0.13.0.dist-info}/WHEEL +0 -0
varname/__init__.py
CHANGED
varname/helpers.py
CHANGED
@@ -1,9 +1,13 @@
|
|
1
1
|
"""Some helper functions builtin based upon core features"""
|
2
|
+
from __future__ import annotations
|
3
|
+
|
2
4
|
import inspect
|
3
5
|
from functools import partial, wraps
|
6
|
+
from os import PathLike
|
4
7
|
from typing import Any, Callable, Dict, Tuple, Type, Union
|
5
8
|
|
6
9
|
from .utils import IgnoreType
|
10
|
+
from .ignore import IgnoreList
|
7
11
|
from .core import argname, varname
|
8
12
|
|
9
13
|
|
@@ -220,3 +224,74 @@ def debug(
|
|
220
224
|
else:
|
221
225
|
for name_and_value in name_and_values:
|
222
226
|
print(f"{prefix}{name_and_value}")
|
227
|
+
|
228
|
+
|
229
|
+
def exec_code(
|
230
|
+
code: str,
|
231
|
+
globals: Dict[str, Any] = None,
|
232
|
+
locals: Dict[str, Any] = None,
|
233
|
+
/,
|
234
|
+
sourcefile: PathLike | str = None,
|
235
|
+
frame: int = 1,
|
236
|
+
ignore: IgnoreType = None,
|
237
|
+
**kwargs: Any,
|
238
|
+
) -> None:
|
239
|
+
"""Execute code where source code is visible at runtime.
|
240
|
+
|
241
|
+
This function is useful when you want to execute some code, where you want to
|
242
|
+
retrieve the AST node of the code at runtime. This function will create a
|
243
|
+
temporary file and write the code into it, then execute the code in the
|
244
|
+
file.
|
245
|
+
|
246
|
+
Examples:
|
247
|
+
>>> from varname import varname
|
248
|
+
>>> def func(): return varname()
|
249
|
+
>>> exec('var = func()') # VarnameRetrievingError:
|
250
|
+
>>> # Unable to retrieve the ast node.
|
251
|
+
>>> from varname.helpers import code_exec
|
252
|
+
>>> code_exec('var = func()') # var == 'var'
|
253
|
+
|
254
|
+
Args:
|
255
|
+
code: The code to execute.
|
256
|
+
globals: The globals to use.
|
257
|
+
locals: The locals to use.
|
258
|
+
sourcefile: The source file to write the code into.
|
259
|
+
if not given, a temporary file will be used.
|
260
|
+
This file will be deleted after the code is executed.
|
261
|
+
frame: The call stack index. You can understand this as the number of
|
262
|
+
wrappers around this function. This is used to fetch `globals` and
|
263
|
+
`locals` from where the destination function (include the wrappers
|
264
|
+
of this function)
|
265
|
+
is called.
|
266
|
+
ignore: The intermediate calls to be ignored. See `varname.ignore`
|
267
|
+
Note that if both `globals` and `locals` are given, `frame` and
|
268
|
+
`ignore` will be ignored.
|
269
|
+
**kwargs: The keyword arguments to pass to `exec`.
|
270
|
+
"""
|
271
|
+
if sourcefile is None:
|
272
|
+
import tempfile
|
273
|
+
|
274
|
+
with tempfile.NamedTemporaryFile(
|
275
|
+
mode="w", suffix=".py", delete=False
|
276
|
+
) as f:
|
277
|
+
f.write(code)
|
278
|
+
sourcefile = f.name
|
279
|
+
else:
|
280
|
+
sourcefile = str(sourcefile)
|
281
|
+
with open(sourcefile, "w") as f:
|
282
|
+
f.write(code)
|
283
|
+
|
284
|
+
if globals is None or locals is None:
|
285
|
+
ignore_list = IgnoreList.create(ignore)
|
286
|
+
frame_info = ignore_list.get_frame(frame)
|
287
|
+
if globals is None:
|
288
|
+
globals = frame_info.f_globals
|
289
|
+
if locals is None:
|
290
|
+
locals = frame_info.f_locals
|
291
|
+
|
292
|
+
try:
|
293
|
+
exec(compile(code, sourcefile, "exec"), globals, locals, **kwargs)
|
294
|
+
finally:
|
295
|
+
import os
|
296
|
+
|
297
|
+
os.remove(sourcefile)
|
varname/utils.py
CHANGED
@@ -185,7 +185,10 @@ def lookfor_parent_assign(node: ast.AST, strict: bool = True) -> AssignType:
|
|
185
185
|
return None
|
186
186
|
|
187
187
|
|
188
|
-
def node_name(
|
188
|
+
def node_name(
|
189
|
+
node: ast.AST,
|
190
|
+
subscript_slice: bool = False,
|
191
|
+
) -> Union[str, Tuple[Union[str, Tuple], ...]]:
|
189
192
|
"""Get the node node name.
|
190
193
|
|
191
194
|
Raises ImproperUseError when failed
|
@@ -193,15 +196,50 @@ def node_name(node: ast.AST) -> Union[str, Tuple[Union[str, Tuple], ...]]:
|
|
193
196
|
if isinstance(node, ast.Name):
|
194
197
|
return node.id
|
195
198
|
if isinstance(node, ast.Attribute):
|
196
|
-
return node.attr
|
197
|
-
if isinstance(node,
|
199
|
+
return f"{node_name(node.value)}.{node.attr}"
|
200
|
+
if isinstance(node, ast.Constant):
|
201
|
+
return repr(node.value)
|
202
|
+
if isinstance(node, (ast.List, ast.Tuple)) and not subscript_slice:
|
198
203
|
return tuple(node_name(elem) for elem in node.elts)
|
204
|
+
if isinstance(node, ast.List):
|
205
|
+
return f"[{', '.join(node_name(elem) for elem in node.elts)}]" # type: ignore
|
206
|
+
if isinstance(node, ast.Tuple):
|
207
|
+
if len(node.elts) == 1:
|
208
|
+
return f"({node_name(node.elts[0])},)"
|
209
|
+
return f"({', '.join(node_name(elem) for elem in node.elts)})" # type: ignore
|
199
210
|
if isinstance(node, ast.Starred):
|
200
211
|
return f"*{node_name(node.value)}"
|
212
|
+
if isinstance(node, ast.Slice):
|
213
|
+
return (
|
214
|
+
f"{node_name(node.lower)}:{node_name(node.upper)}:{node_name(node.step)}"
|
215
|
+
if node.lower is not None
|
216
|
+
and node.upper is not None
|
217
|
+
and node.step is not None
|
218
|
+
else f"{node_name(node.lower)}:{node_name(node.upper)}"
|
219
|
+
if node.lower is not None and node.upper is not None
|
220
|
+
else f"{node_name(node.lower)}:"
|
221
|
+
if node.lower is not None
|
222
|
+
else f":{node_name(node.upper)}"
|
223
|
+
if node.upper is not None
|
224
|
+
else ":"
|
225
|
+
)
|
226
|
+
|
227
|
+
name = type(node).__name__
|
228
|
+
if isinstance(node, ast.Subscript):
|
229
|
+
try:
|
230
|
+
return f"{node_name(node.value)}[{node_name(node.slice, True)}]"
|
231
|
+
except ImproperUseError:
|
232
|
+
name = f"{node_name(node.value)}[{type(node.slice).__name__}]"
|
201
233
|
|
202
234
|
raise ImproperUseError(
|
203
|
-
f"
|
204
|
-
|
235
|
+
f"Node {name!r} detected, but only following nodes are supported: \n"
|
236
|
+
" - ast.Name (e.g. x)\n"
|
237
|
+
" - ast.Attribute (e.g. x.y, x be other supported nodes)\n"
|
238
|
+
" - ast.Constant (e.g. 1, 'a')\n"
|
239
|
+
" - ast.List (e.g. [x, y, z])\n"
|
240
|
+
" - ast.Tuple (e.g. (x, y, z))\n"
|
241
|
+
" - ast.Starred (e.g. *x)\n"
|
242
|
+
" - ast.Subscript with slice of the above nodes (e.g. x[y])"
|
205
243
|
)
|
206
244
|
|
207
245
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: varname
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.13.0
|
4
4
|
Summary: Dark magics about variable names in python.
|
5
5
|
Home-page: https://github.com/pwwang/python-varname
|
6
6
|
License: MIT
|
@@ -54,6 +54,7 @@ Note if you use `python < 3.8`, install `varname < 0.11`
|
|
54
54
|
- A decorator to register `__varname__` to functions/classes, using `register`
|
55
55
|
- A helper function to create dict without explicitly specifying the key-value pairs, using `jsobj`
|
56
56
|
- A `debug` function to print variables with their names and values
|
57
|
+
- `exec_code` to replace `exec` where source code is available at runtime
|
57
58
|
|
58
59
|
## Credits
|
59
60
|
|
@@ -221,7 +222,7 @@ Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this
|
|
221
222
|
func = function2() # func == 'func'
|
222
223
|
|
223
224
|
a = lambda: 0
|
224
|
-
a.b = function() # a.b == 'b'
|
225
|
+
a.b = function() # a.b == 'a.b'
|
225
226
|
```
|
226
227
|
|
227
228
|
### The decorator way to register `__varname__` to functions/classes
|
@@ -346,7 +347,7 @@ func4(y, x, c=z) # prints: ('x', 'z')
|
|
346
347
|
# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc.
|
347
348
|
class Foo:
|
348
349
|
def __setattr__(self, name, value):
|
349
|
-
print(argname("name", "value"))
|
350
|
+
print(argname("name", "value", func=self.__setattr__))
|
350
351
|
|
351
352
|
Foo().a = 1 # prints: ("'a'", '1')
|
352
353
|
|
@@ -406,6 +407,26 @@ debug(a+a)
|
|
406
407
|
debug(a+a, vars_only=True) # ImproperUseError
|
407
408
|
```
|
408
409
|
|
410
|
+
### Replacing `exec` with `exec_code`
|
411
|
+
|
412
|
+
```python
|
413
|
+
from varname import argname
|
414
|
+
from varname.helpers import exec_code
|
415
|
+
|
416
|
+
class Obj:
|
417
|
+
def __init__(self):
|
418
|
+
self.argnames = []
|
419
|
+
|
420
|
+
def receive(self, arg):
|
421
|
+
self.argnames.append(argname('arg', func=self.receive))
|
422
|
+
|
423
|
+
obj = Obj()
|
424
|
+
# exec('obj.receive(1)') # Error
|
425
|
+
exec_code('obj.receive(1)')
|
426
|
+
exec_code('obj.receive(2)')
|
427
|
+
obj.argnames # ['1', '2']
|
428
|
+
```
|
429
|
+
|
409
430
|
## Reliability and limitations
|
410
431
|
|
411
432
|
`varname` is all depending on `executing` package to look for the node.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
varname/__init__.py,sha256=UTuY7fG_AbLwpbhBnup66zRlEvl0WnG6exf5AvOyyp0,369
|
2
|
+
varname/core.py,sha256=nntOVpiavXP0EXijTNF6xIe4mxvz_FRpBjrL9z_JHJ0,19311
|
3
|
+
varname/helpers.py,sha256=ho5X2t3PiSYDexwpA4TO_l68VWh3HER7bsUKzcbiCNM,9242
|
4
|
+
varname/ignore.py,sha256=-VC3oqag44y2UlAw0ErYKHotx616qJL3Sjb_5y7Tw1c,14400
|
5
|
+
varname/utils.py,sha256=ByHbUjbdMlHHckW4y77Jr_DHhkSmk8TabTy3INDJWsY,20971
|
6
|
+
varname-0.13.0.dist-info/LICENSE,sha256=3bS8O2tMbBPz8rWmZBAOzkHQjcK-b7KwFHyyghEZ-Ak,1063
|
7
|
+
varname-0.13.0.dist-info/METADATA,sha256=6YjfqWLcmjJ9TXHN5yLlAn0DHrBg3escnFyzqLgKdWM,12580
|
8
|
+
varname-0.13.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
9
|
+
varname-0.13.0.dist-info/RECORD,,
|
varname-0.12.1.dist-info/RECORD
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
varname/__init__.py,sha256=wCvOdwu0J6X2OQr3j_LgE5rTFYtVK7gPqDD382qOkVs,369
|
2
|
-
varname/core.py,sha256=nntOVpiavXP0EXijTNF6xIe4mxvz_FRpBjrL9z_JHJ0,19311
|
3
|
-
varname/helpers.py,sha256=TUeohi5yCSleXA2betkulAG2_23jsoM_vohHuCEVPQI,6679
|
4
|
-
varname/ignore.py,sha256=-VC3oqag44y2UlAw0ErYKHotx616qJL3Sjb_5y7Tw1c,14400
|
5
|
-
varname/utils.py,sha256=f0dDRYfOeebdDvEwVSQVXNpHC1sB3-1qNE8mICg1IcE,19296
|
6
|
-
varname-0.12.1.dist-info/LICENSE,sha256=3bS8O2tMbBPz8rWmZBAOzkHQjcK-b7KwFHyyghEZ-Ak,1063
|
7
|
-
varname-0.12.1.dist-info/METADATA,sha256=IrxRHVvT9g4Xtq0w_1tEV9o3_rCeeW1KqkU0dAsg3s4,12074
|
8
|
-
varname-0.12.1.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
9
|
-
varname-0.12.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|