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'))

Sync and Async Guide

Serialization

Resolvers survive serialization with TYTX:

tytx = bag.to_tytx()
restored = Bag.from_tytx(tytx)
# Resolver is preserved!

Built-in Resolvers

Resolver

Purpose

BagCbResolver

Callback function

UrlResolver

HTTP requests

DirectoryResolver

Load directory structure

OpenApiResolver

Navigate OpenAPI specs

FileResolver

Load files with format detection

TxtDocResolver

Load file content as bytes

SerializedBagResolver

Load serialized Bag files

Built-in Resolvers

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'])

Custom Resolvers

What’s Next?