environment.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import os
  2. import re
  3. _VARIABLE_PATTERN = re.compile(
  4. r'(?P<escape>\\)?(?P<variable>\$\{(?P<name>[A-Za-z0-9_]+)((:?-)(?P<default>[^}]+))?\})'
  5. )
  6. def _resolve_string(matcher):
  7. '''
  8. Get the value from environment given a matcher containing a name and an optional default value.
  9. If the variable is not defined in environment and no default value is provided, an Error is raised.
  10. '''
  11. if matcher.group('escape') is not None:
  12. # in case of escaped envvar, unescape it
  13. return matcher.group('variable')
  14. # resolve the env var
  15. name, default = matcher.group('name'), matcher.group('default')
  16. out = os.getenv(name, default=default)
  17. if out is None:
  18. raise ValueError(f'Cannot find variable {name} in environment')
  19. return out
  20. def resolve_env_variables(item):
  21. '''
  22. Resolves variables like or ${FOO} from given configuration with values from process environment
  23. Supported formats:
  24. - ${FOO} will return FOO env variable
  25. - ${FOO-bar} or ${FOO:-bar} will return FOO env variable if it exists, else "bar"
  26. If any variable is missing in environment and no default value is provided, an Error is raised.
  27. '''
  28. if isinstance(item, str):
  29. return _VARIABLE_PATTERN.sub(_resolve_string, item)
  30. if isinstance(item, list):
  31. for i, subitem in enumerate(item):
  32. item[i] = resolve_env_variables(subitem)
  33. if isinstance(item, dict):
  34. for key, value in item.items():
  35. item[key] = resolve_env_variables(value)
  36. return item