Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VarnameRetrievingError: Cannot retrieve the node where the function is called. #107

Open
pwwang opened this issue Mar 22, 2024 · 0 comments

Comments

@pwwang
Copy link
Owner

pwwang commented Mar 22, 2024

If you see this warning and the errors caused by it, please ensure you are running your code in the environment where the source code is available at runtime.

Typical environment where the source code is not available at runtime:

  • Raw Python REPL (type python from command line and run your code there)
  • exec()

If you want to use a Python REPL to run your code, ipython, bpython and jupyter notebook are recommended.

If you can't avoid using exec(), use exec_code() from varname.helpers instead.

What if I want to use exec() anyway? The idea is to tell exec where to retrieve the source code. See how exec_code() is implemented:

def exec_code(
code: str,
globals: Dict[str, Any] = None,
locals: Dict[str, Any] = None,
/,
sourcefile: PathLike | str = None,
frame: int = 1,
ignore: IgnoreType = None,
**kwargs: Any,
) -> None:
"""Execute code where source code is visible at runtime.
This function is useful when you want to execute some code, where you want to
retrieve the AST node of the code at runtime. This function will create a
temporary file and write the code into it, then execute the code in the
file.
Examples:
>>> from varname import varname
>>> def func(): return varname()
>>> exec('var = func()') # VarnameRetrievingError:
>>> # Unable to retrieve the ast node.
>>> from varname.helpers import code_exec
>>> code_exec('var = func()') # var == 'var'
Args:
code: The code to execute.
globals: The globals to use.
locals: The locals to use.
sourcefile: The source file to write the code into.
if not given, a temporary file will be used.
This file will be deleted after the code is executed.
frame: The call stack index. You can understand this as the number of
wrappers around this function. This is used to fetch `globals` and
`locals` from where the destination function (include the wrappers
of this function)
is called.
ignore: The intermediate calls to be ignored. See `varname.ignore`
Note that if both `globals` and `locals` are given, `frame` and
`ignore` will be ignored.
**kwargs: The keyword arguments to pass to `exec`.
"""
if sourcefile is None:
import tempfile
with tempfile.NamedTemporaryFile(
mode="w", suffix=".py", delete=False
) as f:
f.write(code)
sourcefile = f.name
else:
sourcefile = str(sourcefile)
with open(sourcefile, "w") as f:
f.write(code)
if globals is None or locals is None:
ignore_list = IgnoreList.create(ignore)
frame_info = ignore_list.get_frame(frame)
if globals is None:
globals = frame_info.f_globals
if locals is None:
locals = frame_info.f_locals
try:
exec(compile(code, sourcefile, "exec"), globals, locals, **kwargs)
finally:
import os
os.remove(sourcefile)

Related:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant