3333from copy import deepcopy
3434from enum import Enum
3535from pathlib import Path
36- from typing import Any , Dict , Iterator , Literal , Optional , Tuple , Union
36+ from typing import Any , Iterator , Literal
3737
3838from pydantic import Field , SecretStr , field_validator
3939from pydantic_settings import BaseSettings , SettingsConfigDict
5858logger = logging .getLogger (__name__ .split ("." )[0 ])
5959
6060
61- def find_config_file (start : Optional [ Path ] = None ) -> Optional [ Path ] :
61+ def find_config_file (start : Path | None = None ) -> Path | None :
6262 """
6363 Search for datajoint.json in current and parent directories.
6464
@@ -89,7 +89,7 @@ def find_config_file(start: Optional[Path] = None) -> Optional[Path]:
8989 current = current .parent
9090
9191
92- def find_secrets_dir (config_path : Optional [ Path ] = None ) -> Optional [ Path ] :
92+ def find_secrets_dir (config_path : Path | None = None ) -> Path | None :
9393 """
9494 Find the secrets directory.
9595
@@ -116,7 +116,7 @@ def find_secrets_dir(config_path: Optional[Path] = None) -> Optional[Path]:
116116 return None
117117
118118
119- def read_secret_file (secrets_dir : Optional [ Path ] , name : str ) -> Optional [ str ] :
119+ def read_secret_file (secrets_dir : Path | None , name : str ) -> str | None :
120120 """
121121 Read a secret value from a file in the secrets directory.
122122
@@ -148,19 +148,19 @@ class DatabaseSettings(BaseSettings):
148148 )
149149
150150 host : str = Field (default = "localhost" , validation_alias = "DJ_HOST" )
151- user : Optional [ str ] = Field (default = None , validation_alias = "DJ_USER" )
152- password : Optional [ SecretStr ] = Field (default = None , validation_alias = "DJ_PASS" )
151+ user : str | None = Field (default = None , validation_alias = "DJ_USER" )
152+ password : SecretStr | None = Field (default = None , validation_alias = "DJ_PASS" )
153153 port : int = Field (default = 3306 , validation_alias = "DJ_PORT" )
154154 reconnect : bool = True
155- use_tls : Optional [ bool ] = None
155+ use_tls : bool | None = None
156156
157157
158158class ConnectionSettings (BaseSettings ):
159159 """Connection behavior settings."""
160160
161161 model_config = SettingsConfigDict (extra = "forbid" , validate_assignment = True )
162162
163- init_function : Optional [ str ] = None
163+ init_function : str | None = None
164164 charset : str = "" # pymysql uses '' as default
165165
166166
@@ -184,8 +184,8 @@ class ExternalSettings(BaseSettings):
184184 validate_assignment = True ,
185185 )
186186
187- aws_access_key_id : Optional [ str ] = Field (default = None , validation_alias = "DJ_AWS_ACCESS_KEY_ID" )
188- aws_secret_access_key : Optional [ SecretStr ] = Field (default = None , validation_alias = "DJ_AWS_SECRET_ACCESS_KEY" )
187+ aws_access_key_id : str | None = Field (default = None , validation_alias = "DJ_AWS_ACCESS_KEY_ID" )
188+ aws_secret_access_key : SecretStr | None = Field (default = None , validation_alias = "DJ_AWS_SECRET_ACCESS_KEY" )
189189
190190
191191class Config (BaseSettings ):
@@ -226,18 +226,18 @@ class Config(BaseSettings):
226226 fetch_format : Literal ["array" , "frame" ] = "array"
227227 enable_python_native_blobs : bool = True
228228 add_hidden_timestamp : bool = False
229- filepath_checksum_size_limit : Optional [ int ] = None
229+ filepath_checksum_size_limit : int | None = None
230230
231231 # External stores configuration
232- stores : Dict [str , Dict [str , Any ]] = Field (default_factory = dict )
232+ stores : dict [str , dict [str , Any ]] = Field (default_factory = dict )
233233
234234 # Cache paths
235- cache : Optional [ Path ] = None
236- query_cache : Optional [ Path ] = None
235+ cache : Path | None = None
236+ query_cache : Path | None = None
237237
238238 # Internal: track where config was loaded from
239- _config_path : Optional [ Path ] = None
240- _secrets_dir : Optional [ Path ] = None
239+ _config_path : Path | None = None
240+ _secrets_dir : Path | None = None
241241
242242 @field_validator ("loglevel" , mode = "after" )
243243 @classmethod
@@ -248,13 +248,13 @@ def set_logger_level(cls, v: str) -> str:
248248
249249 @field_validator ("cache" , "query_cache" , mode = "before" )
250250 @classmethod
251- def convert_path (cls , v : Any ) -> Optional [ Path ] :
251+ def convert_path (cls , v : Any ) -> Path | None :
252252 """Convert string paths to Path objects."""
253253 if v is None :
254254 return None
255255 return Path (v ) if not isinstance (v , Path ) else v
256256
257- def get_store_spec (self , store : str ) -> Dict [str , Any ]:
257+ def get_store_spec (self , store : str ) -> dict [str , Any ]:
258258 """
259259 Get configuration for an external store.
260260
@@ -279,11 +279,11 @@ def get_store_spec(self, store: str) -> Dict[str, Any]:
279279 raise DataJointError (f'Missing or invalid protocol in config.stores["{ store } "]' )
280280
281281 # Define required and allowed keys by protocol
282- required_keys : Dict [str , Tuple [str , ...]] = {
282+ required_keys : dict [str , tuple [str , ...]] = {
283283 "file" : ("protocol" , "location" ),
284284 "s3" : ("protocol" , "endpoint" , "bucket" , "access_key" , "secret_key" , "location" ),
285285 }
286- allowed_keys : Dict [str , Tuple [str , ...]] = {
286+ allowed_keys : dict [str , tuple [str , ...]] = {
287287 "file" : ("protocol" , "location" , "subfolding" , "stage" ),
288288 "s3" : (
289289 "protocol" ,
@@ -311,7 +311,7 @@ def get_store_spec(self, store: str) -> Dict[str, Any]:
311311
312312 return spec
313313
314- def load (self , filename : Union [ str , Path ] ) -> None :
314+ def load (self , filename : str | Path ) -> None :
315315 """
316316 Load settings from a JSON file.
317317
@@ -330,7 +330,7 @@ def load(self, filename: Union[str, Path]) -> None:
330330 self ._update_from_flat_dict (data )
331331 self ._config_path = filepath
332332
333- def _update_from_flat_dict (self , data : Dict [str , Any ]) -> None :
333+ def _update_from_flat_dict (self , data : dict [str , Any ]) -> None :
334334 """Update settings from a flat dict with dot notation keys."""
335335 for key , value in data .items ():
336336 parts = key .split ("." )
0 commit comments