Variable Replacement System¶
Home > Developer Guide > Variable Replacement System
The Ingenious Fabric Accelerator includes a sophisticated variable replacement system that enables environment-specific configuration management across templates, notebooks, and deployments. This system allows the same codebase to work seamlessly across development, testing, and production environments.
Overview¶
The variable replacement system operates through two primary mechanisms:
- Placeholder Replacement: Substituting
{{varlib:variable_name}}markers with actual values - Code Injection: Inserting variable dictionaries and objects between injection markers
Architecture¶
graph TD
A[Variable Library JSON] --> B[VariableLibraryUtils]
B --> C[Template Processing]
B --> D[Code Injection]
C --> E[Placeholder Replacement]
D --> F[Variable Objects]
E --> G[Generated Notebooks]
F --> G
G --> H[Deployment] Core Components¶
VariableLibraryUtils¶
The central class that handles all variable operations:
from ingen_fab.config_utils.variable_lib import VariableLibraryUtils
# Basic instantiation
vlu = VariableLibraryUtils(
project_path=Path("sample_project"),
environment="development"
)
# Get workspace ID
workspace_id = vlu.get_workspace_id()
# Get specific variable
lakehouse_id = vlu.get_variable_value("config_lakehouse_id")
Factory Functions (Recommended)¶
For common patterns, use the factory functions:
from ingen_fab.config_utils.variable_lib_factory import VariableLibraryFactory
# From CLI context
vlu = VariableLibraryFactory.from_cli_context(ctx)
# For specific workflow
dev_injector = VariableLibraryFactory.for_development(environment, project_path)
deploy_injector = VariableLibraryFactory.for_deployment(environment, project_path)
readonly_lib = VariableLibraryFactory.for_readonly(environment, project_path)
Variable Configuration¶
JSON Structure¶
Variables are defined in environment-specific JSON files:
sample_project/
└── fabric_workspace_items/
└── config/
└── var_lib.VariableLibrary/
└── valueSets/
├── development.json
├── test.json
└── production.json
Example Configuration¶
{
"variableOverrides": [
{
"name": "fabric_deployment_workspace_id",
"value": "544530ea-a8c9-4464-8878-f666d2a8f418"
},
{
"name": "config_lakehouse_id",
"value": "514ebe8f-2bf9-4a31-88f7-13d84706431c"
},
{
"name": "config_workspace_name",
"value": "metcash_demo"
}
]
}
Replacement Mechanisms¶
1. Placeholder Replacement¶
When: Template compilation and deployment
Format: {{varlib:variable_name}}
Usage: Connection strings, configuration values
Example Template¶
# Template (library_loader.py.jinja)
notebookutils.fs.mount(
"abfss://{{varlib:config_workspace_name}}@onelake.dfs.fabric.microsoft.com/{{varlib:config_lakehouse_name}}.Lakehouse/Files/",
"/config_files"
)
Generated Result¶
# Generated notebook
notebookutils.fs.mount(
"abfss://metcash_demo@onelake.dfs.fabric.microsoft.com/config.Lakehouse/Files/",
"/config_files"
)
2. Code Injection¶
When: Development and deployment workflows
Format: Injection markers
Usage: Variable dictionaries and objects
Injection Markers¶
# variableLibraryInjectionStart: var_lib
# This content will be replaced
# variableLibraryInjectionEnd: var_lib
Generated Content¶
# variableLibraryInjectionStart: var_lib
# All variables as a dictionary
configs_dict = {
'fabric_environment': 'development',
'fabric_deployment_workspace_id': '544530ea-a8c9-4464-8878-f666d2a8f418',
'config_workspace_name': 'metcash_demo',
'config_lakehouse_id': '514ebe8f-2bf9-4a31-88f7-13d84706431c'
}
# All variables as an object
from dataclasses import dataclass
@dataclass
class ConfigsObject:
fabric_environment: str
fabric_deployment_workspace_id: str
config_workspace_name: str
config_lakehouse_id: str
configs_object: ConfigsObject = ConfigsObject(**configs_dict)
# variableLibraryInjectionEnd: var_lib
When Replacements Occur¶
Supported Artifact Types¶
Variable substitution is applied to the following artifact types during deployment:
| Artifact Type | File Pattern | Description |
|---|---|---|
| Notebooks | notebook-content.py | Python notebook source files |
| Semantic Models | *.tmdl | Tabular Model Definition Language files |
| GraphQL APIs | graphql-definition.json | GraphQL API definition files |
| Data Pipelines | pipeline-content.json | Data pipeline definition files |
| Power BI Reports | definition.pbir | Power BI report definition files |
These artifact types support both placeholder replacement ({{varlib:variable_name}}) and code injection between markers during the deployment process.
Development Workflow¶
- Placeholder replacement: ❌ No (preserved for deployment)
- Code injection: ✅ Yes (enables local development)
- Location: In-place file modification
- Artifacts: Notebooks only (for local development)
DDL Compilation¶
- Placeholder replacement: ❌ No (preserved in templates)
- Code injection: ❌ No (happens later during deployment)
- Location: Generated notebook files
Deployment¶
- Placeholder replacement: ✅ Yes (environment-specific values)
- Code injection: ✅ Yes (complete configuration)
- Location: Output directory for deployment
- Artifacts: Notebooks, Semantic Models, GraphQL APIs, Data Pipelines, and Power BI Reports
OneLake Upload¶
- Placeholder replacement: ✅ Yes (if placeholders exist)
- Code injection: ✅ Yes (if markers exist)
- Location: Files processed during upload to Fabric
Workflow-Specific Classes¶
DevelopmentVariableInjector¶
Pre-configured for development workflows:
from ingen_fab.config_utils.variable_lib_workflows import DevelopmentVariableInjector
# Optimized for development
injector = DevelopmentVariableInjector(project_path, environment)
injector.inject_variables() # Code injection only, preserves placeholders
DeploymentVariableInjector¶
Pre-configured for deployment workflows:
from ingen_fab.config_utils.variable_lib_workflows import DeploymentVariableInjector
# Optimized for deployment
injector = DeploymentVariableInjector(project_path, environment)
injector.inject_variables(output_dir=Path("dist")) # Full substitution
ReadOnlyVariableLibrary¶
For variable lookup without injection:
from ingen_fab.config_utils.variable_lib_workflows import ReadOnlyVariableLibrary
# Read-only access
reader = ReadOnlyVariableLibrary(project_path, environment)
workspace_id = reader.workspace_id
config_value = reader.get_variable("config_lakehouse_id")
Advanced Usage¶
Artifact-Specific Examples¶
Notebooks (notebook-content.py)¶
Notebooks support both placeholder replacement and code injection:
# Template with placeholders
workspace_id = "{{varlib:fabric_deployment_workspace_id}}"
lakehouse_id = "{{varlib:config_lakehouse_id}}"
# variableLibraryInjectionStart: var_lib
# Config variables will be injected here during deployment
# variableLibraryInjectionEnd: var_lib
# Use injected configs_dict
spark.conf.set(f"spark.sql.lakehouse.id", configs_dict['config_lakehouse_id'])
After deployment:
# Placeholders replaced
workspace_id = "544530ea-a8c9-4464-8878-f666d2a8f418"
lakehouse_id = "514ebe8f-2bf9-4a31-88f7-13d84706431c"
# variableLibraryInjectionStart: var_lib
configs_dict = {
'fabric_deployment_workspace_id': '544530ea-a8c9-4464-8878-f666d2a8f418',
'config_lakehouse_id': '514ebe8f-2bf9-4a31-88f7-13d84706431c'
}
# variableLibraryInjectionEnd: var_lib
# Use injected configs_dict
spark.conf.set(f"spark.sql.lakehouse.id", configs_dict['config_lakehouse_id'])
Semantic Models (*.tmdl)¶
Semantic model TMDL files can use placeholders for data sources:
table Customer
lineageTag: abc123
sourceExpression:
kind: m
expression: =
let
Source = Lakehouse.Contents("{{varlib:config_lakehouse_id}}"),
Navigation = Source{[workspaceId="{{varlib:fabric_deployment_workspace_id}}"]}[Data]
in
Navigation
After deployment:
table Customer
lineageTag: abc123
sourceExpression:
kind: m
expression: =
let
Source = Lakehouse.Contents("514ebe8f-2bf9-4a31-88f7-13d84706431c"),
Navigation = Source{[workspaceId="544530ea-a8c9-4464-8878-f666d2a8f418"]}[Data]
in
Navigation
GraphQL APIs (graphql-definition.json)¶
GraphQL API definitions can use placeholders for connection information:
{
"dataSource": {
"type": "Lakehouse",
"workspaceId": "{{varlib:fabric_deployment_workspace_id}}",
"lakehouseId": "{{varlib:config_lakehouse_id}}"
},
"schema": {
"types": [...],
"queries": [...]
}
}
After deployment:
{
"dataSource": {
"type": "Lakehouse",
"workspaceId": "544530ea-a8c9-4464-8878-f666d2a8f418",
"lakehouseId": "514ebe8f-2bf9-4a31-88f7-13d84706431c"
},
"schema": {
"types": [...],
"queries": [...]
}
}
Data Pipelines (pipeline-content.json)¶
Data pipeline definitions can use placeholders for workspace IDs, lakehouse IDs, and other connection properties:
{
"properties": {
"activities": [
{
"name": "Copy_Data",
"type": "Copy",
"typeProperties": {
"source": {
"type": "LakehouseTableSource",
"lakehouseId": "{{varlib:config_lakehouse_id}}"
},
"sink": {
"type": "LakehouseTableSink",
"lakehouseId": "{{varlib:target_lakehouse_id}}",
"workspaceId": "{{varlib:fabric_deployment_workspace_id}}"
}
}
}
]
}
}
Power BI Reports (definition.pbir)¶
Power BI report definition files can use placeholders for dataset connection strings:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definitionProperties/2.0.0/schema.json",
"version": "4.0",
"datasetReference": {
"byConnection": {
"connectionString": "{{varlib:report_connection_string}}"
}
}
}
After deployment to production:
{
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/report/definitionProperties/2.0.0/schema.json",
"version": "4.0",
"datasetReference": {
"byConnection": {
"connectionString": "Data Source=powerbi://api.powerbi.com/v1.0/myorg/Production Workspace;Initial Catalog=sales_semantic_model"
}
}
}
Custom Injection Behavior¶
{
"properties": {
"activities": [
{
"name": "Copy_Data",
"type": "Copy",
"typeProperties": {
"source": {
"type": "LakehouseTableSource",
"lakehouseId": "514ebe8f-2bf9-4a31-88f7-13d84706431c"
},
"sink": {
"type": "LakehouseTableSink",
"lakehouseId": "a29c4f1e-5d67-4c89-b123-9e8d74f31a2b",
"workspaceId": "544530ea-a8c9-4464-8878-f666d2a8f418"
}
}
}
]
}
}
Custom Variable Processing¶
# Fine-grained control
vlu = VariableLibraryUtils(project_path, environment)
# Only placeholder replacement
content = vlu.perform_code_replacements(
content,
replace_placeholders=True,
inject_code=False
)
# Only code injection
content = vlu.perform_code_replacements(
content,
replace_placeholders=False,
inject_code=True
)
Caching for Performance¶
from ingen_fab.config_utils.variable_lib_factory import VariableLibraryCache
# Cache management
cache_size = VariableLibraryCache.cache_size()
VariableLibraryCache.clear_cache() # Clear when switching environments
Best Practices¶
1. Environment Separation¶
- ✅ Do: Use separate JSON files for each environment
- ✅ Do: Keep sensitive values in production-only configs
- ❌ Don't: Hardcode environment-specific values in templates
2. Template Design¶
- ✅ Do: Use placeholders for connection strings and IDs
- ✅ Do: Use injection markers for variable objects
- ❌ Don't: Mix placeholder and hardcoded values
3. Development Workflow¶
- ✅ Do: Use code injection during development for testing
- ✅ Do: Preserve placeholders until deployment
- ❌ Don't: Inject variables multiple times (causes redundancy)
4. Performance¶
- ✅ Do: Use factory functions for common patterns
- ✅ Do: Enable caching for repeated operations
- ❌ Don't: Create multiple instances unnecessarily
Common Patterns¶
CLI Integration¶
def my_command(ctx: typer.Context):
# Use factory for CLI context
vlu = VariableLibraryFactory.from_cli_context(ctx)
workspace_id = vlu.get_workspace_id()
Template Processing¶
def process_template(template_content: str, environment: str):
vlu = VariableLibraryFactory.from_environment_and_path(environment, project_path)
return vlu.perform_code_replacements(template_content)
Deployment Pipeline¶
def deploy_notebooks(environment: str, project_path: Path):
# Use deployment-specific injector
injector = VariableLibraryFactory.for_deployment(environment, project_path)
injector.inject_variables(output_dir=Path("dist"))
Troubleshooting¶
Common Issues¶
- Variables not found
- Check JSON file exists for environment
- Verify variable name spelling
-
Ensure
variableOverridesarray structure -
Injection markers not processed
-
Placeholders not replaced
- Ensure
replace_placeholders=Trueis set - Check placeholder format:
{{varlib:variable_name}} - Verify deployment workflow is used
Debugging¶
# Enable verbose output
import logging
logging.basicConfig(level=logging.DEBUG)
# Check variable loading
vlu = VariableLibraryUtils(project_path, environment)
print(f"Loaded variables: {vlu.variables}")
# Test specific operations
result = vlu.replace_variable_placeholders("{{varlib:config_workspace_name}}")
print(f"Replacement result: {result}")
Related Documentation¶
- Python Libraries - Core library architecture
- DDL Scripts - Template system integration
- CLI Reference - Command usage
- Workflows - End-to-end processes
The variable replacement system is fundamental to enabling environment-agnostic development and deployment in the Ingenious Fabric Accelerator. Understanding when and how replacements occur is crucial for effective use of the platform.