Priority ExampleΒΆ
Demonstrates priority ordering.
1"""
2Example demonstrating priority ordering.
3
4Shows three ways to customize priority:
51. Reorder sources (recommended - simplest)
62. Use PriorityPolicy for per-key rules
73. Multiple sources of the same type with custom IDs
8
9Run with:
10 python priority_example.py
11 python priority_example.py --host 0.0.0.0 --port 9999
12"""
13
14import os
15import tempfile
16from dataclasses import dataclass, field
17
18from varlord import Config, PriorityPolicy, sources
19
20# Set environment variables for testing
21os.environ["HOST"] = "env-host"
22os.environ["PORT"] = "8888"
23os.environ["API_KEY"] = "env-api-key"
24
25
26@dataclass(frozen=True)
27class DBConfig:
28 """Database configuration (nested dataclass - best practice)."""
29
30 host: str = field(default="localhost", metadata={"description": "Database host"})
31 port: int = field(default=5432, metadata={"description": "Database port"})
32
33
34@dataclass(frozen=True)
35class AppConfig:
36 """Application configuration model."""
37
38 host: str = field(default="127.0.0.1", metadata={"description": "Server host address"})
39 port: int = field(default=8000, metadata={"description": "Server port number"})
40 debug: bool = field(default=False, metadata={"description": "Enable debug mode"})
41 api_key: str = field(default="default-key", metadata={"description": "API key"})
42 # Use nested dataclass for nested structure (best practice)
43 db: DBConfig = field(
44 default_factory=DBConfig, metadata={"description": "Database configuration"}
45 )
46
47
48def example_1_reorder_sources():
49 """Method 1: Reorder sources (recommended - simplest)."""
50 print("=== Example 1: Reorder Sources ===")
51 print("Priority: defaults < env < cli (later sources override earlier ones)\n")
52
53 # Priority is determined by sources order: later sources override earlier ones
54 # Model defaults are automatically applied first (lowest priority)
55 # Model is auto-injected to all sources by Config
56 cfg = Config(
57 model=AppConfig,
58 sources=[
59 sources.Env(), # Overrides defaults - model auto-injected
60 sources.CLI(), # Highest priority (last) - model auto-injected
61 ],
62 )
63
64 app = cfg.load()
65 print("β
Config loaded:")
66 print(f" host: {app.host} (from {'CLI' if '--host' in str(cfg._sources) else 'env'})")
67 print(f" port: {app.port}")
68 print(f" api_key: {app.api_key[:10]}...")
69
70
71def example_2_priority_policy():
72 """Method 2: Use PriorityPolicy (advanced: per-key rules)."""
73 print("\n=== Example 2: PriorityPolicy ===")
74 print("Custom priority: api_key and db.* only from defaults and env (CLI ignored)\n")
75
76 # Use when you need different priority rules for different keys
77 # Model is auto-injected to all sources by Config
78 cfg = Config(
79 model=AppConfig,
80 sources=[
81 sources.Env(), # Model defaults applied automatically, model auto-injected
82 sources.CLI(), # Model auto-injected
83 ],
84 policy=PriorityPolicy(
85 default=["defaults", "env", "cli"], # Default: all sources in order
86 overrides={
87 "api_key": ["defaults", "env"], # API key: env can override, but not CLI
88 "db.host": ["defaults", "env"], # DB host: env can override, but not CLI
89 "db.port": ["defaults", "env"], # DB port: env can override, but not CLI
90 },
91 ),
92 )
93
94 app = cfg.load()
95 print("β
Config loaded:")
96 print(f" host: {app.host} (CLI can override)")
97 print(f" api_key: {app.api_key[:10]}... (CLI cannot override)")
98 print(f" db.host: {app.db.host} (CLI cannot override)")
99
100
101def example_3_multiple_sources_same_type():
102 """Method 3: Multiple sources of the same type."""
103 print("\n=== Example 3: Multiple Sources of Same Type ===")
104 print("System config (lower priority) + User config (higher priority)\n")
105
106 # Create two YAML files
107 yaml1_content = """
108host: system-host
109port: 9000
110api_key: system-key
111"""
112 yaml2_content = """
113host: user-host
114port: 8080
115debug: true
116"""
117
118 with tempfile.NamedTemporaryFile(mode="w", suffix="_system.yaml", delete=False) as f:
119 f.write(yaml1_content)
120 yaml1_path = f.name
121
122 with tempfile.NamedTemporaryFile(mode="w", suffix="_user.yaml", delete=False) as f:
123 f.write(yaml2_content)
124 yaml2_path = f.name
125
126 try:
127 # Create two YAML sources with different IDs
128 yaml1 = sources.YAML(yaml1_path, model=AppConfig, source_id="system-config")
129 yaml2 = sources.YAML(yaml2_path, model=AppConfig, source_id="user-config")
130
131 cfg = Config(
132 model=AppConfig,
133 sources=[
134 yaml1, # System config (lower priority)
135 yaml2, # User config (higher priority - overrides system)
136 ],
137 )
138
139 app = cfg.load()
140 print("β
Config loaded:")
141 print(f" host: {app.host} (from user-config, overrides system-config)")
142 print(f" port: {app.port} (from user-config)")
143 print(f" debug: {app.debug} (from user-config)")
144 print(
145 f" api_key: {app.api_key[:10]}... (from system-config, user-config doesn't have it)"
146 )
147 finally:
148 import os
149
150 os.unlink(yaml1_path)
151 os.unlink(yaml2_path)
152
153
154def main():
155 """Main function."""
156 example_1_reorder_sources()
157 example_2_priority_policy()
158 example_3_multiple_sources_same_type()
159
160
161if __name__ == "__main__":
162 main()