environment.py 3.2 KB

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