diff options
| author | CoprDistGit <infra@openeuler.org> | 2023-04-11 08:00:41 +0000 |
|---|---|---|
| committer | CoprDistGit <infra@openeuler.org> | 2023-04-11 08:00:41 +0000 |
| commit | b7661f0effe69eca253fc9a252a97766fcbb4f3e (patch) | |
| tree | 04d74af5ddbbb1d42a0c7164bfe120d9aaae54ad | |
| parent | d9b7ce71b68da835ba759b3603b04cb57cf5d169 (diff) | |
automatic import of python-varname
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-varname.spec | 1320 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 1322 insertions, 0 deletions
@@ -0,0 +1 @@ +/varname-0.11.0.tar.gz diff --git a/python-varname.spec b/python-varname.spec new file mode 100644 index 0000000..9ceac1d --- /dev/null +++ b/python-varname.spec @@ -0,0 +1,1320 @@ +%global _empty_manifest_terminate_build 0 +Name: python-varname +Version: 0.11.0 +Release: 1 +Summary: Dark magics about variable names in python. +License: MIT +URL: https://github.com/pwwang/python-varname +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/a1/d8/c07c3f2302b4b039439701d0781cd0265ad3127e141da9dbc3f6dc8323d5/varname-0.11.0.tar.gz +BuildArch: noarch + +Requires: python3-executing +Requires: python3-asttokens +Requires: python3-pure_eval + +%description +![varname][7] + +[![Pypi][3]][4] [![Github][5]][6] [![PythonVers][8]][4] ![Building][10] +[![Docs and API][9]][15] [![Codacy][12]][13] [![Codacy coverage][14]][13] +![Downloads][17] + +Dark magics about variable names in python + +[CHANGELOG][16] | [API][15] | [Playground][11] | :fire: [StackOverflow answer][20] + +## Installation + +```shell +pip install -U varname +``` + +Note if you use `python < 3.8`, install `varname < 0.11` + +## Features + +- Core features: + + - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`. + - Retrieving variable names directly, using `nameof` + - Detecting next immediate attribute name, using `will` + - Fetching argument names/sources passed to a function using `argname` + +- Other helper APIs (built based on core features): + + - A value wrapper to store the variable name that a value is assigned to, using `Wrapper` + - A decorator to register `__varname__` to functions/classes, using `register` + - A `debug` function to print variables with their names and values + +## Credits + +Thanks goes to these awesome people/projects: + +<table> + <tr> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/alexmojaki/executing"> + <img src="https://ui-avatars.com/api/?color=3333ff&background=ffffff&bold=true&name=e&size=400" width="50px;" alt=""/> + <br /><sub><b>executing</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/alexmojaki"> + <img src="https://avatars0.githubusercontent.com/u/3627481?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@alexmojaki</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/breuleux"> + <img src="https://avatars.githubusercontent.com/u/599820?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@breuleux</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/ElCuboNegro"> + <img src="https://avatars.githubusercontent.com/u/5524219?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@ElCuboNegro</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/thewchan"> + <img src="https://avatars.githubusercontent.com/u/49702524?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@thewchan</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/LawsOfSympathy"> + <img src="https://avatars.githubusercontent.com/u/96355982?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@LawsOfSympathy</b></sub> + </a> + </td> + </tr> +</table> + +Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this project. + +## Usage + +### Retrieving the variable names using `varname(...)` + +- From inside a function + + ```python + from varname import varname + def function(): + return varname() + + func = function() # func == 'func' + ``` + + When there are intermediate frames: + + ```python + def wrapped(): + return function() + + def function(): + # retrieve the variable name at the 2nd frame from this one + return varname(frame=2) + + func = wrapped() # func == 'func' + ``` + + Or use `ignore` to ignore the wrapped frame: + + ```python + def wrapped(): + return function() + + def function(): + return varname(ignore=wrapped) + + func = wrapped() # func == 'func' + ``` + + Calls from standard libraries are ignored by default: + + ```python + import asyncio + + async def function(): + return varname() + + func = asyncio.run(function()) # func == 'func' + ``` + + Use `strict` to control whether the call should be assigned to + the variable directly: + + ```python + def function(strict): + return varname(strict=strict) + + func = function(True) # OK, direct assignment, func == 'func' + + func = [function(True)] # Not a direct assignment, raises ImproperUseError + func = [function(False)] # OK, func == ['func'] + + func = function(False), function(False) # OK, func = ('func', 'func') + ``` + +- Retrieving name of a class instance + + ```python + class Foo: + def __init__(self): + self.id = varname() + + def copy(self): + # also able to fetch inside a method call + copied = Foo() # copied.id == 'copied' + copied.id = varname() # assign id to whatever variable name + return copied + + foo = Foo() # foo.id == 'foo' + + foo2 = foo.copy() # foo2.id == 'foo2' + ``` + +- Multiple variables on Left-hand side + + ```python + # since v0.5.4 + def func(): + return varname(multi_vars=True) + + a = func() # a == ('a',) + a, b = func() # (a, b) == ('a', 'b') + [a, b] = func() # (a, b) == ('a', 'b') + + # hierarchy is also possible + a, (b, c) = func() # (a, b, c) == ('a', 'b', 'c') + ``` + +- Some unusual use + + ```python + def function(**kwargs): + return varname(strict=False) + + func = func1 = function() # func == func1 == 'func1' + # if varname < 0.8: func == func1 == 'func' + # a warning will be shown + # since you may not want func to be 'func1' + + x = function(y = function()) # x == 'x' + + # get part of the name + func_abc = function()[-3:] # func_abc == 'abc' + + # function alias supported now + function2 = function + func = function2() # func == 'func' + + a = lambda: 0 + a.b = function() # a.b == 'b' + ``` + +### The decorator way to register `__varname__` to functions/classes + +- Registering `__varname__` to functions + + ```python + from varname.helpers import register + + @register + def function(): + return __varname__ + + func = function() # func == 'func' + ``` + + ```python + # arguments also allowed (frame, ignore and raise_exc) + @register(frame=2) + def function(): + return __varname__ + + def wrapped(): + return function() + + func = wrapped() # func == 'func' + ``` + +- Registering `__varname__` as a class property + + ```python + @register + class Foo: + ... + + foo = Foo() + # foo.__varname__ == 'foo' + ``` + +### Getting variable names directly using `nameof` + +```python +from varname import varname, nameof + +a = 1 +nameof(a) # 'a' + +b = 2 +nameof(a, b) # ('a', 'b') + +def func(): + return varname() + '_suffix' + +f = func() # f == 'f_suffix' +nameof(f) # 'f' + +# get full names of (chained) attribute calls +func.a = func +nameof(func.a, vars_only=False) # 'func.a' + +func.a.b = 1 +nameof(func.a.b, vars_only=False) # 'func.a.b' +``` + +### Detecting next immediate attribute name + +```python +from varname import will +class AwesomeClass: + def __init__(self): + self.will = None + + def permit(self): + self.will = will(raise_exc=False) + if self.will == 'do': + # let self handle do + return self + raise AttributeError('Should do something with AwesomeClass object') + + def do(self): + if self.will != 'do': + raise AttributeError("You don't have permission to do") + return 'I am doing!' + +awesome = AwesomeClass() +awesome.do() # AttributeError: You don't have permission to do +awesome.permit() # AttributeError: Should do something with AwesomeClass object +awesome.permit().do() == 'I am doing!' +``` + +### Fetching argument names/sources using `argname` + +```python +from varname import argname + +def func(a, b=1): + print(argname('a')) + +x = y = z = 2 +func(x) # prints: x + + +def func2(a, b=1): + print(argname('a', 'b')) +func2(y, b=x) # prints: ('y', 'x') + + +# allow expressions +def func3(a, b=1): + print(argname('a', 'b', vars_only=False)) +func3(x+y, y+x) # prints: ('x+y', 'y+x') + + +# positional and keyword arguments +def func4(*args, **kwargs): + print(argname('args[1]', 'kwargs[c]')) +func4(y, x, c=z) # prints: ('x', 'z') + + +# As of 0.9.0 (see: https://pwwang.github.io/python-varname/CHANGELOG/#v090) +# Can also fetch the source of the argument for +# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc. +class Foo: + def __setattr__(self, name, value): + print(argname("name", "value")) + +Foo().a = 1 # prints: ("'a'", '1') + +``` + +### Value wrapper + +```python +from varname.helpers import Wrapper + +foo = Wrapper(True) +# foo.name == 'foo' +# foo.value == True +bar = Wrapper(False) +# bar.name == 'bar' +# bar.value == False + +def values_to_dict(*args): + return {val.name: val.value for val in args} + +mydict = values_to_dict(foo, bar) +# {'foo': True, 'bar': False} +``` + +### Debugging with `debug` + +```python +from varname.helpers import debug + +a = 'value' +b = ['val'] +debug(a) +# "DEBUG: a='value'\n" +debug(b) +# "DEBUG: b=['val']\n" +debug(a, b) +# "DEBUG: a='value'\nDEBUG: b=['val']\n" +debug(a, b, merge=True) +# "DEBUG: a='value', b=['val']\n" +debug(a, repr=False, prefix='') +# 'a=value\n' +# also debug an expression +debug(a+a) +# "DEBUG: a+a='valuevalue'\n" +# If you want to disable it: +debug(a+a, vars_only=True) # ImproperUseError +``` + +## Reliability and limitations + +`varname` is all depending on `executing` package to look for the node. +The node `executing` detects is ensured to be the correct one (see [this][19]). + +It partially works with environments where other AST magics apply, including +`pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither +`executing` nor `varname` is 100% working with those environments. Use +it at your own risk. + +For example: + +- This will not work with `pytest`: + + ```python + a = 1 + assert nameof(a) == 'a' # pytest manipulated the ast here + + # do this instead + name_a = nameof(a) + assert name_a == 'a' + ``` + +[1]: https://github.com/pwwang/python-varname +[2]: https://github.com/HanyuuLu +[3]: https://img.shields.io/pypi/v/varname?style=flat-square +[4]: https://pypi.org/project/varname/ +[5]: https://img.shields.io/github/tag/pwwang/python-varname?style=flat-square +[6]: https://github.com/pwwang/python-varname +[7]: logo.png +[8]: https://img.shields.io/pypi/pyversions/varname?style=flat-square +[9]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/docs.yml?branch=master +[10]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/build.yml?branch=master +[11]: https://mybinder.org/v2/gh/pwwang/python-varname/dev?filepath=playground%2Fplayground.ipynb +[12]: https://img.shields.io/codacy/grade/6fdb19c845f74c5c92056e88d44154f7?style=flat-square +[13]: https://app.codacy.com/gh/pwwang/python-varname/dashboard +[14]: https://img.shields.io/codacy/coverage/6fdb19c845f74c5c92056e88d44154f7?style=flat-square +[15]: https://pwwang.github.io/python-varname/api/varname +[16]: https://pwwang.github.io/python-varname/CHANGELOG/ +[17]: https://img.shields.io/pypi/dm/varname?style=flat-square +[19]: https://github.com/alexmojaki/executing#is-it-reliable +[20]: https://stackoverflow.com/a/59364138/5088165 + + +%package -n python3-varname +Summary: Dark magics about variable names in python. +Provides: python-varname +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-varname +![varname][7] + +[![Pypi][3]][4] [![Github][5]][6] [![PythonVers][8]][4] ![Building][10] +[![Docs and API][9]][15] [![Codacy][12]][13] [![Codacy coverage][14]][13] +![Downloads][17] + +Dark magics about variable names in python + +[CHANGELOG][16] | [API][15] | [Playground][11] | :fire: [StackOverflow answer][20] + +## Installation + +```shell +pip install -U varname +``` + +Note if you use `python < 3.8`, install `varname < 0.11` + +## Features + +- Core features: + + - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`. + - Retrieving variable names directly, using `nameof` + - Detecting next immediate attribute name, using `will` + - Fetching argument names/sources passed to a function using `argname` + +- Other helper APIs (built based on core features): + + - A value wrapper to store the variable name that a value is assigned to, using `Wrapper` + - A decorator to register `__varname__` to functions/classes, using `register` + - A `debug` function to print variables with their names and values + +## Credits + +Thanks goes to these awesome people/projects: + +<table> + <tr> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/alexmojaki/executing"> + <img src="https://ui-avatars.com/api/?color=3333ff&background=ffffff&bold=true&name=e&size=400" width="50px;" alt=""/> + <br /><sub><b>executing</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/alexmojaki"> + <img src="https://avatars0.githubusercontent.com/u/3627481?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@alexmojaki</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/breuleux"> + <img src="https://avatars.githubusercontent.com/u/599820?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@breuleux</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/ElCuboNegro"> + <img src="https://avatars.githubusercontent.com/u/5524219?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@ElCuboNegro</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/thewchan"> + <img src="https://avatars.githubusercontent.com/u/49702524?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@thewchan</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/LawsOfSympathy"> + <img src="https://avatars.githubusercontent.com/u/96355982?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@LawsOfSympathy</b></sub> + </a> + </td> + </tr> +</table> + +Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this project. + +## Usage + +### Retrieving the variable names using `varname(...)` + +- From inside a function + + ```python + from varname import varname + def function(): + return varname() + + func = function() # func == 'func' + ``` + + When there are intermediate frames: + + ```python + def wrapped(): + return function() + + def function(): + # retrieve the variable name at the 2nd frame from this one + return varname(frame=2) + + func = wrapped() # func == 'func' + ``` + + Or use `ignore` to ignore the wrapped frame: + + ```python + def wrapped(): + return function() + + def function(): + return varname(ignore=wrapped) + + func = wrapped() # func == 'func' + ``` + + Calls from standard libraries are ignored by default: + + ```python + import asyncio + + async def function(): + return varname() + + func = asyncio.run(function()) # func == 'func' + ``` + + Use `strict` to control whether the call should be assigned to + the variable directly: + + ```python + def function(strict): + return varname(strict=strict) + + func = function(True) # OK, direct assignment, func == 'func' + + func = [function(True)] # Not a direct assignment, raises ImproperUseError + func = [function(False)] # OK, func == ['func'] + + func = function(False), function(False) # OK, func = ('func', 'func') + ``` + +- Retrieving name of a class instance + + ```python + class Foo: + def __init__(self): + self.id = varname() + + def copy(self): + # also able to fetch inside a method call + copied = Foo() # copied.id == 'copied' + copied.id = varname() # assign id to whatever variable name + return copied + + foo = Foo() # foo.id == 'foo' + + foo2 = foo.copy() # foo2.id == 'foo2' + ``` + +- Multiple variables on Left-hand side + + ```python + # since v0.5.4 + def func(): + return varname(multi_vars=True) + + a = func() # a == ('a',) + a, b = func() # (a, b) == ('a', 'b') + [a, b] = func() # (a, b) == ('a', 'b') + + # hierarchy is also possible + a, (b, c) = func() # (a, b, c) == ('a', 'b', 'c') + ``` + +- Some unusual use + + ```python + def function(**kwargs): + return varname(strict=False) + + func = func1 = function() # func == func1 == 'func1' + # if varname < 0.8: func == func1 == 'func' + # a warning will be shown + # since you may not want func to be 'func1' + + x = function(y = function()) # x == 'x' + + # get part of the name + func_abc = function()[-3:] # func_abc == 'abc' + + # function alias supported now + function2 = function + func = function2() # func == 'func' + + a = lambda: 0 + a.b = function() # a.b == 'b' + ``` + +### The decorator way to register `__varname__` to functions/classes + +- Registering `__varname__` to functions + + ```python + from varname.helpers import register + + @register + def function(): + return __varname__ + + func = function() # func == 'func' + ``` + + ```python + # arguments also allowed (frame, ignore and raise_exc) + @register(frame=2) + def function(): + return __varname__ + + def wrapped(): + return function() + + func = wrapped() # func == 'func' + ``` + +- Registering `__varname__` as a class property + + ```python + @register + class Foo: + ... + + foo = Foo() + # foo.__varname__ == 'foo' + ``` + +### Getting variable names directly using `nameof` + +```python +from varname import varname, nameof + +a = 1 +nameof(a) # 'a' + +b = 2 +nameof(a, b) # ('a', 'b') + +def func(): + return varname() + '_suffix' + +f = func() # f == 'f_suffix' +nameof(f) # 'f' + +# get full names of (chained) attribute calls +func.a = func +nameof(func.a, vars_only=False) # 'func.a' + +func.a.b = 1 +nameof(func.a.b, vars_only=False) # 'func.a.b' +``` + +### Detecting next immediate attribute name + +```python +from varname import will +class AwesomeClass: + def __init__(self): + self.will = None + + def permit(self): + self.will = will(raise_exc=False) + if self.will == 'do': + # let self handle do + return self + raise AttributeError('Should do something with AwesomeClass object') + + def do(self): + if self.will != 'do': + raise AttributeError("You don't have permission to do") + return 'I am doing!' + +awesome = AwesomeClass() +awesome.do() # AttributeError: You don't have permission to do +awesome.permit() # AttributeError: Should do something with AwesomeClass object +awesome.permit().do() == 'I am doing!' +``` + +### Fetching argument names/sources using `argname` + +```python +from varname import argname + +def func(a, b=1): + print(argname('a')) + +x = y = z = 2 +func(x) # prints: x + + +def func2(a, b=1): + print(argname('a', 'b')) +func2(y, b=x) # prints: ('y', 'x') + + +# allow expressions +def func3(a, b=1): + print(argname('a', 'b', vars_only=False)) +func3(x+y, y+x) # prints: ('x+y', 'y+x') + + +# positional and keyword arguments +def func4(*args, **kwargs): + print(argname('args[1]', 'kwargs[c]')) +func4(y, x, c=z) # prints: ('x', 'z') + + +# As of 0.9.0 (see: https://pwwang.github.io/python-varname/CHANGELOG/#v090) +# Can also fetch the source of the argument for +# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc. +class Foo: + def __setattr__(self, name, value): + print(argname("name", "value")) + +Foo().a = 1 # prints: ("'a'", '1') + +``` + +### Value wrapper + +```python +from varname.helpers import Wrapper + +foo = Wrapper(True) +# foo.name == 'foo' +# foo.value == True +bar = Wrapper(False) +# bar.name == 'bar' +# bar.value == False + +def values_to_dict(*args): + return {val.name: val.value for val in args} + +mydict = values_to_dict(foo, bar) +# {'foo': True, 'bar': False} +``` + +### Debugging with `debug` + +```python +from varname.helpers import debug + +a = 'value' +b = ['val'] +debug(a) +# "DEBUG: a='value'\n" +debug(b) +# "DEBUG: b=['val']\n" +debug(a, b) +# "DEBUG: a='value'\nDEBUG: b=['val']\n" +debug(a, b, merge=True) +# "DEBUG: a='value', b=['val']\n" +debug(a, repr=False, prefix='') +# 'a=value\n' +# also debug an expression +debug(a+a) +# "DEBUG: a+a='valuevalue'\n" +# If you want to disable it: +debug(a+a, vars_only=True) # ImproperUseError +``` + +## Reliability and limitations + +`varname` is all depending on `executing` package to look for the node. +The node `executing` detects is ensured to be the correct one (see [this][19]). + +It partially works with environments where other AST magics apply, including +`pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither +`executing` nor `varname` is 100% working with those environments. Use +it at your own risk. + +For example: + +- This will not work with `pytest`: + + ```python + a = 1 + assert nameof(a) == 'a' # pytest manipulated the ast here + + # do this instead + name_a = nameof(a) + assert name_a == 'a' + ``` + +[1]: https://github.com/pwwang/python-varname +[2]: https://github.com/HanyuuLu +[3]: https://img.shields.io/pypi/v/varname?style=flat-square +[4]: https://pypi.org/project/varname/ +[5]: https://img.shields.io/github/tag/pwwang/python-varname?style=flat-square +[6]: https://github.com/pwwang/python-varname +[7]: logo.png +[8]: https://img.shields.io/pypi/pyversions/varname?style=flat-square +[9]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/docs.yml?branch=master +[10]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/build.yml?branch=master +[11]: https://mybinder.org/v2/gh/pwwang/python-varname/dev?filepath=playground%2Fplayground.ipynb +[12]: https://img.shields.io/codacy/grade/6fdb19c845f74c5c92056e88d44154f7?style=flat-square +[13]: https://app.codacy.com/gh/pwwang/python-varname/dashboard +[14]: https://img.shields.io/codacy/coverage/6fdb19c845f74c5c92056e88d44154f7?style=flat-square +[15]: https://pwwang.github.io/python-varname/api/varname +[16]: https://pwwang.github.io/python-varname/CHANGELOG/ +[17]: https://img.shields.io/pypi/dm/varname?style=flat-square +[19]: https://github.com/alexmojaki/executing#is-it-reliable +[20]: https://stackoverflow.com/a/59364138/5088165 + + +%package help +Summary: Development documents and examples for varname +Provides: python3-varname-doc +%description help +![varname][7] + +[![Pypi][3]][4] [![Github][5]][6] [![PythonVers][8]][4] ![Building][10] +[![Docs and API][9]][15] [![Codacy][12]][13] [![Codacy coverage][14]][13] +![Downloads][17] + +Dark magics about variable names in python + +[CHANGELOG][16] | [API][15] | [Playground][11] | :fire: [StackOverflow answer][20] + +## Installation + +```shell +pip install -U varname +``` + +Note if you use `python < 3.8`, install `varname < 0.11` + +## Features + +- Core features: + + - Retrieving names of variables a function/class call is assigned to from inside it, using `varname`. + - Retrieving variable names directly, using `nameof` + - Detecting next immediate attribute name, using `will` + - Fetching argument names/sources passed to a function using `argname` + +- Other helper APIs (built based on core features): + + - A value wrapper to store the variable name that a value is assigned to, using `Wrapper` + - A decorator to register `__varname__` to functions/classes, using `register` + - A `debug` function to print variables with their names and values + +## Credits + +Thanks goes to these awesome people/projects: + +<table> + <tr> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/alexmojaki/executing"> + <img src="https://ui-avatars.com/api/?color=3333ff&background=ffffff&bold=true&name=e&size=400" width="50px;" alt=""/> + <br /><sub><b>executing</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/alexmojaki"> + <img src="https://avatars0.githubusercontent.com/u/3627481?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@alexmojaki</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/breuleux"> + <img src="https://avatars.githubusercontent.com/u/599820?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@breuleux</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/ElCuboNegro"> + <img src="https://avatars.githubusercontent.com/u/5524219?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@ElCuboNegro</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/thewchan"> + <img src="https://avatars.githubusercontent.com/u/49702524?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@thewchan</b></sub> + </a> + </td> + <td align="center" style="min-width: 75px"> + <a href="https://github.com/LawsOfSympathy"> + <img src="https://avatars.githubusercontent.com/u/96355982?s=400&v=4" width="50px;" alt=""/> + <br /><sub><b>@LawsOfSympathy</b></sub> + </a> + </td> + </tr> +</table> + +Special thanks to [@HanyuuLu][2] to give up the name `varname` in pypi for this project. + +## Usage + +### Retrieving the variable names using `varname(...)` + +- From inside a function + + ```python + from varname import varname + def function(): + return varname() + + func = function() # func == 'func' + ``` + + When there are intermediate frames: + + ```python + def wrapped(): + return function() + + def function(): + # retrieve the variable name at the 2nd frame from this one + return varname(frame=2) + + func = wrapped() # func == 'func' + ``` + + Or use `ignore` to ignore the wrapped frame: + + ```python + def wrapped(): + return function() + + def function(): + return varname(ignore=wrapped) + + func = wrapped() # func == 'func' + ``` + + Calls from standard libraries are ignored by default: + + ```python + import asyncio + + async def function(): + return varname() + + func = asyncio.run(function()) # func == 'func' + ``` + + Use `strict` to control whether the call should be assigned to + the variable directly: + + ```python + def function(strict): + return varname(strict=strict) + + func = function(True) # OK, direct assignment, func == 'func' + + func = [function(True)] # Not a direct assignment, raises ImproperUseError + func = [function(False)] # OK, func == ['func'] + + func = function(False), function(False) # OK, func = ('func', 'func') + ``` + +- Retrieving name of a class instance + + ```python + class Foo: + def __init__(self): + self.id = varname() + + def copy(self): + # also able to fetch inside a method call + copied = Foo() # copied.id == 'copied' + copied.id = varname() # assign id to whatever variable name + return copied + + foo = Foo() # foo.id == 'foo' + + foo2 = foo.copy() # foo2.id == 'foo2' + ``` + +- Multiple variables on Left-hand side + + ```python + # since v0.5.4 + def func(): + return varname(multi_vars=True) + + a = func() # a == ('a',) + a, b = func() # (a, b) == ('a', 'b') + [a, b] = func() # (a, b) == ('a', 'b') + + # hierarchy is also possible + a, (b, c) = func() # (a, b, c) == ('a', 'b', 'c') + ``` + +- Some unusual use + + ```python + def function(**kwargs): + return varname(strict=False) + + func = func1 = function() # func == func1 == 'func1' + # if varname < 0.8: func == func1 == 'func' + # a warning will be shown + # since you may not want func to be 'func1' + + x = function(y = function()) # x == 'x' + + # get part of the name + func_abc = function()[-3:] # func_abc == 'abc' + + # function alias supported now + function2 = function + func = function2() # func == 'func' + + a = lambda: 0 + a.b = function() # a.b == 'b' + ``` + +### The decorator way to register `__varname__` to functions/classes + +- Registering `__varname__` to functions + + ```python + from varname.helpers import register + + @register + def function(): + return __varname__ + + func = function() # func == 'func' + ``` + + ```python + # arguments also allowed (frame, ignore and raise_exc) + @register(frame=2) + def function(): + return __varname__ + + def wrapped(): + return function() + + func = wrapped() # func == 'func' + ``` + +- Registering `__varname__` as a class property + + ```python + @register + class Foo: + ... + + foo = Foo() + # foo.__varname__ == 'foo' + ``` + +### Getting variable names directly using `nameof` + +```python +from varname import varname, nameof + +a = 1 +nameof(a) # 'a' + +b = 2 +nameof(a, b) # ('a', 'b') + +def func(): + return varname() + '_suffix' + +f = func() # f == 'f_suffix' +nameof(f) # 'f' + +# get full names of (chained) attribute calls +func.a = func +nameof(func.a, vars_only=False) # 'func.a' + +func.a.b = 1 +nameof(func.a.b, vars_only=False) # 'func.a.b' +``` + +### Detecting next immediate attribute name + +```python +from varname import will +class AwesomeClass: + def __init__(self): + self.will = None + + def permit(self): + self.will = will(raise_exc=False) + if self.will == 'do': + # let self handle do + return self + raise AttributeError('Should do something with AwesomeClass object') + + def do(self): + if self.will != 'do': + raise AttributeError("You don't have permission to do") + return 'I am doing!' + +awesome = AwesomeClass() +awesome.do() # AttributeError: You don't have permission to do +awesome.permit() # AttributeError: Should do something with AwesomeClass object +awesome.permit().do() == 'I am doing!' +``` + +### Fetching argument names/sources using `argname` + +```python +from varname import argname + +def func(a, b=1): + print(argname('a')) + +x = y = z = 2 +func(x) # prints: x + + +def func2(a, b=1): + print(argname('a', 'b')) +func2(y, b=x) # prints: ('y', 'x') + + +# allow expressions +def func3(a, b=1): + print(argname('a', 'b', vars_only=False)) +func3(x+y, y+x) # prints: ('x+y', 'y+x') + + +# positional and keyword arguments +def func4(*args, **kwargs): + print(argname('args[1]', 'kwargs[c]')) +func4(y, x, c=z) # prints: ('x', 'z') + + +# As of 0.9.0 (see: https://pwwang.github.io/python-varname/CHANGELOG/#v090) +# Can also fetch the source of the argument for +# __getattr__/__getitem__/__setattr/__setitem__/__add__/__lt__, etc. +class Foo: + def __setattr__(self, name, value): + print(argname("name", "value")) + +Foo().a = 1 # prints: ("'a'", '1') + +``` + +### Value wrapper + +```python +from varname.helpers import Wrapper + +foo = Wrapper(True) +# foo.name == 'foo' +# foo.value == True +bar = Wrapper(False) +# bar.name == 'bar' +# bar.value == False + +def values_to_dict(*args): + return {val.name: val.value for val in args} + +mydict = values_to_dict(foo, bar) +# {'foo': True, 'bar': False} +``` + +### Debugging with `debug` + +```python +from varname.helpers import debug + +a = 'value' +b = ['val'] +debug(a) +# "DEBUG: a='value'\n" +debug(b) +# "DEBUG: b=['val']\n" +debug(a, b) +# "DEBUG: a='value'\nDEBUG: b=['val']\n" +debug(a, b, merge=True) +# "DEBUG: a='value', b=['val']\n" +debug(a, repr=False, prefix='') +# 'a=value\n' +# also debug an expression +debug(a+a) +# "DEBUG: a+a='valuevalue'\n" +# If you want to disable it: +debug(a+a, vars_only=True) # ImproperUseError +``` + +## Reliability and limitations + +`varname` is all depending on `executing` package to look for the node. +The node `executing` detects is ensured to be the correct one (see [this][19]). + +It partially works with environments where other AST magics apply, including +`pytest`, `ipython`, `macropy`, `birdseye`, `reticulate` with `R`, etc. Neither +`executing` nor `varname` is 100% working with those environments. Use +it at your own risk. + +For example: + +- This will not work with `pytest`: + + ```python + a = 1 + assert nameof(a) == 'a' # pytest manipulated the ast here + + # do this instead + name_a = nameof(a) + assert name_a == 'a' + ``` + +[1]: https://github.com/pwwang/python-varname +[2]: https://github.com/HanyuuLu +[3]: https://img.shields.io/pypi/v/varname?style=flat-square +[4]: https://pypi.org/project/varname/ +[5]: https://img.shields.io/github/tag/pwwang/python-varname?style=flat-square +[6]: https://github.com/pwwang/python-varname +[7]: logo.png +[8]: https://img.shields.io/pypi/pyversions/varname?style=flat-square +[9]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/docs.yml?branch=master +[10]: https://img.shields.io/github/actions/workflow/status/pwwang/python-varname/build.yml?branch=master +[11]: https://mybinder.org/v2/gh/pwwang/python-varname/dev?filepath=playground%2Fplayground.ipynb +[12]: https://img.shields.io/codacy/grade/6fdb19c845f74c5c92056e88d44154f7?style=flat-square +[13]: https://app.codacy.com/gh/pwwang/python-varname/dashboard +[14]: https://img.shields.io/codacy/coverage/6fdb19c845f74c5c92056e88d44154f7?style=flat-square +[15]: https://pwwang.github.io/python-varname/api/varname +[16]: https://pwwang.github.io/python-varname/CHANGELOG/ +[17]: https://img.shields.io/pypi/dm/varname?style=flat-square +[19]: https://github.com/alexmojaki/executing#is-it-reliable +[20]: https://stackoverflow.com/a/59364138/5088165 + + +%prep +%autosetup -n varname-0.11.0 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-varname -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Tue Apr 11 2023 Python_Bot <Python_Bot@openeuler.org> - 0.11.0-1 +- Package Spec generated @@ -0,0 +1 @@ +15188542a66d8c74f0833f772fc8459f varname-0.11.0.tar.gz |
