2727from collections import abc
2828from pathlib import Path
2929from typing import (
30- Any ,
3130 Iterable ,
3231 Iterator ,
3332 List ,
4140)
4241
4342from .path import environment_paths
44- from .read import EnvReader , NestedMapping , PrimitiveValue
43+ from .read import EnvReader
44+ from .types import LeafValue , NestedMapping , check_valid_leaf_value
4545
4646logger = logging .getLogger (__name__ )
4747
4848DEBUG_MODE = os .environ .get ("CLRENV_DEBUG" , "" ).lower () in ("true" , "1" )
4949
5050# Access to an attribute might return a primitive or if it is not a leaf node
5151# another SubClrEnv.
52- Value = Union [PrimitiveValue , "SubClrEnv" ]
52+ Value = Union [LeafValue , "SubClrEnv" ]
5353
5454
5555class SubClrEnv (abc .MutableMapping ):
@@ -90,10 +90,10 @@ def __getattr__(self, key: str) -> Value:
9090 except KeyError as e :
9191 raise AttributeError (str (e ))
9292
93- def __setitem__ (self , key : str , value : PrimitiveValue ):
93+ def __setitem__ (self , key : str , value : LeafValue ):
9494 self ._root .set_runtime_override (self ._sub_key_path (key ), value )
9595
96- def __setattr__ (self , key : str , value : PrimitiveValue ):
96+ def __setattr__ (self , key : str , value : LeafValue ):
9797 """Sets a runtime override as an attribute."""
9898 # Internal fields are prefixed with a _ and should be treated normally.
9999 if key .startswith ("_" ):
@@ -145,7 +145,7 @@ def _sub_keys(self) -> Set[str]:
145145 subkeys .add (env_var .split ("__" )[0 ].lower ())
146146 return subkeys
147147
148- def _evaluate_key (self , key : str ) -> Union [PrimitiveValue , Mapping , None ]:
148+ def _evaluate_key (self , key : str ) -> Union [LeafValue , Mapping , None ]:
149149 """Returns the stored value for the given key.
150150
151151 There are three potential sources of data (in order of priority):
@@ -219,7 +219,7 @@ def __init__(self, paths: Optional[List[Path]] = None):
219219 # efficent lookup for subkeys.
220220 # env.a.b.c = 'd' ==> _runtime_overrides = {('a', 'b'): {'c': 'd'}}
221221 self ._runtime_overrides : MutableMapping [
222- Tuple [str , ...], MutableMapping [str , PrimitiveValue ]
222+ Tuple [str , ...], MutableMapping [str , LeafValue ]
223223 ] = {}
224224
225225 def _make_env (self ) -> NestedMapping :
@@ -230,7 +230,9 @@ def clear_runtime_overrides(self):
230230 """Clear all runtime overrides."""
231231 self ._runtime_overrides .clear ()
232232
233- def set_runtime_override (self , key_path : Sequence [str ], value : PrimitiveValue ):
233+ def set_runtime_override (
234+ self , key_path : Union [str , Sequence [str ]], value : LeafValue
235+ ):
234236 """Sets a runtime override.
235237
236238 Only do this in tests and ideally use unittest.mock.patch or monkeypath.setattr
@@ -239,20 +241,19 @@ def set_runtime_override(self, key_path: Sequence[str], value: PrimitiveValue):
239241 Notice that this method is only on the root node."""
240242 if not key_path :
241243 raise ValueError ("key_path can not be empty." )
244+ # No support for nested runtime overrides. Only allow primitives.
245+ check_valid_leaf_value (key_path , value )
246+
242247 if isinstance (key_path , str ):
243248 key_path = key_path .split ("." )
244249
245250 # Check that the key already exists.
246- parent : Union [SubClrEnv , PrimitiveValue ] = self
251+ parent : Union [SubClrEnv , LeafValue ] = self
247252 for name in key_path :
248253 assert isinstance (parent , Mapping )
249254 assert name in parent , f"{ name , parent } "
250255 parent = parent [name ]
251256
252- # No support for nested runtime overrides. Only allow primitives.
253- if not isinstance (value , PrimitiveValue .__args__ ): # type: ignore
254- raise ValueError ("Env values must be one of {str, int, float, boolean}." )
255-
256257 # Ideally we wouldn't be overriding global state like this at all, but at least
257258 # make it loud.
258259 logger .warning (f"Manually overriding env.{ '.' .join (key_path )} to { value } ." )
0 commit comments