Resolvers
Resolvers enable lazy loading: instead of storing a value directly, a node can compute or fetch its value on demand.
When Do You Need Resolvers?
You need resolvers when:
Values come from external sources: API calls, database queries, file reads
Computation is expensive: Only compute when actually accessed
Data changes over time: Fetch fresh data on each access (or with caching)
You want transparent access: Code that reads the value doesn’t need to know it’s dynamic
The Core Idea
Without resolvers:
# Value is static, set once
bag['data'] = fetch_from_api() # Called immediately
With resolvers:
# Value is computed on access
bag['data'] = UrlResolver('https://api.example.com/data')
# Nothing fetched yet
result = bag['data'] # NOW the API is called
Quick Example
>>> from genro_bag import Bag
>>> from genro_bag.resolvers import BagCbResolver
>>> from datetime import datetime
>>> def get_timestamp():
... return datetime.now().isoformat()
>>> bag = Bag()
>>> bag['timestamp'] = BagCbResolver(get_timestamp)
>>> # Value computed on access
>>> bag['timestamp']
'2025-01-07T10:30:45.123456'
Key Features
Caching
Control how often values are recomputed:
# Compute every time (default)
bag['dynamic'] = BagCbResolver(func, cache_time=0)
# Cache for 5 minutes (passive — reload on next access after expiry)
bag['cached'] = BagCbResolver(func, cache_time=300)
# Cache forever (until manual reset)
bag['permanent'] = BagCbResolver(func, cache_time=False)
# Active cache — background refresh every 30 seconds (async only)
bag['live'] = BagCbResolver(func, cache_time=-30)
Async Support
Resolvers work in both sync and async contexts:
# Sync - just works
result = bag['data']
# Async - use smartawait
from genro_toolbox import smartawait
result = await smartawait(bag.get_item('data'))
Serialization
Resolvers survive serialization with TYTX:
tytx = bag.to_tytx()
restored = Bag.from_tytx(tytx)
# Resolver is preserved!
Built-in Resolvers
Resolver |
Purpose |
|---|---|
|
Callback function |
|
HTTP requests |
|
Load directory structure |
|
Navigate OpenAPI specs |
|
Load files with format detection |
|
Load file content as bytes |
|
Load serialized Bag files |
Creating Custom Resolvers
Extend BagResolver for your own data sources:
from genro_bag.resolver import BagResolver
class DatabaseResolver(BagResolver):
class_args = ['query']
class_kwargs = {'connection': None, 'cache_time': 60}
def load(self):
return self.kw['connection'].execute(self.kw['query'])