Skip to content

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

Open
@pwwang

Description

@pwwang

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:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions