CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-varname

Dark magics about variable names in python

Overall
score

90%

Overview
Eval results
Files

helper-functions.mddocs/

Helper Functions

Utility functions and classes that build upon varname's core functionality to provide convenient patterns for common use cases. These helpers make it easier to integrate varname capabilities into applications.

Capabilities

Variable Name Registration

Decorator to automatically add __varname__ support to classes and functions, enabling them to access their assigned variable names.

def register(
    cls_or_func: type = None,
    frame: int = 1,
    ignore: IgnoreType = None,
    multi_vars: bool = False,
    raise_exc: bool = True,
    strict: bool = True
) -> Union[Type, Callable]:
    """
    A decorator to register __varname__ to a class or function.
    
    Args:
        cls_or_func: The class or function to register. When used as @register
                    without parentheses, this receives the decorated object.
        frame: Nth frame used to retrieve the variable name (same as varname)
        ignore: Frames to be ignored (same as varname)
        multi_vars: Whether allow multiple variables (same as varname)
        raise_exc: Whether to raise exception on failure (same as varname)
        strict: Whether to only return name for direct assignments (same as varname)
        
    Returns:
        The decorated class or function with __varname__ attribute support
        
    Note:
        After decoration, instances/calls will have a __varname__ attribute
        containing the variable name they were assigned to.
    """

Usage Examples

from varname.helpers import register

# Class registration
@register
class DataProcessor:
    def __init__(self, data):
        self.data = data
        print(f"Created {self.__varname__} processor")
        
    def process(self):
        return f"Processing with {self.__varname__}"

# Usage
main_processor = DataProcessor([1, 2, 3])  # Prints: Created main_processor processor
result = main_processor.process()          # Returns: "Processing with main_processor"

# Function registration
@register
def create_connection():
    print(f"Creating connection: {create_connection.__varname__}")
    return f"Connection_{create_connection.__varname__}"

db_conn = create_connection()  # Prints: Creating connection: db_conn
                              # db_conn == "Connection_db_conn"

# With parameters
@register(frame=2, strict=False)
class FlexibleProcessor:
    def __init__(self):
        self.name = self.__varname__

def factory():
    return FlexibleProcessor()

flexible = factory()  # flexible.name == "flexible"

Value Wrapper with Name Storage

A wrapper class that stores both a value and the variable name it was assigned to, useful for debugging and introspection.

class Wrapper:
    """A wrapper with ability to retrieve the variable name."""
    
    def __init__(
        self,
        value: Any,
        frame: int = 1,
        ignore: IgnoreType = None,
        raise_exc: bool = True,
        strict: bool = True
    ):
        """
        Initialize wrapper with value and retrieve variable name.
        
        Args:
            value: The value to be wrapped
            frame: Nth frame used to retrieve variable name (same as varname)
            ignore: Frames to be ignored (same as varname)  
            raise_exc: Whether to raise exception on failure (same as varname)
            strict: Whether to only return name for direct assignments (same as varname)
        """
        
    @property
    def name(self) -> str:
        """The variable name to which the instance is assigned."""
        
    @property  
    def value(self) -> Any:
        """The value this wrapper wraps."""
        
    def __str__(self) -> str:
        """Returns repr(self.value)."""
        
    def __repr__(self) -> str:
        """Returns formatted representation with name and value."""

Usage Examples

from varname.helpers import Wrapper

# Basic wrapper usage
data_wrapper = Wrapper([1, 2, 3, 4])
print(data_wrapper.name)   # "data_wrapper"  
print(data_wrapper.value)  # [1, 2, 3, 4]
print(data_wrapper)        # [1, 2, 3, 4]
print(repr(data_wrapper))  # <Wrapper (data_wrapper): [1, 2, 3, 4]>

# With complex objects
class Config:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

app_config = Wrapper(Config(debug=True, port=8080))
print(f"Config name: {app_config.name}")           # Config name: app_config
print(f"Debug mode: {app_config.value.debug}")     # Debug mode: True

# Multiple wrappers
user_data = Wrapper({"name": "Alice", "age": 30})
system_data = Wrapper({"version": "1.0", "env": "prod"})

wrappers = [user_data, system_data]
for wrapper in wrappers:
    print(f"{wrapper.name}: {wrapper.value}")
# user_data: {'name': 'Alice', 'age': 30}
# system_data: {'version': '1.0', 'env': 'prod'}

Debug Printing with Variable Names

Print variables with their names automatically retrieved, making debugging output more informative.

def debug(
    var,
    *more_vars,
    prefix: str = "DEBUG: ",
    merge: bool = False,
    repr: bool = True,
    sep: str = "=",
    vars_only: bool = False
) -> None:
    """
    Print variable names and values for debugging.
    
    Args:
        var: The variable to print
        *more_vars: Other variables to print
        prefix: Prefix to add to each debug line
        merge: Whether to merge all variables in one line instead of separate lines
        repr: Whether to print values using repr() (True) or str() (False)
        sep: Separator between variable name and value
        vars_only: Whether to only include variables in output (vs expressions)
        
    Note:
        Uses nameof internally to get variable names, so inherits its limitations
        in REPL/exec environments.
    """

Usage Examples

from varname.helpers import debug

# Basic debug printing
x = 42
y = "hello"
debug(x, y)
# DEBUG: x=42
# DEBUG: y='hello'

# Custom formatting
debug(x, y, prefix=">>> ", sep=" -> ", merge=True)
# >>> x -> 42, y -> 'hello'

# With expressions (vars_only=False)
items = [1, 2, 3]  
debug(len(items), items[0], vars_only=False)
# DEBUG: len(items)=3
# DEBUG: items[0]=1

# Complex objects without repr
class Person:
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return f"Person({self.name})"

person = Person("Bob")
debug(person, repr=False)
# DEBUG: person=Person(Bob)

JavaScript-like Object Creation

Create dictionaries using variable names as keys automatically, similar to JavaScript's object shorthand.

def jsobj(
    *args: Any,
    vars_only: bool = True,
    frame: int = 1,
    **kwargs: Any
) -> Dict[str, Any]:
    """
    Create a JavaScript-like object (dict) using variable names as keys.
    
    Args:
        *args: Positional arguments whose names will become keys
        vars_only: Whether to only allow variables as arguments (vs expressions)
        frame: Frame adjustment for name retrieval
        **kwargs: Keyword arguments to include in the resulting dict
        
    Returns:
        Dictionary mapping argument names to their values, plus any kwargs
        
    Note:
        Uses nameof internally to get variable names from positional arguments.
        Keyword arguments are included as-is.
    """

Usage Examples

from varname.helpers import jsobj

# Basic usage
username = "alice"
user_id = 12345
active = True

user = jsobj(username, user_id, active)
# user == {'username': 'alice', 'user_id': 12345, 'active': True}

# With keyword arguments
user = jsobj(username, user_id, role="admin", permissions=["read", "write"])
# user == {
#     'username': 'alice', 
#     'user_id': 12345, 
#     'role': 'admin',
#     'permissions': ['read', 'write']
# }

# Nested objects
server_config = jsobj(
    username,
    user_id,
    database=jsobj(host="localhost", port=5432),
    cache=jsobj(enabled=True, ttl=3600)
)
# server_config == {
#     'username': 'alice',
#     'user_id': 12345,
#     'database': {'host': 'localhost', 'port': 5432},
#     'cache': {'enabled': True, 'ttl': 3600}
# }

# With expressions (vars_only=False)
items = [1, 2, 3]
result = jsobj(len(items), items[0], vars_only=False, total=sum(items))
# result == {'len(items)': 3, 'items[0]': 1, 'total': 6}

Code Execution with Source Visibility

Execute code where the source is visible at runtime, enabling varname functions to work in dynamic execution contexts.

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.
    
    Args:
        code: The code string to execute
        globals: Global namespace for execution (defaults to caller's globals)
        locals: Local namespace for execution (defaults to caller's locals)
        sourcefile: Optional file path to write source code to for visibility
        frame: Frame adjustment for namespace retrieval
        ignore: Frames to ignore when retrieving namespace
        **kwargs: Additional arguments passed to exec()
        
    Note:
        This function makes varname operations work inside exec'd code by
        ensuring the source code is available for AST analysis. Without this,
        exec'd code cannot use varname functions effectively.
    """

Usage Examples

from varname.helpers import exec_code, varname

# Basic code execution with varname support
code = '''
def create_item():
    return varname()

my_item = create_item()
print(f"Created: {my_item}")  # Will print: Created: my_item
'''

exec_code(code)

# With custom globals/locals
local_vars = {'data': [1, 2, 3]}
global_vars = {'varname': varname}

code = '''
def process():
    name = varname()
    return f"Processing {name} with {len(data)} items"

result = process()
'''

exec_code(code, globals=global_vars, locals=local_vars)
print(local_vars['result'])  # Processing result with 3 items

# With source file for debugging
import tempfile
from pathlib import Path

with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
    source_file = f.name

code = '''
from varname.helpers import debug

x = 42
y = "test"
debug(x, y)
'''

exec_code(code, sourcefile=source_file)
# DEBUG: x=42
# DEBUG: y='test'

# Clean up
Path(source_file).unlink()

Integration Patterns

Factory Pattern with Name Awareness

from varname.helpers import register
from varname.helpers import Wrapper

@register
class NamedFactory:
    @classmethod
    def create(cls, *args, **kwargs):
        instance = cls(*args, **kwargs)
        instance._factory_name = cls.__varname__
        return instance

# Automatic name detection in factory
user_factory = NamedFactory.create()
print(user_factory._factory_name)  # "user_factory"

# Combined with Wrapper
class SmartFactory:
    def __init__(self, config):
        self.config = config
        
    def create_component(self):
        return Wrapper({"factory": "smart", "config": self.config})

factory = SmartFactory({"debug": True})
component = factory.create_component()
print(f"Component {component.name} created")  # Component component created

Configuration Management

from varname.helpers import jsobj, debug

def load_config():
    # Database settings
    db_host = "localhost"
    db_port = 5432
    db_name = "myapp"
    
    # Cache settings  
    cache_enabled = True
    cache_ttl = 3600
    
    # Create config using variable names
    config = {
        "database": jsobj(db_host, db_port, db_name),
        "cache": jsobj(cache_enabled, cache_ttl)
    }
    
    # Debug the configuration
    debug(config, prefix="CONFIG: ")
    return config

config = load_config()
# CONFIG: config={'database': {'db_host': 'localhost', ...}, ...}

Install with Tessl CLI

npx tessl i tessl/pypi-varname

docs

advanced-functions.md

config-exceptions.md

core-functions.md

helper-functions.md

index.md

tile.json