0
# Helper Functions
1
2
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.
3
4
## Capabilities
5
6
### Variable Name Registration
7
8
Decorator to automatically add `__varname__` support to classes and functions, enabling them to access their assigned variable names.
9
10
```python { .api }
11
def register(
12
cls_or_func: type = None,
13
frame: int = 1,
14
ignore: IgnoreType = None,
15
multi_vars: bool = False,
16
raise_exc: bool = True,
17
strict: bool = True
18
) -> Union[Type, Callable]:
19
"""
20
A decorator to register __varname__ to a class or function.
21
22
Args:
23
cls_or_func: The class or function to register. When used as @register
24
without parentheses, this receives the decorated object.
25
frame: Nth frame used to retrieve the variable name (same as varname)
26
ignore: Frames to be ignored (same as varname)
27
multi_vars: Whether allow multiple variables (same as varname)
28
raise_exc: Whether to raise exception on failure (same as varname)
29
strict: Whether to only return name for direct assignments (same as varname)
30
31
Returns:
32
The decorated class or function with __varname__ attribute support
33
34
Note:
35
After decoration, instances/calls will have a __varname__ attribute
36
containing the variable name they were assigned to.
37
"""
38
```
39
40
#### Usage Examples
41
42
```python
43
from varname.helpers import register
44
45
# Class registration
46
@register
47
class DataProcessor:
48
def __init__(self, data):
49
self.data = data
50
print(f"Created {self.__varname__} processor")
51
52
def process(self):
53
return f"Processing with {self.__varname__}"
54
55
# Usage
56
main_processor = DataProcessor([1, 2, 3]) # Prints: Created main_processor processor
57
result = main_processor.process() # Returns: "Processing with main_processor"
58
59
# Function registration
60
@register
61
def create_connection():
62
print(f"Creating connection: {create_connection.__varname__}")
63
return f"Connection_{create_connection.__varname__}"
64
65
db_conn = create_connection() # Prints: Creating connection: db_conn
66
# db_conn == "Connection_db_conn"
67
68
# With parameters
69
@register(frame=2, strict=False)
70
class FlexibleProcessor:
71
def __init__(self):
72
self.name = self.__varname__
73
74
def factory():
75
return FlexibleProcessor()
76
77
flexible = factory() # flexible.name == "flexible"
78
```
79
80
### Value Wrapper with Name Storage
81
82
A wrapper class that stores both a value and the variable name it was assigned to, useful for debugging and introspection.
83
84
```python { .api }
85
class Wrapper:
86
"""A wrapper with ability to retrieve the variable name."""
87
88
def __init__(
89
self,
90
value: Any,
91
frame: int = 1,
92
ignore: IgnoreType = None,
93
raise_exc: bool = True,
94
strict: bool = True
95
):
96
"""
97
Initialize wrapper with value and retrieve variable name.
98
99
Args:
100
value: The value to be wrapped
101
frame: Nth frame used to retrieve variable name (same as varname)
102
ignore: Frames to be ignored (same as varname)
103
raise_exc: Whether to raise exception on failure (same as varname)
104
strict: Whether to only return name for direct assignments (same as varname)
105
"""
106
107
@property
108
def name(self) -> str:
109
"""The variable name to which the instance is assigned."""
110
111
@property
112
def value(self) -> Any:
113
"""The value this wrapper wraps."""
114
115
def __str__(self) -> str:
116
"""Returns repr(self.value)."""
117
118
def __repr__(self) -> str:
119
"""Returns formatted representation with name and value."""
120
```
121
122
#### Usage Examples
123
124
```python
125
from varname.helpers import Wrapper
126
127
# Basic wrapper usage
128
data_wrapper = Wrapper([1, 2, 3, 4])
129
print(data_wrapper.name) # "data_wrapper"
130
print(data_wrapper.value) # [1, 2, 3, 4]
131
print(data_wrapper) # [1, 2, 3, 4]
132
print(repr(data_wrapper)) # <Wrapper (data_wrapper): [1, 2, 3, 4]>
133
134
# With complex objects
135
class Config:
136
def __init__(self, **kwargs):
137
self.__dict__.update(kwargs)
138
139
app_config = Wrapper(Config(debug=True, port=8080))
140
print(f"Config name: {app_config.name}") # Config name: app_config
141
print(f"Debug mode: {app_config.value.debug}") # Debug mode: True
142
143
# Multiple wrappers
144
user_data = Wrapper({"name": "Alice", "age": 30})
145
system_data = Wrapper({"version": "1.0", "env": "prod"})
146
147
wrappers = [user_data, system_data]
148
for wrapper in wrappers:
149
print(f"{wrapper.name}: {wrapper.value}")
150
# user_data: {'name': 'Alice', 'age': 30}
151
# system_data: {'version': '1.0', 'env': 'prod'}
152
```
153
154
### Debug Printing with Variable Names
155
156
Print variables with their names automatically retrieved, making debugging output more informative.
157
158
```python { .api }
159
def debug(
160
var,
161
*more_vars,
162
prefix: str = "DEBUG: ",
163
merge: bool = False,
164
repr: bool = True,
165
sep: str = "=",
166
vars_only: bool = False
167
) -> None:
168
"""
169
Print variable names and values for debugging.
170
171
Args:
172
var: The variable to print
173
*more_vars: Other variables to print
174
prefix: Prefix to add to each debug line
175
merge: Whether to merge all variables in one line instead of separate lines
176
repr: Whether to print values using repr() (True) or str() (False)
177
sep: Separator between variable name and value
178
vars_only: Whether to only include variables in output (vs expressions)
179
180
Note:
181
Uses nameof internally to get variable names, so inherits its limitations
182
in REPL/exec environments.
183
"""
184
```
185
186
#### Usage Examples
187
188
```python
189
from varname.helpers import debug
190
191
# Basic debug printing
192
x = 42
193
y = "hello"
194
debug(x, y)
195
# DEBUG: x=42
196
# DEBUG: y='hello'
197
198
# Custom formatting
199
debug(x, y, prefix=">>> ", sep=" -> ", merge=True)
200
# >>> x -> 42, y -> 'hello'
201
202
# With expressions (vars_only=False)
203
items = [1, 2, 3]
204
debug(len(items), items[0], vars_only=False)
205
# DEBUG: len(items)=3
206
# DEBUG: items[0]=1
207
208
# Complex objects without repr
209
class Person:
210
def __init__(self, name):
211
self.name = name
212
def __str__(self):
213
return f"Person({self.name})"
214
215
person = Person("Bob")
216
debug(person, repr=False)
217
# DEBUG: person=Person(Bob)
218
```
219
220
### JavaScript-like Object Creation
221
222
Create dictionaries using variable names as keys automatically, similar to JavaScript's object shorthand.
223
224
```python { .api }
225
def jsobj(
226
*args: Any,
227
vars_only: bool = True,
228
frame: int = 1,
229
**kwargs: Any
230
) -> Dict[str, Any]:
231
"""
232
Create a JavaScript-like object (dict) using variable names as keys.
233
234
Args:
235
*args: Positional arguments whose names will become keys
236
vars_only: Whether to only allow variables as arguments (vs expressions)
237
frame: Frame adjustment for name retrieval
238
**kwargs: Keyword arguments to include in the resulting dict
239
240
Returns:
241
Dictionary mapping argument names to their values, plus any kwargs
242
243
Note:
244
Uses nameof internally to get variable names from positional arguments.
245
Keyword arguments are included as-is.
246
"""
247
```
248
249
#### Usage Examples
250
251
```python
252
from varname.helpers import jsobj
253
254
# Basic usage
255
username = "alice"
256
user_id = 12345
257
active = True
258
259
user = jsobj(username, user_id, active)
260
# user == {'username': 'alice', 'user_id': 12345, 'active': True}
261
262
# With keyword arguments
263
user = jsobj(username, user_id, role="admin", permissions=["read", "write"])
264
# user == {
265
# 'username': 'alice',
266
# 'user_id': 12345,
267
# 'role': 'admin',
268
# 'permissions': ['read', 'write']
269
# }
270
271
# Nested objects
272
server_config = jsobj(
273
username,
274
user_id,
275
database=jsobj(host="localhost", port=5432),
276
cache=jsobj(enabled=True, ttl=3600)
277
)
278
# server_config == {
279
# 'username': 'alice',
280
# 'user_id': 12345,
281
# 'database': {'host': 'localhost', 'port': 5432},
282
# 'cache': {'enabled': True, 'ttl': 3600}
283
# }
284
285
# With expressions (vars_only=False)
286
items = [1, 2, 3]
287
result = jsobj(len(items), items[0], vars_only=False, total=sum(items))
288
# result == {'len(items)': 3, 'items[0]': 1, 'total': 6}
289
```
290
291
### Code Execution with Source Visibility
292
293
Execute code where the source is visible at runtime, enabling varname functions to work in dynamic execution contexts.
294
295
```python { .api }
296
def exec_code(
297
code: str,
298
globals: Dict[str, Any] = None,
299
locals: Dict[str, Any] = None,
300
/,
301
sourcefile: PathLike | str = None,
302
frame: int = 1,
303
ignore: IgnoreType = None,
304
**kwargs: Any
305
) -> None:
306
"""
307
Execute code where source code is visible at runtime.
308
309
Args:
310
code: The code string to execute
311
globals: Global namespace for execution (defaults to caller's globals)
312
locals: Local namespace for execution (defaults to caller's locals)
313
sourcefile: Optional file path to write source code to for visibility
314
frame: Frame adjustment for namespace retrieval
315
ignore: Frames to ignore when retrieving namespace
316
**kwargs: Additional arguments passed to exec()
317
318
Note:
319
This function makes varname operations work inside exec'd code by
320
ensuring the source code is available for AST analysis. Without this,
321
exec'd code cannot use varname functions effectively.
322
"""
323
```
324
325
#### Usage Examples
326
327
```python
328
from varname.helpers import exec_code, varname
329
330
# Basic code execution with varname support
331
code = '''
332
def create_item():
333
return varname()
334
335
my_item = create_item()
336
print(f"Created: {my_item}") # Will print: Created: my_item
337
'''
338
339
exec_code(code)
340
341
# With custom globals/locals
342
local_vars = {'data': [1, 2, 3]}
343
global_vars = {'varname': varname}
344
345
code = '''
346
def process():
347
name = varname()
348
return f"Processing {name} with {len(data)} items"
349
350
result = process()
351
'''
352
353
exec_code(code, globals=global_vars, locals=local_vars)
354
print(local_vars['result']) # Processing result with 3 items
355
356
# With source file for debugging
357
import tempfile
358
from pathlib import Path
359
360
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
361
source_file = f.name
362
363
code = '''
364
from varname.helpers import debug
365
366
x = 42
367
y = "test"
368
debug(x, y)
369
'''
370
371
exec_code(code, sourcefile=source_file)
372
# DEBUG: x=42
373
# DEBUG: y='test'
374
375
# Clean up
376
Path(source_file).unlink()
377
```
378
379
## Integration Patterns
380
381
### Factory Pattern with Name Awareness
382
383
```python
384
from varname.helpers import register
385
from varname.helpers import Wrapper
386
387
@register
388
class NamedFactory:
389
@classmethod
390
def create(cls, *args, **kwargs):
391
instance = cls(*args, **kwargs)
392
instance._factory_name = cls.__varname__
393
return instance
394
395
# Automatic name detection in factory
396
user_factory = NamedFactory.create()
397
print(user_factory._factory_name) # "user_factory"
398
399
# Combined with Wrapper
400
class SmartFactory:
401
def __init__(self, config):
402
self.config = config
403
404
def create_component(self):
405
return Wrapper({"factory": "smart", "config": self.config})
406
407
factory = SmartFactory({"debug": True})
408
component = factory.create_component()
409
print(f"Component {component.name} created") # Component component created
410
```
411
412
### Configuration Management
413
414
```python
415
from varname.helpers import jsobj, debug
416
417
def load_config():
418
# Database settings
419
db_host = "localhost"
420
db_port = 5432
421
db_name = "myapp"
422
423
# Cache settings
424
cache_enabled = True
425
cache_ttl = 3600
426
427
# Create config using variable names
428
config = {
429
"database": jsobj(db_host, db_port, db_name),
430
"cache": jsobj(cache_enabled, cache_ttl)
431
}
432
433
# Debug the configuration
434
debug(config, prefix="CONFIG: ")
435
return config
436
437
config = load_config()
438
# CONFIG: config={'database': {'db_host': 'localhost', ...}, ...}
439
```