Interpolation Syntax¶
Dracon provides powerful expression interpolation using ${...}
syntax for dynamic values.
Basic Interpolation¶
Simple Expressions¶
# Environment variables
log_level: ${getenv('LOG_LEVEL', 'INFO')}
# Mathematical expressions
max_workers: ${os.cpu_count() * 2}
# String operations
app_name: ${getenv('APP_NAME', 'myapp').lower()}
Immediate vs Lazy Evaluation¶
# Lazy evaluation (default) - resolved at construction time
computed_at_runtime: ${time.time()}
# Immediate evaluation - resolved during loading
computed_at_load: $(time.time())
Shorthand Variables¶
When enable_shorthand_vars=True
(default):
# These are equivalent:
user_home: $HOME
user_home: ${HOME}
# Complex expressions still need full syntax
computed: ${$HOME + '/data'}
Reference System¶
KeyPath References (@
)¶
Reference other keys in the same configuration:
environment: prod
database:
host: "db.${@/environment}.local" # References /environment
backup_host: "backup.${@host}" # References database/host
Reference Syntax¶
@/key
: Absolute reference from root@key
: Relative reference from current level@../key
: Parent level reference@/nested/deep/key
: Deep nested reference
Anchor References (&
)¶
Reference YAML anchors and process them:
defaults: &defaults
timeout: 30
retries: 3
service_config:
name: my-service
timeout: ${&defaults.timeout * 2} # References anchor content
Built-in Functions¶
OS Functions¶
# Environment variables
api_url: ${getenv('API_URL', 'http://localhost:8080')}
# File system
data_dir: ${expanduser('~/data')}
current_dir: ${getcwd()}
config_files: ${listdir('/etc/myapp')}
# Path operations
log_file: ${join(expanduser('~/logs'), 'app.log')}
script_name: ${basename(__file__)}
script_dir: ${dirname(__file__)}
Dracon Functions¶
# Construct deferred nodes
output_path: ${construct(deferred_node, {'runtime_var': 'value'})}
# Access current file context
config_dir: ${__DRACON__CURRENT_PATH}
parent_dir: ${__DRACON__PARENT_PATH}
Context Variables¶
Automatic Context (in file loading)¶
# File information
config_backup: ${DIR}/backup/${FILE_STEM}.backup
load_timestamp: ${FILE_LOAD_TIME}
config_size: ${FILE_SIZE}
Custom Context¶
# Provided when loading
loader.load('config.yaml', context={
'version': '1.2.3',
'deployment': 'production',
'custom_func': lambda x: x.upper()
})
# Used in YAML
app_version: ${version}
deployment_type: ${deployment}
service_name: ${custom_func('myservice')}
Advanced Patterns¶
Conditional Expressions¶
# Simple conditionals
debug_mode: ${getenv('DEBUG', 'false').lower() == 'true'}
# Complex conditionals
log_level: ${
'DEBUG' if getenv('ENVIRONMENT') == 'dev'
else 'WARNING' if getenv('ENVIRONMENT') == 'prod'
else 'INFO'
}
List Comprehensions¶
# Generate lists
service_ports: ${[8000 + i for i in range(int(getenv('REPLICAS', '3')))]}
# Filter lists
enabled_services: ${[s for s in services if s.get('enabled', True)]}
Dictionary Operations¶
# Merge dictionaries
merged_config: ${dict(base_config, **override_config)}
# Filter dictionaries
prod_settings: ${
{k: v for k, v in all_settings.items()
if not k.startswith('dev_')}
}
Key Interpolation¶
Generate dynamic keys:
!define environments: ["dev", "staging", "prod"]
!each(env) ${environments}:
${env}_database_url: postgres://db.${env}.local/myapp
${env}_redis_url: redis://cache.${env}.local
Nested Interpolation¶
# Environment-based configuration selection
!define config_key: ${getenv('ENVIRONMENT', 'dev')}_settings
# Use the computed key
app_config: ${globals()[config_key]}
# Nested expressions
complex_value: ${getenv('PREFIX', 'app') + '_' + str(getenv('VERSION', '1'))}
Escaping¶
Escape interpolation when you need literal ${}
:
# Escaped - will be literal "${version}"
escaped_template: \${version}
# Not escaped - will interpolate
interpolated: ${version}
# Mixed
docker_command: echo \${VERSION} > /tmp/version && echo ${actual_version}
Error Handling¶
Safe Navigation¶
# Handle missing keys gracefully
optional_value: ${config.get('optional_key', 'default')}
# Chain operations safely
nested_value: ${config.get('section', {}).get('key', 'fallback')}
Try-Catch Patterns¶
# Using Python's exception handling
database_url: ${
getenv('DATABASE_URL') if getenv('DATABASE_URL')
else f"postgresql://{getenv('DB_USER')}:{getenv('DB_PASS')}@{getenv('DB_HOST')}/myapp"
}
Performance Notes¶
- Expressions are cached when possible
- References (
@
and&
) are resolved efficiently - Complex expressions may impact loading time
- Use immediate evaluation
$()
for values that don't change
Common Use Cases¶
Environment-based Configuration¶
database:
host: db.${getenv('ENVIRONMENT', 'dev')}.local
pool_size: ${int(getenv('DB_POOL_SIZE', '10'))}
ssl_mode: ${
'require' if getenv('ENVIRONMENT') == 'prod'
else 'prefer'
}
Dynamic Service Discovery¶
services:
auth_service: http://${getenv('AUTH_HOST', 'localhost')}:${getenv('AUTH_PORT', '8001')}
data_service: http://${getenv('DATA_HOST', 'localhost')}:${getenv('DATA_PORT', '8002')}
service_mesh: ${
[f"http://{service}:{port}"
for service, port in zip(service_hosts, service_ports)]
}