@@ -16,14 +16,15 @@ from typing import Any, Callable, Set
16
16
17
17
from pydantic import (
18
18
AliasChoices,
19
+ AmqpDsn,
19
20
BaseModel,
20
21
ConfigDict,
22
+ Field,
21
23
ImportString,
22
- RedisDsn,
23
24
PostgresDsn,
24
- AmqpDsn,
25
- Field,
25
+ RedisDsn,
26
26
)
27
+
27
28
from pydantic_settings import BaseSettings
28
29
29
30
@@ -38,7 +39,7 @@ class Settings(BaseSettings):
38
39
39
40
redis_dsn: RedisDsn = Field(
40
41
' redis://user:pass@localhost:6379/1' ,
41
- validation_alias = AliasChoices(' service_redis_dsn' , ' redis_url' )
42
+ validation_alias = AliasChoices(' service_redis_dsn' , ' redis_url' ),
42
43
)
43
44
pg_dsn: PostgresDsn = ' postgres://user:pass@localhost:5432/foobar'
44
45
amqp_dsn: AmqpDsn = ' amqp://user:pass@localhost:5672/'
@@ -53,7 +54,8 @@ class Settings(BaseSettings):
53
54
# export my_prefix_more_settings='{"foo": "x", "apple": 1}'
54
55
more_settings: SubModel = SubModel()
55
56
56
- model_config = ConfigDict(env_prefix = ' my_prefix_' ) # defaults to no prefix, i.e. ""
57
+ model_config = ConfigDict(env_prefix = ' my_prefix_' ) # defaults to no prefix, i.e. ""
58
+
57
59
58
60
print (Settings().model_dump())
59
61
"""
@@ -63,7 +65,7 @@ print(Settings().model_dump())
63
65
'redis_dsn': Url('redis://user:pass@localhost:6379/1'),
64
66
'pg_dsn': Url('postgres://user:pass@localhost:5432/foobar'),
65
67
'amqp_dsn': Url('amqp://user:pass@localhost:5672/'),
66
- 'special_function': <built-in function cos> ,
68
+ 'special_function': math. cos,
67
69
'domains': set(),
68
70
'more_settings': {'foo': 'bar', 'apple': 1},
69
71
}
@@ -92,6 +94,7 @@ Case-sensitivity can be turned on through the `model_config`:
92
94
93
95
``` py
94
96
from pydantic import ConfigDict
97
+
95
98
from pydantic_settings import BaseSettings
96
99
97
100
@@ -144,6 +147,7 @@ You could load a settings module thus:
144
147
145
148
``` py
146
149
from pydantic import BaseModel, ConfigDict
150
+
147
151
from pydantic_settings import BaseSettings
148
152
149
153
@@ -169,12 +173,7 @@ print(Settings().model_dump())
169
173
"""
170
174
{
171
175
'v0': '0',
172
- 'sub_model': {
173
- 'v1': 'json-1',
174
- 'v2': b'nested-2',
175
- 'v3': 3,
176
- 'deep': {'v4': 'v4'},
177
- },
176
+ 'sub_model': {'v1': 'json-1', 'v2': b'nested-2', 'v3': 3, 'deep': {'v4': 'v4'}},
178
177
}
179
178
"""
180
179
```
@@ -196,11 +195,18 @@ import os
196
195
from typing import Any, List, Tuple, Type
197
196
198
197
from pydantic.fields import FieldInfo
199
- from pydantic_settings import BaseSettings, EnvSettingsSource, PydanticBaseSettingsSource
198
+
199
+ from pydantic_settings import (
200
+ BaseSettings,
201
+ EnvSettingsSource,
202
+ PydanticBaseSettingsSource,
203
+ )
200
204
201
205
202
206
class MyCustomSource (EnvSettingsSource ):
203
- def prepare_field_value (self , field_name : str , field : FieldInfo, value : Any, value_is_complex : bool ) -> Any:
207
+ def prepare_field_value (
208
+ self , field_name : str , field : FieldInfo, value : Any, value_is_complex : bool
209
+ ) -> Any:
204
210
if field_name == ' numbers' :
205
211
return [int (x) for x in value.split(' ,' )]
206
212
return json.loads(value)
@@ -251,7 +257,7 @@ Once you have your `.env` file filled with variables, *pydantic* supports loadin
251
257
** 1.** setting ` env_file ` (and ` env_file_encoding ` if you don't want the default encoding of your OS) on ` model_config `
252
258
in a ` BaseSettings ` class:
253
259
254
- ``` py
260
+ ``` py test="skip" lint="skip"
255
261
class Settings (BaseSettings ):
256
262
...
257
263
@@ -261,7 +267,7 @@ class Settings(BaseSettings):
261
267
** 2.** instantiating a ` BaseSettings ` derived class with the ` _env_file ` keyword argument
262
268
(and the ` _env_file_encoding ` if needed):
263
269
264
- ``` py
270
+ ``` py test="skip" lint="skip"
265
271
settings = Settings(_env_file = ' prod.env' , _env_file_encoding = ' utf-8' )
266
272
```
267
273
@@ -285,12 +291,18 @@ If you need to load multiple dotenv files, you can pass the file paths as a `lis
285
291
Later files in the list/tuple will take priority over earlier files.
286
292
287
293
``` py
288
- from pydantic import BaseSettings
294
+ from pydantic import ConfigDict
295
+
296
+ from pydantic_settings import BaseSettings
297
+
289
298
290
299
class Settings (BaseSettings ):
291
300
...
292
301
293
- model_config = ConfigDict(env_file = (' .env' , ' .env.prod' )) # `.env.prod` takes priority over `.env`
302
+ model_config = ConfigDict(
303
+ # `.env.prod` takes priority over `.env`
304
+ env_file = (' .env' , ' .env.prod' )
305
+ )
294
306
```
295
307
296
308
You can also use the keyword argument override to tell Pydantic not to load any file at all (even if one is set in
@@ -320,7 +332,7 @@ Once you have your secret files, *pydantic* supports loading it in two ways:
320
332
321
333
** 1.** setting ` secrets_dir ` on ` model_config ` in a ` BaseSettings ` class to the directory where your secret files are stored:
322
334
323
- ``` py
335
+ ``` py test="skip" lint="skip"
324
336
class Settings (BaseSettings ):
325
337
...
326
338
database_password: str
@@ -330,7 +342,7 @@ class Settings(BaseSettings):
330
342
331
343
** 2.** instantiating a ` BaseSettings ` derived class with the ` _secrets_dir ` keyword argument:
332
344
333
- ``` py
345
+ ``` py test="skip" lint="skip"
334
346
settings = Settings(_secrets_dir = ' /var/run' )
335
347
```
336
348
@@ -352,7 +364,7 @@ and using secrets in Docker see the official
352
364
[ Docker documentation] ( https://docs.docker.com/engine/reference/commandline/secret/ ) .
353
365
354
366
First, define your Settings
355
- ``` py
367
+ ``` py test="skip" lint="skip"
356
368
class Settings (BaseSettings ):
357
369
my_secret_data: str
358
370
@@ -399,7 +411,9 @@ The order of the returned callables decides the priority of inputs; first item i
399
411
400
412
``` py
401
413
from typing import Tuple, Type
414
+
402
415
from pydantic import PostgresDsn
416
+
403
417
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
404
418
405
419
@@ -436,6 +450,7 @@ from typing import Any, Dict, Tuple, Type
436
450
437
451
from pydantic import ConfigDict
438
452
from pydantic.fields import FieldInfo
453
+
439
454
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
440
455
441
456
@@ -448,22 +463,31 @@ class JsonConfigSettingsSource(PydanticBaseSettingsSource):
448
463
when reading `config.json`
449
464
"""
450
465
451
- def get_field_value (self , field : FieldInfo, field_name : str ) -> Tuple[Any, str , bool ]:
466
+ def get_field_value (
467
+ self , field : FieldInfo, field_name : str
468
+ ) -> Tuple[Any, str , bool ]:
452
469
encoding = self .config.get(' env_file_encoding' )
453
- file_content_json = json.loads(Path(' config.json' ).read_text(encoding))
470
+ file_content_json = json.loads(
471
+ Path(' tests/example_test_config.json' ).read_text(encoding)
472
+ )
454
473
fiel_value = file_content_json.get(field_name)
455
474
return fiel_value, field_name, False
456
475
457
-
458
- def prepare_field_value (self , field_name : str , field : FieldInfo, value : Any, value_is_complex : bool ) -> Any:
476
+ def prepare_field_value (
477
+ self , field_name : str , field : FieldInfo, value : Any, value_is_complex : bool
478
+ ) -> Any:
459
479
return value
460
480
461
481
def __call__ (self ) -> Dict[str , Any]:
462
482
d: Dict[str , Any] = {}
463
483
464
484
for field_name, field in self .settings_cls.model_fields.items():
465
- field_value, field_key, value_is_complex = self .get_field_value(field, field_name)
466
- field_value = self .prepare_field_value(field_name, field, field_value, value_is_complex)
485
+ field_value, field_key, value_is_complex = self .get_field_value(
486
+ field, field_name
487
+ )
488
+ field_value = self .prepare_field_value(
489
+ field_name, field, field_value, value_is_complex
490
+ )
467
491
if field_value is not None :
468
492
d[field_key] = field_value
469
493
@@ -493,7 +517,7 @@ class Settings(BaseSettings):
493
517
494
518
495
519
print (Settings())
496
- # > foobar='spam '
520
+ # > foobar='test '
497
521
```
498
522
499
523
### Removing sources
@@ -503,6 +527,8 @@ You might also want to disable a source:
503
527
``` py
504
528
from typing import Tuple, Type
505
529
530
+ from pydantic import ValidationError
531
+
506
532
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
507
533
508
534
@@ -522,6 +548,14 @@ class Settings(BaseSettings):
522
548
return env_settings, file_secret_settings
523
549
524
550
525
- print (Settings(my_api_key = ' this is ignored' ))
526
- # requires: `MY_API_KEY` env variable to be set, e.g. `export MY_API_KEY=xxx`
551
+ try :
552
+ Settings(my_api_key = ' this is ignored' )
553
+ except ValidationError as exc_info:
554
+ print (exc_info)
555
+ """
556
+ 1 validation error for Settings
557
+ my_api_key
558
+ Field required [type=missing, input_value={}, input_type=dict]
559
+ For further information visit https://errors.pydantic.dev/2/v/missing
560
+ """
527
561
```
0 commit comments