Varname
Varname is a Python library that provides 'dark magics' to retrieve the names of variables, arguments, and expressions at runtime. It's currently at version 0.15.1, offering functions like `varname()`, `nameof()`, and `argname()` to simplify introspection and debugging. The library maintains an active release cadence, with recent updates focusing on improved expression parsing and Python version compatibility.
Common errors
-
ImproperUseError: varname() is used improperly.
cause This error often occurs when `varname()` is called within complex expressions, especially in versions prior to 0.15.1 when used in array/list subscripts or other non-direct assignments.fixUpgrade to `varname>=0.15.1` for better support of complex expressions. If upgrading is not an option, simplify the expression where `varname()` is called, or assign its result to a simple variable first. -
AttributeError: module 'varname' has no attribute 'nameof'
cause This specific error indicates that you are likely using `varname==0.14.0`, where the `nameof` function was temporarily removed after deprecation.fixUpgrade to `varname>=0.15.0` to restore `nameof` functionality, as it was re-introduced in this version. Alternatively, refactor your code to use `varname.argname()` which can often achieve similar results, or use `varname()` if appropriate. -
NameError: name 'my_variable' is not defined (when using varname inside certain loops or comprehensions)
cause `varname` can sometimes struggle to reliably retrieve variable names when they are created dynamically, assigned implicitly within loops (e.g., in a list comprehension or tight loop constructs), or when the assignment context is not a direct variable assignment.fixFor scenarios where `varname.varname()` struggles, consider using `varname.helpers.Wrapper` to explicitly associate a value with its variable name. Example: `from varname.helpers import Wrapper; a = Wrapper(''); mydict = {val.name: val.value for val in [a]}`. -
TypeError: exec_code() got an unexpected keyword argument 'sourcefile'
cause This may occur if `varname.helpers.exec_code()` is called with incorrect arguments or an older signature. The `sourcefile` argument, while present in some internal uses, might not be intended for direct user calls or its position changed.fixEnsure you are passing `code`, `globals` (e.g., `globals().copy()`), `locals` (e.g., `locals().copy()`) and any other specified arguments according to the current `varname` documentation. Avoid passing `sourcefile` unless explicitly required and documented for public API usage.
Warnings
- breaking In `varname` versions 0.13.0 and later, calling `varname()` on an attribute chain like `a.b` will return the full chain `"a.b"` instead of just the root variable name `"a"`.
- deprecated `nameof` was deprecated in version 0.14.0 (warned in 0.13.4), leading to its removal in that version. It was subsequently re-introduced in version 0.15.0.
- gotcha Prior to version 0.15.1, using `varname()` within complex subscript assignments (e.g., `a[x + 1] = func()`) would raise an `ImproperUseError` due to limitations in parsing complex expressions.
- gotcha `varname` relies heavily on AST analysis via the `executing` package, which may not work reliably with environments using other AST manipulation techniques or dynamic code execution like Python's built-in `exec()` function, `macropy`, `birdseye`, or `reticulate`.
Install
-
pip install varname
Imports
- varname
from varname import varname
- nameof
from varname.core import nameof
from varname import nameof
- argname
from varname import argname
- jsobj
from varname.helpers import jsobj
- exec_code
exec(code_string)
from varname.helpers import exec_code
- Wrapper
from varname.helpers import Wrapper
Quickstart
import varname
def func():
# varname() retrieves the name of the variable it's assigned to.
return varname()
x = 0
a = [object] * 5
# Before v0.15.1, this might raise ImproperUseError.
# Now, it correctly prints 'a[x + 1]' (which evaluates to a[1]).
a[x + 1] = func()
print(f"Value at a[1]: {a[1]}")
# Demonstrating other new subscript supports from v0.15.1
b = []
b.append(func())
print(f"Element in b: {b[0]}") # prints 'b.append(func())'
# Using nameof to get an argument's name
def process(my_arg):
return varname.nameof(my_arg)
result = process(x)
print(f"Name of argument 'x': {result}")
# Using argname to get argument names within a function
def greet(name, message):
return varname.argname('name', 'message')
arg_names = greet('Alice', 'Hello')
print(f"Argument names in greet: {arg_names}") # {'name': 'name', 'message': 'message'}