@@ -18,14 +18,13 @@ from pydantic import (
18
18
AliasChoices,
19
19
AmqpDsn,
20
20
BaseModel,
21
- ConfigDict,
22
21
Field,
23
22
ImportString,
24
23
PostgresDsn,
25
24
RedisDsn,
26
25
)
27
26
28
- from pydantic_settings import BaseSettings
27
+ from pydantic_settings import BaseSettings, SettingsConfigDict
29
28
30
29
31
30
class SubModel (BaseModel ):
@@ -34,17 +33,16 @@ class SubModel(BaseModel):
34
33
35
34
36
35
class Settings (BaseSettings ):
37
- auth_key: str = Field(validation_alias = ' my_auth_key' )
38
- api_key: str = Field(validation_alias = ' my_api_key' )
36
+ auth_key: str = Field(validation_alias = ' my_auth_key' ) # (1)!
39
37
40
38
redis_dsn: RedisDsn = Field(
41
39
' redis://user:pass@localhost:6379/1' ,
42
- validation_alias = AliasChoices(' service_redis_dsn' , ' redis_url' ),
40
+ validation_alias = AliasChoices(' service_redis_dsn' , ' redis_url' ), # (2)!
43
41
)
44
42
pg_dsn: PostgresDsn = ' postgres://user:pass@localhost:5432/foobar'
45
43
amqp_dsn: AmqpDsn = ' amqp://user:pass@localhost:5672/'
46
44
47
- special_function: ImportString[Callable[[Any], Any]] = ' math.cos'
45
+ special_function: ImportString[Callable[[Any], Any]] = ' math.cos' # (3)!
48
46
49
47
# to override domains:
50
48
# export my_prefix_domains='["foo.com", "bar.com"]'
@@ -54,14 +52,13 @@ class Settings(BaseSettings):
54
52
# export my_prefix_more_settings='{"foo": "x", "apple": 1}'
55
53
more_settings: SubModel = SubModel()
56
54
57
- model_config = ConfigDict (env_prefix = ' my_prefix_' ) # defaults to no prefix, i.e. ""
55
+ model_config = SettingsConfigDict (env_prefix = ' my_prefix_' ) # (4)!
58
56
59
57
60
58
print (Settings().model_dump())
61
59
"""
62
60
{
63
61
'auth_key': 'xxx',
64
- 'api_key': 'xxx',
65
62
'redis_dsn': Url('redis://user:pass@localhost:6379/1'),
66
63
'pg_dsn': Url('postgres://user:pass@localhost:5432/foobar'),
67
64
'amqp_dsn': Url('amqp://user:pass@localhost:5672/'),
@@ -72,68 +69,133 @@ print(Settings().model_dump())
72
69
"""
73
70
```
74
71
75
- ## Environment variable names
72
+ 1 . The environment variable name is overridden using ` validation_alias ` . In this case, the environment variable
73
+ ` my_auth_key ` will be read instead of ` auth_key ` .
74
+
75
+ Check the [ ` Field ` documentation] ( /usage/fields/ ) for more information.
76
+
77
+ 2 . The ` AliasChoices ` class allows to have multiple environment variable names for a single field.
78
+ The first environment variable that is found will be used.
79
+
80
+ Check the [ ` AliasChoices ` ] ( /usage/fields/#aliaspath-and-aliaschoices ) for more information.
76
81
77
- The following rules are used to determine which environment variable(s) are read for a given field:
82
+ 3 . The ` ImportString ` class allows to import an object from a string.
83
+ In this case, the environment variable ` special_function ` will be read and the function ` math.cos ` will be imported.
78
84
79
- * By default, the environment variable name is built by concatenating the prefix and field name.
80
- * For example, to override ` special_function ` above, you could use:
85
+ 4 . The ` env_prefix ` config setting allows to set a prefix for all environment variables.
81
86
82
- export my_prefix_special_function='foo.bar'
87
+ Check the [ Environment variable names documentation ] ( #environment-variable-names ) for more information.
83
88
84
- * Note : The default prefix is an empty string.
89
+ ## Environment variable names
85
90
86
- * Custom environment variable names can be set like:
87
- * ` Field(validation_alias=...) ` (see ` api_key ` and ` redis_dsn ` above)
88
- * When specifying custom environment variable names, either a string, ` AliasChoices ` , ` AliasPath ` my be provided.
89
- * ` env_prefix ` is not considered.
90
- * When specifying a ` AliasChoices ` , order matters: the first detected value is used.
91
- * For example, for ` redis_dsn ` above, ` service_redis_dsn ` would take precedence over ` redis_url ` .
91
+ By default, the environment variable name is the same as the field name.
92
92
93
- Case-sensitivity can be turned on through the ` model_config ` :
93
+ You can change the prefix for all environment variables by setting the ` env_prefix ` config setting :
94
94
95
95
``` py
96
- from pydantic import ConfigDict
96
+ from pydantic_settings import BaseSettings, SettingsConfigDict
97
+
98
+
99
+ class Settings (BaseSettings ):
100
+ model_config = SettingsConfigDict(env_prefix = ' my_prefix_' )
101
+
102
+ auth_key: str = ' xxx' # will be read from `my_prefix_auth_key`
103
+ ```
104
+
105
+ !!! note
106
+ The default ` env_prefix ` is ` '' ` (empty string).
107
+
108
+ If you want to change the environment variable name for a single field, you can use an alias.
109
+
110
+ There are two ways to do this:
111
+
112
+ * Using ` Field(alias=...) ` (see ` api_key ` above)
113
+ * Using ` Field(validation_alias=...) ` (see ` auth_key ` above)
114
+
115
+ Check the [ ` Field ` aliases documentation] ( /usage/fields#field-aliases ) for more information about aliases.
97
116
98
- from pydantic_settings import BaseSettings
117
+ ### Case-sensitivity
118
+
119
+ By default, environment variable names are case-insensitive.
120
+
121
+ If you want to make environment variable names case-sensitive, you can set the ` case_sensitive ` config setting:
122
+
123
+ ``` py
124
+ from pydantic_settings import BaseSettings, SettingsConfigDict
99
125
100
126
101
127
class Settings (BaseSettings ):
102
- model_config = ConfigDict (case_sensitive = True )
128
+ model_config = SettingsConfigDict (case_sensitive = True )
103
129
104
130
redis_host: str = ' localhost'
105
131
```
106
132
107
133
When ` case_sensitive ` is ` True ` , the environment variable names must match field names (optionally with a prefix),
108
- so in this example
109
- ` redis_host ` could only be modified via ` export redis_host ` . If you want to name environment variables
134
+ so in this example ` redis_host ` could only be modified via ` export redis_host ` . If you want to name environment variables
110
135
all upper-case, you should name attribute all upper-case too. You can still name environment variables anything
111
136
you like through ` Field(validation_alias=...) ` .
112
137
113
- In Pydantic ** v1** ` case_sensitive ` is ` False ` by default and all variable names are converted to lower-case internally.
114
- If you want to define upper-case variable names on nested models like ` SubModel ` you have to
115
- set ` case_sensitive=True ` to disable this behaviour.
138
+ In case of nested models, the ` case_sensitive ` setting will be applied to all nested models.
139
+
140
+ ``` py
141
+ import os
142
+
143
+ from pydantic import ValidationError
144
+
145
+ from pydantic_settings import BaseSettings, SettingsConfigDict
146
+
147
+
148
+ class RedisSettings (BaseSettings ):
149
+ host: str
150
+ port: int
151
+
152
+
153
+ class Settings (BaseSettings ):
154
+ model_config = SettingsConfigDict(case_sensitive = True )
155
+
156
+ redis: RedisSettings
157
+
158
+
159
+ os.environ[' redis' ] = ' {"host": "localhost", "port": 6379}'
160
+ print (Settings().model_dump())
161
+ # > {'redis': {'host': 'localhost', 'port': 6379}}
162
+ os.environ[' redis' ] = ' {"HOST": "localhost", "port": 6379}' # (1)!
163
+ try :
164
+ Settings()
165
+ except ValidationError as e:
166
+ print (e)
167
+ """
168
+ 2 validation errors for RedisSettings
169
+ host
170
+ Field required [type=missing, input_value={'HOST': 'localhost', 'port': 6379}, input_type=dict]
171
+ For further information visit https://errors.pydantic.dev/2/v/missing
172
+ HOST
173
+ Extra inputs are not permitted [type=extra_forbidden, input_value='localhost', input_type=str]
174
+ For further information visit https://errors.pydantic.dev/2/v/extra_forbidden
175
+ """
176
+ ```
177
+
178
+ 1 . Note that the ` host ` field is not found because the environment variable name is ` HOST ` (all upper-case).
116
179
117
180
!!! note
118
181
On Windows, Python's ` os ` module always treats environment variables as case-insensitive, so the
119
182
` case_sensitive ` config setting will have no effect - settings will always be updated ignoring case.
120
183
121
184
## Parsing environment variable values
122
185
123
- For most simple field types (such as ` int ` , ` float ` , ` str ` , etc.),
124
- the environment variable value is parsed the same way it would
125
- be if passed directly to the initialiser (as a string).
186
+ For most simple field types (such as ` int ` , ` float ` , ` str ` , etc.), the environment variable value is parsed
187
+ the same way it would be if passed directly to the initialiser (as a string).
126
188
127
- Complex types like ` list ` , ` set ` , ` dict ` , and sub-models are populated from the environment
128
- by treating the environment variable's value as a JSON-encoded string.
189
+ Complex types like ` list ` , ` set ` , ` dict ` , and sub-models are populated from the environment by treating the
190
+ environment variable's value as a JSON-encoded string.
129
191
130
192
Another way to populate nested complex variables is to configure your model with the ` env_nested_delimiter `
131
- config setting, then use an env variable with a name pointing to the nested module fields.
193
+ config setting, then use an environment variable with a name pointing to the nested module fields.
132
194
What it does is simply explodes your variable into nested models or dicts.
133
195
So if you define a variable ` FOO__BAR__BAZ=123 ` it will convert it into ` FOO={'BAR': {'BAZ': 123}} `
134
196
If you have multiple variables with the same structure they will be merged.
135
197
136
- With the following environment variables:
198
+ As an example, given the following environment variables:
137
199
``` bash
138
200
# your environment
139
201
export V0=0
@@ -143,12 +205,12 @@ export SUB_MODEL__V3=3
143
205
export SUB_MODEL__DEEP__V4=v4
144
206
```
145
207
146
- You could load a settings module thus :
208
+ You could load them into the following settings model :
147
209
148
210
``` py
149
- from pydantic import BaseModel, ConfigDict
211
+ from pydantic import BaseModel
150
212
151
- from pydantic_settings import BaseSettings
213
+ from pydantic_settings import BaseSettings, SettingsConfigDict
152
214
153
215
154
216
class DeepSubModel (BaseModel ):
@@ -163,7 +225,7 @@ class SubModel(BaseModel):
163
225
164
226
165
227
class Settings (BaseSettings ):
166
- model_config = ConfigDict (env_nested_delimiter = ' __' )
228
+ model_config = SettingsConfigDict (env_nested_delimiter = ' __' )
167
229
168
230
v0: str
169
231
sub_model: SubModel
@@ -234,17 +296,12 @@ print(Settings().model_dump())
234
296
235
297
## Dotenv (.env) support
236
298
237
- !!! note
238
- dotenv file parsing requires [ python-dotenv] ( https://pypi.org/project/python-dotenv/ ) to be installed.
239
- This can be done with either ` pip install python-dotenv ` or ` pip install pydantic[dotenv] ` .
240
-
241
299
Dotenv files (generally named ` .env ` ) are a common pattern that make it easy to use environment variables in a
242
300
platform-independent manner.
243
301
244
- A dotenv file follows the same general principles of all environment variables,
245
- and looks something like:
302
+ A dotenv file follows the same general principles of all environment variables, and it looks like this:
246
303
247
- ``` bash
304
+ ``` bash title=".env"
248
305
# ignore comment
249
306
ENVIRONMENT=" production"
250
307
REDIS_ADDRESS=localhost:6379
@@ -254,18 +311,15 @@ MY_VAR='Hello world'
254
311
255
312
Once you have your ` .env ` file filled with variables, * pydantic* supports loading it in two ways:
256
313
257
- ** 1. ** setting ` env_file ` (and ` env_file_encoding ` if you don't want the default encoding of your OS) on ` model_config `
258
- in a ` BaseSettings ` class:
314
+ 1 . Setting the ` env_file ` (and ` env_file_encoding ` if you don't want the default encoding of your OS) on ` model_config `
315
+ in the ` BaseSettings ` class:
259
316
260
317
``` py test="skip" lint="skip"
261
318
class Settings (BaseSettings ):
262
- model_config = ConfigDict(env_file = ' .env' , env_file_encoding = ' utf-8' )
263
-
264
- ...
265
-
319
+ model_config = SettingsConfigDict(env_file = ' .env' , env_file_encoding = ' utf-8' )
266
320
```
267
321
268
- ** 2. ** instantiating a ` BaseSettings ` derived class with the ` _env_file ` keyword argument
322
+ 2 . Instantiating the ` BaseSettings ` derived class with the ` _env_file ` keyword argument
269
323
(and the ` _env_file_encoding ` if needed):
270
324
271
325
``` py test="skip" lint="skip"
@@ -287,23 +341,15 @@ Passing a file path via the `_env_file` keyword argument on instantiation (metho
287
341
the value (if any) set on the ` model_config ` class. If the above snippets were used in conjunction, ` prod.env ` would be loaded
288
342
while ` .env ` would be ignored.
289
343
290
- If you need to load multiple dotenv files, you can pass the file paths as a ` list ` or ` tuple ` .
291
-
292
- Later files in the list/tuple will take priority over earlier files.
293
-
294
- ``` py
295
- from pydantic import ConfigDict
296
-
297
- from pydantic_settings import BaseSettings
298
-
344
+ If you need to load multiple dotenv files, you can pass multiple file paths as a tuple or list. The files will be
345
+ loaded in order, with each file overriding the previous one.
299
346
347
+ ``` py test="skip" lint="skip"
300
348
class Settings (BaseSettings ):
301
- model_config = ConfigDict (
349
+ model_config = SettingsConfigDict (
302
350
# `.env.prod` takes priority over `.env`
303
351
env_file = (' .env' , ' .env.prod' )
304
352
)
305
-
306
- ...
307
353
```
308
354
309
355
You can also use the keyword argument override to tell Pydantic not to load any file at all (even if one is set in
@@ -317,32 +363,29 @@ Pydantic settings consider `extra` config in case of dotenv file. It means if yo
317
363
on ` model_config ` and your dotenv file contains an entry for a field that is not defined in settings model,
318
364
it will raise ` ValidationError ` in settings construction.
319
365
320
- ## Secret Support
366
+ ## Secrets
321
367
322
368
Placing secret values in files is a common pattern to provide sensitive configuration to an application.
323
369
324
370
A secret file follows the same principal as a dotenv file except it only contains a single value and the file name
325
371
is used as the key. A secret file will look like the following:
326
372
327
- ` /var/run/database_password ` :
328
- ```
373
+ ``` title="/var/run/database_password"
329
374
super_secret_database_password
330
375
```
331
376
332
377
Once you have your secret files, * pydantic* supports loading it in two ways:
333
378
334
- ** 1. ** setting ` secrets_dir ` on ` model_config ` in a ` BaseSettings ` class to the directory where your secret files are stored:
379
+ 1 . Setting the ` secrets_dir ` on ` model_config ` in a ` BaseSettings ` class to the directory where your secret files are stored.
335
380
336
381
``` py test="skip" lint="skip"
337
382
class Settings (BaseSettings ):
338
- model_config = ConfigDict (secrets_dir = ' /var/run' )
383
+ model_config = SettingsConfigDict (secrets_dir = ' /var/run' )
339
384
340
- ...
341
385
database_password: str
342
-
343
386
```
344
387
345
- ** 2. ** instantiating a ` BaseSettings ` derived class with the ` _secrets_dir ` keyword argument:
388
+ 2 . Instantiating the ` BaseSettings ` derived class with the ` _secrets_dir ` keyword argument:
346
389
347
390
``` py test="skip" lint="skip"
348
391
settings = Settings(_secrets_dir = ' /var/run' )
@@ -365,16 +408,18 @@ To use these secrets in a *pydantic* application the process is simple. More inf
365
408
and using secrets in Docker see the official
366
409
[ Docker documentation] ( https://docs.docker.com/engine/reference/commandline/secret/ ) .
367
410
368
- First, define your Settings
411
+ First, define your ` Settings ` class with a ` SettingsConfigDict ` that specifies the secrets directory.
412
+
369
413
``` py test="skip" lint="skip"
370
414
class Settings (BaseSettings ):
371
- model_config = ConfigDict (secrets_dir = ' /run/secrets' )
415
+ model_config = SettingsConfigDict (secrets_dir = ' /run/secrets' )
372
416
373
417
my_secret_data: str
374
418
```
419
+
375
420
!!! note
376
- By default Docker uses ` /run/secrets ` as the target mount point. If you want to use a different location, change
377
- ` Config.secrets_dir ` accordingly.
421
+ By default [ Docker uses ` /run/secrets ` ] ( https://docs.docker.com/engine/swarm/secrets/#how-docker-manages-secrets )
422
+ as the target mount point. If you want to use a different location, change ` Config.secrets_dir ` accordingly.
378
423
379
424
Then, create your secret via the Docker CLI
380
425
``` bash
@@ -450,10 +495,13 @@ import json
450
495
from pathlib import Path
451
496
from typing import Any, Dict, Tuple, Type
452
497
453
- from pydantic import ConfigDict
454
498
from pydantic.fields import FieldInfo
455
499
456
- from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
500
+ from pydantic_settings import (
501
+ BaseSettings,
502
+ PydanticBaseSettingsSource,
503
+ SettingsConfigDict,
504
+ )
457
505
458
506
459
507
class JsonConfigSettingsSource (PydanticBaseSettingsSource ):
@@ -497,7 +545,7 @@ class JsonConfigSettingsSource(PydanticBaseSettingsSource):
497
545
498
546
499
547
class Settings (BaseSettings ):
500
- model_config = ConfigDict (env_file_encoding = ' utf-8' )
548
+ model_config = SettingsConfigDict (env_file_encoding = ' utf-8' )
501
549
502
550
foobar: str
503
551
0 commit comments