diff --git a/.travis.yml b/.travis.yml index c8f56f51..5588c7ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,6 @@ matrix: - python: "2.7" env: TOXENV=py27 - - python: "3.4" - env: TOXENV=py34 - - python: "3.4" - env: TOXENV=py34-no-typing - python: "3.5" env: TOXENV=py35 - python: "3.6" diff --git a/src/dotenv/main.py b/src/dotenv/main.py index 6b7f947d..5a1c3250 100644 --- a/src/dotenv/main.py +++ b/src/dotenv/main.py @@ -50,7 +50,7 @@ class DotEnv(): def __init__(self, dotenv_path, verbose=False, encoding=None): # type: (Union[Text, _PathLike, _StringIO], bool, Union[None, Text]) -> None self.dotenv_path = dotenv_path # type: Union[Text,_PathLike, _StringIO] - self._dict = None # type: Optional[Dict[Text, Text]] + self._dict = None # type: Optional[Dict[Text, Optional[Text]]] self.verbose = verbose # type: bool self.encoding = encoding # type: Union[None, Text] @@ -68,7 +68,7 @@ def _get_stream(self): yield StringIO('') def dict(self): - # type: () -> Dict[Text, Text] + # type: () -> Dict[Text, Optional[Text]] """Return dotenv as dict""" if self._dict: return self._dict @@ -78,10 +78,10 @@ def dict(self): return self._dict def parse(self): - # type: () -> Iterator[Tuple[Text, Text]] + # type: () -> Iterator[Tuple[Text, Optional[Text]]] with self._get_stream() as stream: for mapping in with_warn_for_invalid_lines(parse_stream(stream)): - if mapping.key is not None and mapping.value is not None: + if mapping.key is not None: yield mapping.key, mapping.value def set_as_environment_variables(self, override=False): @@ -92,7 +92,8 @@ def set_as_environment_variables(self, override=False): for k, v in self.dict().items(): if k in os.environ and not override: continue - os.environ[to_env(k)] = to_env(v) + if v is not None: + os.environ[to_env(k)] = to_env(v) return True @@ -197,7 +198,7 @@ def unset_key(dotenv_path, key_to_unset, quote_mode="always"): def resolve_nested_variables(values): - # type: (Dict[Text, Text]) -> Dict[Text, Text] + # type: (Dict[Text, Optional[Text]]) -> Dict[Text, Optional[Text]] def _replacement(name): # type: (Text) -> Text """ @@ -206,7 +207,7 @@ def _replacement(name): then look into the dotenv variables """ ret = os.getenv(name, new_values.get(name, "")) - return ret + return ret # type: ignore def _re_sub_callback(match_object): # type: (Match[Text]) -> Text @@ -219,7 +220,7 @@ def _re_sub_callback(match_object): new_values = {} for k, v in values.items(): - new_values[k] = __posix_variable.sub(_re_sub_callback, v) + new_values[k] = __posix_variable.sub(_re_sub_callback, v) if v is not None else None return new_values @@ -301,6 +302,6 @@ def load_dotenv(dotenv_path=None, stream=None, verbose=False, override=False, ** def dotenv_values(dotenv_path=None, stream=None, verbose=False, **kwargs): - # type: (Union[Text, _PathLike, None], Optional[_StringIO], bool, Union[None, Text]) -> Dict[Text, Text] + # type: (Union[Text, _PathLike, None], Optional[_StringIO], bool, Union[None, Text]) -> Dict[Text, Optional[Text]] f = dotenv_path or stream or find_dotenv() return DotEnv(f, verbose=verbose, **kwargs).dict() diff --git a/src/dotenv/parser.py b/src/dotenv/parser.py index dc8fe008..bd60cab4 100644 --- a/src/dotenv/parser.py +++ b/src/dotenv/parser.py @@ -20,7 +20,7 @@ def make_regex(string, extra_flags=0): _export = make_regex(r"(?:export[^\S\r\n]+)?") _single_quoted_key = make_regex(r"'([^']+)'") _unquoted_key = make_regex(r"([^=\#\s]+)") -_equal_sign = make_regex(r"[^\S\r\n]*=[^\S\r\n]*") +_equal_sign = make_regex(r"([^\S\r\n]*=[^\S\r\n]*)?") _single_quoted_value = make_regex(r"'((?:\\'|[^'])*)'") _double_quoted_value = make_regex(r'"((?:\\"|[^"])*)"') _unquoted_value_part = make_regex(r"([^ \r\n]*)") @@ -194,8 +194,8 @@ def parse_binding(reader): reader.read_regex(_whitespace) reader.read_regex(_export) key = parse_key(reader) - reader.read_regex(_equal_sign) - value = parse_value(reader) + (sign,) = reader.read_regex(_equal_sign) + value = parse_value(reader) if sign else None reader.read_regex(_comment) reader.read_regex(_end_of_line) return Binding( diff --git a/tests/test_parser.py b/tests/test_parser.py index aac19302..c19ed502 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -35,7 +35,7 @@ (u"a='b\\'c'", [Binding(key=u"a", value=u"b'c", original=Original(string=u"a='b\\'c'", line=1))]), (u"a=à", [Binding(key=u"a", value=u"à", original=Original(string=u"a=à", line=1))]), (u'a="à"', [Binding(key=u"a", value=u"à", original=Original(string=u'a="à"', line=1))]), - (u'garbage', [Binding(key=None, value=None, original=Original(string=u"garbage", line=1))]), + (u'no_value_var', [Binding(key=u'no_value_var', value=None, original=Original(string=u"no_value_var", line=1))]), ( u"a=b\nc=d", [ @@ -87,9 +87,11 @@ ], ), ( - u'garbage[%$#\na=b', + u'uglyKey[%$=\"S3cr3t_P4ssw#rD\" #\na=b', [ - Binding(key=None, value=None, original=Original(string=u"garbage[%$#\n", line=1)), + Binding(key=u'uglyKey[%$', + value=u'S3cr3t_P4ssw#rD', + original=Original(string=u"uglyKey[%$=\"S3cr3t_P4ssw#rD\" #\n", line=1)), Binding(key=u"a", value=u"b", original=Original(string=u'a=b', line=2)), ], ),