0
# Structured Configs
1
2
Integration with Python dataclasses and attrs classes for type-safe configuration schemas, enabling automatic validation and IDE support.
3
4
## Capabilities
5
6
### Structured Config Creation
7
8
Creates type-safe configurations from Python dataclasses and attrs classes with automatic validation.
9
10
```python { .api }
11
def structured(obj, parent=None, flags=None):
12
"""
13
Create config from structured object (dataclass/attrs).
14
15
Parameters:
16
- obj: Dataclass/attrs class or instance
17
- parent: Parent node for nested configs
18
- flags: Configuration flags
19
20
Returns:
21
DictConfig with type validation based on structured schema
22
23
Features:
24
- Automatic type validation based on annotations
25
- Support for default values and factory functions
26
- Integration with typing module (Optional, Union, etc.)
27
- Preservation of class structure and relationships
28
"""
29
```
30
31
### Object Instantiation
32
33
Converts configurations back to Python objects with proper type instantiation.
34
35
```python { .api }
36
def to_object(cfg):
37
"""
38
Convert configuration to instantiated objects.
39
40
Parameters:
41
- cfg: Configuration to convert (must be from structured config)
42
43
Returns:
44
Instantiated dataclass/attrs object with validated values
45
46
Notes:
47
- Only works with configs created from structured objects
48
- Recursively instantiates nested structured configs
49
- Validates all values against original type annotations
50
"""
51
```
52
53
### Type Information
54
55
Methods for inspecting type information in structured configurations.
56
57
```python { .api }
58
def get_type(obj, key=None):
59
"""
60
Get type information for structured config.
61
62
Parameters:
63
- obj: Structured configuration object
64
- key: Optional specific key to inspect
65
66
Returns:
67
Type information from original dataclass/attrs annotations
68
"""
69
```
70
71
## Dataclass Integration
72
73
### Basic Dataclass Usage
74
75
```python
76
from dataclasses import dataclass, field
77
from typing import List, Optional
78
from omegaconf import OmegaConf
79
80
@dataclass
81
class DatabaseConfig:
82
host: str = "localhost"
83
port: int = 5432
84
username: str = "admin"
85
password: Optional[str] = None
86
pool_size: int = 10
87
88
@dataclass
89
class AppConfig:
90
database: DatabaseConfig = field(default_factory=DatabaseConfig)
91
debug: bool = False
92
features: List[str] = field(default_factory=list)
93
94
# Create from class (uses defaults)
95
config = OmegaConf.structured(AppConfig)
96
print(config.database.host) # "localhost"
97
print(config.debug) # False
98
99
# Create from instance (with overrides)
100
config = OmegaConf.structured(AppConfig(
101
database=DatabaseConfig(host="remote-db", port=3306),
102
debug=True,
103
features=["auth", "logging"]
104
))
105
```
106
107
### Type Validation
108
109
```python
110
from dataclasses import dataclass
111
from omegaconf import OmegaConf, ValidationError
112
113
@dataclass
114
class Config:
115
name: str
116
count: int
117
rate: float
118
enabled: bool
119
120
config = OmegaConf.structured(Config)
121
122
# Type conversion works
123
config.name = "test" # str -> str ✓
124
config.count = "42" # str -> int ✓
125
config.rate = "3.14" # str -> float ✓
126
config.enabled = "true" # str -> bool ✓
127
128
# Type validation prevents errors
129
try:
130
config.count = "invalid" # Cannot convert to int
131
except ValidationError:
132
print("Validation failed")
133
134
try:
135
config.new_field = "value" # New fields not allowed in struct mode
136
except Exception:
137
print("Cannot add new fields")
138
```
139
140
### Optional and Union Types
141
142
```python
143
from dataclasses import dataclass
144
from typing import Optional, Union
145
from omegaconf import OmegaConf
146
147
@dataclass
148
class Config:
149
required_field: str
150
optional_field: Optional[str] = None
151
union_field: Union[str, int] = "default"
152
optional_union: Optional[Union[str, int]] = None
153
154
config = OmegaConf.structured(Config)
155
156
# Optional fields can be None
157
config.optional_field = None # ✓
158
config.optional_field = "some value" # ✓
159
160
# Union fields accept multiple types
161
config.union_field = "string value" # ✓
162
config.union_field = 42 # ✓
163
164
# Optional union combines both behaviors
165
config.optional_union = None # ✓
166
config.optional_union = "string" # ✓
167
config.optional_union = 123 # ✓
168
```
169
170
### Nested Structured Configs
171
172
```python
173
from dataclasses import dataclass, field
174
from typing import List
175
from omegaconf import OmegaConf
176
177
@dataclass
178
class ServerConfig:
179
host: str = "localhost"
180
port: int = 8080
181
ssl_enabled: bool = False
182
183
@dataclass
184
class DatabaseConfig:
185
url: str = "sqlite:///app.db"
186
pool_size: int = 5
187
timeout: int = 30
188
189
@dataclass
190
class AppConfig:
191
name: str = "MyApp"
192
servers: List[ServerConfig] = field(default_factory=list)
193
database: DatabaseConfig = field(default_factory=DatabaseConfig)
194
195
# Create nested structured config
196
config = OmegaConf.structured(AppConfig(
197
servers=[
198
ServerConfig(host="web1", port=80),
199
ServerConfig(host="web2", port=80, ssl_enabled=True)
200
]
201
))
202
203
# Access nested values with type safety
204
print(config.servers[0].host) # "web1"
205
print(config.servers[1].ssl_enabled) # True
206
print(config.database.pool_size) # 5
207
208
# Modify nested structures
209
config.servers[0].port = 8080
210
config.database.timeout = 60
211
```
212
213
## Attrs Integration
214
215
```python
216
import attr
217
from typing import Optional
218
from omegaconf import OmegaConf
219
220
@attr.s
221
class DatabaseConfig:
222
host: str = attr.ib(default="localhost")
223
port: int = attr.ib(default=5432)
224
ssl: bool = attr.ib(default=False)
225
226
@attr.s
227
class AppConfig:
228
name: str = attr.ib()
229
database: DatabaseConfig = attr.ib(factory=DatabaseConfig)
230
debug: Optional[bool] = attr.ib(default=None)
231
232
# Works same as dataclasses
233
config = OmegaConf.structured(AppConfig(name="MyApp"))
234
print(config.database.host) # "localhost"
235
```
236
237
## Object Conversion
238
239
### Converting Back to Objects
240
241
```python
242
from dataclasses import dataclass
243
from omegaconf import OmegaConf
244
245
@dataclass
246
class Config:
247
name: str = "default"
248
value: int = 42
249
250
# Create and modify config
251
config = OmegaConf.structured(Config)
252
config.name = "modified"
253
config.value = 100
254
255
# Convert back to dataclass instance
256
obj = OmegaConf.to_object(config)
257
print(type(obj)) # <class '__main__.Config'>
258
print(obj.name) # "modified"
259
print(obj.value) # 100
260
261
# Original dataclass methods work
262
print(obj) # Config(name='modified', value=100)
263
```
264
265
### Recursive Object Conversion
266
267
```python
268
from dataclasses import dataclass, field
269
from typing import List
270
from omegaconf import OmegaConf
271
272
@dataclass
273
class Item:
274
name: str
275
quantity: int
276
277
@dataclass
278
class Order:
279
id: str
280
items: List[Item] = field(default_factory=list)
281
282
# Create structured config
283
config = OmegaConf.structured(Order(
284
id="order-123",
285
items=[Item("apple", 5), Item("banana", 3)]
286
))
287
288
# Convert entire structure back to objects
289
order = OmegaConf.to_object(config)
290
print(type(order)) # <class '__main__.Order'>
291
print(type(order.items[0])) # <class '__main__.Item'>
292
print(order.items[0].name) # "apple"
293
```
294
295
## Advanced Patterns
296
297
### Inheritance with Structured Configs
298
299
```python
300
from dataclasses import dataclass
301
from omegaconf import OmegaConf
302
303
@dataclass
304
class BaseConfig:
305
name: str = "base"
306
version: str = "1.0"
307
308
@dataclass
309
class ServerConfig(BaseConfig):
310
host: str = "localhost"
311
port: int = 8080
312
313
@dataclass
314
class DatabaseConfig(BaseConfig):
315
url: str = "sqlite:///db.sqlite"
316
pool_size: int = 5
317
318
# Inheritance works naturally
319
server_config = OmegaConf.structured(ServerConfig)
320
print(server_config.name) # "base" (inherited)
321
print(server_config.host) # "localhost" (own field)
322
```
323
324
### Factory Functions and Complex Defaults
325
326
```python
327
from dataclasses import dataclass, field
328
from datetime import datetime
329
from typing import Dict, Any
330
from omegaconf import OmegaConf
331
332
def get_timestamp():
333
return datetime.now().isoformat()
334
335
@dataclass
336
class Config:
337
id: str = field(default_factory=lambda: f"config-{get_timestamp()}")
338
metadata: Dict[str, Any] = field(default_factory=dict)
339
created_at: str = field(default_factory=get_timestamp)
340
341
config = OmegaConf.structured(Config)
342
print(config.id) # "config-2023-10-15T14:30:00.123456"
343
print(config.created_at) # "2023-10-15T14:30:00.123456"
344
```
345
346
### Struct Mode with Structured Configs
347
348
```python
349
from dataclasses import dataclass
350
from omegaconf import OmegaConf
351
352
@dataclass
353
class StrictConfig:
354
allowed_field: str = "value"
355
356
# Structured configs are automatically in struct mode
357
config = OmegaConf.structured(StrictConfig)
358
359
try:
360
config.new_field = "not allowed" # Raises exception
361
except Exception:
362
print("Cannot add fields to structured config")
363
364
# Use open_dict to temporarily allow new fields
365
with OmegaConf.open_dict(config):
366
config.temporary_field = "allowed"
367
368
print(config.temporary_field) # "allowed"
369
```