environment.py 3.6 KB

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