environment.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. from __future__ import absolute_import
  2. from __future__ import unicode_literals
  3. import logging
  4. import os
  5. import re
  6. import dotenv
  7. import six
  8. from ..const import IS_WINDOWS_PLATFORM
  9. from .errors import ConfigurationError
  10. from .errors import EnvFileNotFound
  11. log = logging.getLogger(__name__)
  12. def split_env(env):
  13. if isinstance(env, six.binary_type):
  14. env = env.decode('utf-8', 'replace')
  15. key = value = None
  16. if '=' in env:
  17. key, value = env.split('=', 1)
  18. else:
  19. key = env
  20. if re.search(r'\s', key):
  21. raise ConfigurationError(
  22. "environment variable name '{}' may not contain whitespace.".format(key)
  23. )
  24. return key, value
  25. def env_vars_from_file(filename, interpolate=True):
  26. """
  27. Read in a line delimited file of environment variables.
  28. """
  29. if not os.path.exists(filename):
  30. raise EnvFileNotFound("Couldn't find env file: {}".format(filename))
  31. elif not os.path.isfile(filename):
  32. raise EnvFileNotFound("{} is not a file.".format(filename))
  33. env = dotenv.dotenv_values(dotenv_path=filename, encoding='utf-8-sig', interpolate=interpolate)
  34. for k, v in env.items():
  35. env[k] = v if interpolate else v.replace('$', '$$')
  36. return env
  37. class Environment(dict):
  38. def __init__(self, *args, **kwargs):
  39. super(Environment, self).__init__(*args, **kwargs)
  40. self.missing_keys = []
  41. self.silent = False
  42. @classmethod
  43. def from_env_file(cls, base_dir, env_file=None):
  44. def _initialize():
  45. result = cls()
  46. if base_dir is None:
  47. return result
  48. if env_file:
  49. env_file_path = os.path.join(base_dir, env_file)
  50. else:
  51. env_file_path = os.path.join(base_dir, '.env')
  52. try:
  53. return cls(env_vars_from_file(env_file_path))
  54. except EnvFileNotFound:
  55. pass
  56. return result
  57. instance = _initialize()
  58. instance.update(os.environ)
  59. return instance
  60. @classmethod
  61. def from_command_line(cls, parsed_env_opts):
  62. result = cls()
  63. for k, v in parsed_env_opts.items():
  64. # Values from the command line take priority, unless they're unset
  65. # in which case they take the value from the system's environment
  66. if v is None and k in os.environ:
  67. result[k] = os.environ[k]
  68. else:
  69. result[k] = v
  70. return result
  71. def __getitem__(self, key):
  72. try:
  73. return super(Environment, self).__getitem__(key)
  74. except KeyError:
  75. if IS_WINDOWS_PLATFORM:
  76. try:
  77. return super(Environment, self).__getitem__(key.upper())
  78. except KeyError:
  79. pass
  80. if not self.silent and key not in self.missing_keys:
  81. log.warning(
  82. "The {} variable is not set. Defaulting to a blank string."
  83. .format(key)
  84. )
  85. self.missing_keys.append(key)
  86. return ""
  87. def __contains__(self, key):
  88. result = super(Environment, self).__contains__(key)
  89. if IS_WINDOWS_PLATFORM:
  90. return (
  91. result or super(Environment, self).__contains__(key.upper())
  92. )
  93. return result
  94. def get(self, key, *args, **kwargs):
  95. if IS_WINDOWS_PLATFORM:
  96. return super(Environment, self).get(
  97. key,
  98. super(Environment, self).get(key.upper(), *args, **kwargs)
  99. )
  100. return super(Environment, self).get(key, *args, **kwargs)
  101. def get_boolean(self, key):
  102. # Convert a value to a boolean using "common sense" rules.
  103. # Unset, empty, "0" and "false" (i-case) yield False.
  104. # All other values yield True.
  105. value = self.get(key)
  106. if not value:
  107. return False
  108. if value.lower() in ['0', 'false']:
  109. return False
  110. return True