Built-in Resolvers
BagCbResolver (Callback)
Execute a Python callable on demand.
>>> from genro_bag import Bag
>>> from genro_bag.resolvers import BagCbResolver
>>> def compute():
... return 42 * 2
>>> bag = Bag()
>>> bag['result'] = BagCbResolver(compute)
>>> bag['result']
84
With Arguments
def fetch_user(user_id):
return database.get_user(user_id)
bag['user'] = BagCbResolver(fetch_user, 'u123')
With Caching
call_count = 0
def expensive():
global call_count
call_count += 1
return {'result': 42, 'calls': call_count}
# Cache for 60 seconds
bag['data'] = BagCbResolver(expensive, cache_time=60)
bag['data'] # {'result': 42, 'calls': 1}
bag['data'] # {'result': 42, 'calls': 1} - cached
Async Callbacks
async def fetch_async():
async with aiohttp.ClientSession() as session:
async with session.get('https://api.example.com') as resp:
return await resp.json()
bag['api'] = BagCbResolver(fetch_async)
UrlResolver
Fetch content from HTTP URLs.
from genro_bag import Bag
from genro_bag.resolvers import UrlResolver
bag = Bag()
bag['api'] = UrlResolver('https://api.example.com/data')
# Access triggers HTTP request
data = bag['api'] # Returns bytes
Parse as Bag
# Auto-parse JSON/XML response
bag['users'] = UrlResolver(
'https://api.example.com/users',
as_bag=True,
cache_time=300
)
users = bag['users'] # Returns Bag
HTTP Methods
# GET with query parameters
bag['search'] = UrlResolver(
'https://api.example.com/search',
qs={'query': 'test', 'limit': 10}
)
# POST with body
body = Bag({'name': 'Alice', 'email': 'alice@example.com'})
bag['create'] = UrlResolver(
'https://api.example.com/users',
method='post',
body=body,
as_bag=True
)
Default Cache
UrlResolver defaults to cache_time=300 (5 minutes).
DirectoryResolver
Load a directory structure as a Bag hierarchy.
from genro_bag import Bag
from genro_bag.resolvers import DirectoryResolver
bag = Bag()
bag['config'] = DirectoryResolver('/path/to/config/')
# Directory structure becomes Bag:
# /path/to/config/
# database.xml -> bag['config.database']
# logging.json -> bag['config.logging']
# subdir/ -> bag['config.subdir'] (recursive)
Supported Files
.xml- Parsed as XML.bag.json- Parsed as TYTX JSON.bag.mp- Parsed as TYTX MessagePack
Default Cache
DirectoryResolver defaults to cache_time=0 (rescan on each access).
OpenApiResolver
Navigate OpenAPI specifications.
from genro_bag import Bag
from genro_bag.resolvers import OpenApiResolver
bag = Bag()
bag['api'] = OpenApiResolver('https://petstore3.swagger.io/api/v3/openapi.json')
# Access triggers fetch and parse
api = bag['api']
# Structure organized by tags
api['info'] # API description
api['api']['pet'].keys() # ['addPet', 'updatePet', ...]
api['api']['store'].keys() # ['getInventory', 'placeOrder', ...]
# Access operation details
op = api['api']['pet']['findPetsByStatus']
op['summary'] # 'Finds Pets by status'
op['method'] # 'get'
op['path'] # '/pet/findByStatus'
Default Cache
OpenApiResolver defaults to cache_time=False (infinite).
TxtDocResolver
Load file content as raw bytes.
from genro_bag import Bag
from genro_bag.resolvers import TxtDocResolver
bag = Bag()
bag['readme'] = TxtDocResolver('/path/to/readme.txt')
content = bag['readme'] # Returns bytes
text = content.decode('utf-8')
SerializedBagResolver
Load a serialized Bag file.
from genro_bag import Bag
from genro_bag.resolvers import SerializedBagResolver
bag = Bag()
bag['config'] = SerializedBagResolver('/path/to/config.xml')
bag['data'] = SerializedBagResolver('/path/to/data.bag.json')
# Access triggers file read and parse
config = bag['config'] # Returns Bag
config['database.host']
Supported Formats
.xml- XML format.bag.json- TYTX JSON.bag.mp- TYTX MessagePack
FileResolver
Lazily load a file with automatic format detection by extension.
from genro_bag import Bag
from genro_bag.resolvers import FileResolver
bag = Bag()
# Text files — returned as string
bag['style'] = FileResolver('/path/to/style.css')
bag['readme'] = FileResolver('/path/to/readme.md')
# JSON — returned as dict/list (or Bag with as_bag=True)
bag['config'] = FileResolver('/path/to/config.json')
bag['data'] = FileResolver('/path/to/data.json', as_bag=True)
# CSV — returned as Bag of records
bag['contacts'] = FileResolver('/path/to/contacts.csv')
# Native Bag formats — returned as Bag
bag['settings'] = FileResolver('/path/to/settings.bag.json')
Format Detection
Extension |
Returns |
Notes |
|---|---|---|
|
|
Text content |
|
|
Bag if |
|
|
Rows as nodes with column attributes |
|
|
Delegates to |
(other) |
|
Fallback to text |
CSV Structure
Each row becomes a Bag node with column values as attributes:
# contacts.csv:
# name,age,city
# Alice,30,NYC
# Bob,25,LA
bag['contacts'] = FileResolver('/path/to/contacts.csv')
contacts = bag['contacts']
node = contacts.get_node('r0')
node.attr['name'] # 'Alice'
node.attr['age'] # '30'
node.attr['city'] # 'NYC'
Without headers (csv_has_header=False), attributes are named c0, c1, c2, etc.
Relative Paths
# Resolve relative to a base directory
bag['style'] = FileResolver('static/style.css', base_path='/app')
# Without base_path, resolves relative to cwd
bag['style'] = FileResolver('style.css')
Parameters
Parameter |
Default |
Description |
|---|---|---|
|
(required) |
File path (absolute or relative) |
|
|
Base directory for relative paths (default: cwd) |
|
|
Text encoding |
|
|
CSV column delimiter |
|
|
Whether first CSV row is headers |
FileResolver defaults to cache_time=0 (re-read every time) and read_only=True.
EnvResolver
Read an environment variable on demand, with optional caching.
from genro_bag import Bag
from genro_bag.resolvers import EnvResolver
bag = Bag()
bag['db_host'] = EnvResolver('DATABASE_HOST', default='localhost')
bag['db_port'] = EnvResolver('DATABASE_PORT', default='5432')
bag['db_host'] # reads os.environ['DATABASE_HOST'] or 'localhost'
Live Updates
With cache_time=0 (default), every access re-reads the variable:
import os
bag['mode'] = EnvResolver('APP_MODE', default='development')
bag['mode'] # 'development'
os.environ['APP_MODE'] = 'production'
bag['mode'] # 'production' — picked up immediately
Caching
With cache_time=N, the value is cached for N seconds:
bag['secret'] = EnvResolver('API_KEY', cache_time=60)
bag['secret'] # reads from os.environ
bag['secret'] # cached for 60 seconds
EnvResolver defaults to cache_time=0 (re-read every time).
UuidResolver
Generate a UUID string on first access, cached forever by default.
from genro_bag import Bag
from genro_bag.resolvers import UuidResolver
bag = Bag()
bag['session_id'] = UuidResolver()
bag['session_id'] # '550e8400-e29b-41d4-a716-446655440000'
bag['session_id'] # same UUID (cached with cache_time=False)
UUID Versions
bag['random_id'] = UuidResolver() # uuid4 (default, random)
bag['ts_id'] = UuidResolver('uuid1') # uuid1 (timestamp-based)
Regenerate
node = bag.get_node('session_id')
node.value.reset() # invalidate cache
bag['session_id'] # new UUID generated
UuidResolver defaults to cache_time=False (infinite cache).
Common Parameters
All resolvers support three independent parameters:
Parameter |
Default |
Description |
|---|---|---|
|
varies |
Cache: 0=none, >0=passive TTL (int or float seconds), <0=active refresh (async only), False=infinite |
|
False |
If True, value is NOT stored in |
|
None |
If True, convert result to Bag; if None, follows |
Parameter Behavior
The three parameters are independent:
cache_time: Controls the resolver’s internal cache (TTL-based)read_only: Controls whether the value is stored in the Bag nodeas_bag: Controls automatic conversion to Bag
Truth Table
cache_time |
read_only |
as_bag |
Where stored |
Converts to Bag |
|---|---|---|---|---|
0 |
True |
[False] |
nowhere |
No |
0 |
True |
True |
nowhere |
Yes |
0 |
True |
False |
nowhere |
No |
0 |
[False] |
[True] |
node |
Yes |
0 |
[False] |
True |
node |
Yes |
0 |
[False] |
False |
node |
No |
!=0 |
True |
[False] |
cache |
No |
!=0 |
True |
True |
cache |
Yes |
!=0 |
True |
False |
cache |
No |
!=0 |
[False] |
[True] |
node |
Yes |
!=0 |
[False] |
True |
node |
Yes |
!=0 |
[False] |
False |
node |
No |
Where [value] indicates the computed default: as_bag defaults to not read_only.
Practical Implications
read_only=False(default): The resolved value becomes part of the Bag and can be navigated with dot notation. Defaultas_bag=Trueconverts the result to Bag automatically.read_only=True: The resolver acts like a “virtual” node - each access triggers resolution, the value is not stored in the Bag tree. Defaultas_bag=Falsereturns raw values.cache_time != 0: The resolver maintains its own internal cache (in_cached_value), independent from where the value is stored.
Resolver Defaults
Resolver |
|
|---|---|
|
0 |
|
0 |
|
0 |
|
False |
|
300 |
|
0 |
|
False |
|
500 |
|
500 |