88import shlex
99import socket
1010import sys
11+ import traceback
1112
1213from botocore .exceptions import EndpointConnectionError
1314
2425OFFLINE_FLAG = 'CLRENV_OFFLINE_DEV'
2526OFFLINE_VALUE = 'CLRENV_OFFLINE_PLACEHOLDER'
2627
28+ DEBUG_MODE = environ .get ('CLRENV_DEBUG' , '' ).lower () in ('true' , '1' )
2729
2830class LazyEnv (object ):
2931 def __init__ (self ):
3032 self .__mode = tuple (shlex .split (environ .get ('CLRENV_MODE' , '' )))
3133 self .__env = None
34+ self .__runtime_overrides = {}
3235
3336 def is_set (self ):
3437 return self .__env is not None
@@ -40,18 +43,35 @@ def set_mode(self, *mode):
4043 def get_mode (self ):
4144 return self .__mode
4245
46+ def clear_runtime_overrides (self ):
47+ self .__runtime_overrides .clear ()
48+
4349 def __getattr__ (self , key ):
4450 if self .__env is None :
4551 self .__env = get_env (* self .__mode )
4652
47- try :
48- return getattr (self .__env , key )
49- except AttributeError :
50- return None
53+ if key in self .__runtime_overrides :
54+ return self .__runtime_overrides [key ]
55+ return getattr (self .__env , key , None )
5156
5257 def __getitem__ (self , key ):
5358 return self .__getattr__ (key )
5459
60+ def __setattr__ (self , key , value ):
61+ # Internal fields are prefixed with a _
62+ if key .startswith ('_' ):
63+ return object .__setattr__ (self , key , value )
64+
65+ # Ideally we wouldn't be overriding global state like this at all, but at least
66+ # make it loud.
67+ logger .warning (f'Manually overriding env.{ key } to { value } .' )
68+ if DEBUG_MODE :
69+ # Get stack and remove this frame.
70+ tb = traceback .extract_stack ()[:- 1 ]
71+ logger .warning ("" .join (traceback .format_list (tb )))
72+
73+ self .__runtime_overrides [key ] = value
74+
5575_env = {}
5676def get_env (* mode ):
5777 global _env
0 commit comments