pwwang/python-varname

Is there a way to get the argname with exec or eval

vishalvora opened this issue · 4 comments

from varname import argname

class elements:

    def __init__(self):
        self.app = []

    def sidebar(self):
        c = elements()
        self.app.append(c)
        return c

    def button(self, name):
        self.app.append({"type":"button", "name":argname("name")})


ds = elements()
exec("ds.button('test button')")

Error:

\Lib\site-packages\varname\core.py", line 451, in argname
    raise VarnameRetrievingError(
varname.utils.VarnameRetrievingError: Cannot retrieve the node where the function is called.
pwwang commented

Source code is not available at runtime so the node cannot be retrieved.

See: https://github.com/pwwang/python-varname#reliability-and-limitations
and https://stackoverflow.com/a/59364138/5088165

You can trick exec to provide source code at runtime:

In [1]: from varname import argname
   ...: 
   ...: class elements:
   ...: 
   ...:     def __init__(self):
   ...:         self.app = []
   ...: 
   ...:     def sidebar(self):
   ...:         c = elements()
   ...:         self.app.append(c)
   ...:         return c
   ...: 
   ...:     def button(self, name):
   ...:         self.app.append({"type":"button", "name":argname("name")})
   ...: 
   ...: 
   ...: ds = elements()
   ...: 
   ...: from pathlib import Path
   ...: code = "ds.button('test button')"
   ...: sourcefile = "/tmp/mycode.py"
   ...: Path(sourcefile).write_text(code)
   ...: compiled = compile(code, sourcefile, mode="exec")
   ...: exec(compiled)

In [2]: ds.app
Out[2]: [{'type': 'button', 'name': "'test button'"}]

It worked! Thank you so much.

pwwang commented

Now with v0.12.2, you can use exec_code() instead of exec(), so that source code is visible at runtime to varname.

In [1]: from varname import argname
   ...: from varname.helpers import exec_code
   ...: 
   ...: class elements:
   ...:     def __init__(self):
   ...:         self.app = []
   ...:     def sidebar(self):
   ...:         c = elements()
   ...:         self.app.append(c)
   ...:         return c
   ...:     def button(self, name):
   ...:         self.app.append({"type":"button", "name":argname("name", func=self.button)})
   ...: 
   ...: ds = elements()
   ...: 
   ...: code = "ds.button('test button')"
   ...: exec_code(code)
   ...: ds.app
Out[1]: [{'type': 'button', 'name': "'test button'"}]

This is really great 👍