Skip to content

Commit

Permalink
Merge branch 'remote-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
mwjin committed Jul 30, 2021
2 parents c65a86a + 36516a7 commit 46c1ddb
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 26 deletions.
22 changes: 13 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- The `dotenv_path` argument of `set_key` and `unset_key` now has a type of `Union[str,
os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
## [0.19.0] - 2021-07-24

### Changed

- Require Python 3.5 or a later version. Python 2 and 3.4 are no longer supported. (#341
by [@bbc2]).

### Added

- The `dotenv_path` argument of `set_key` and `unset_key` now has a type of `Union[str,
os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]).
- The `stream` argument of `load_dotenv` and `dotenv_values` can now be a text stream
(`IO[str]`), which includes values like `io.StringIO("foo")` and `open("file.env",
"r")` (#348 by [@bbc2]).

## [0.18.0] - 2021-06-20

### Changed
Expand Down Expand Up @@ -218,13 +221,13 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.6.2

- Fix dotenv list command ([@ticosax](https://github.com/ticosax))
- Add iPython Suport
- Add iPython Support
([@tillahoffmann](https://github.com/tillahoffmann))

## 0.6.0

- Drop support for Python 2.6
- Handle escaped charaters and newlines in quoted values. (Thanks
- Handle escaped characters and newlines in quoted values. (Thanks
[@iameugenejo](https://github.com/iameugenejo))
- Remove any spaces around unquoted key/value. (Thanks
[@paulochf](https://github.com/paulochf))
Expand Down Expand Up @@ -282,7 +285,8 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
[@yannham]: https://github.com/yannham
[@zueve]: https://github.com/zueve

[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v0.18.0...HEAD
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v0.19.0...HEAD
[0.19.0]: https://github.com/theskumar/python-dotenv/compare/v0.18.0...v0.19.0
[0.18.0]: https://github.com/theskumar/python-dotenv/compare/v0.17.1...v0.18.0
[0.17.1]: https://github.com/theskumar/python-dotenv/compare/v0.17.0...v0.17.1
[0.17.0]: https://github.com/theskumar/python-dotenv/compare/v0.16.0...v0.17.0
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.18.0
current_version = 0.19.0
commit = True
tag = True

Expand Down
38 changes: 25 additions & 13 deletions src/dotenv/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding
class DotEnv():
def __init__(
self,
dotenv_path: Union[str, _PathLike, io.StringIO],
dotenv_path: Optional[Union[str, _PathLike]],
stream: Optional[IO[str]] = None,
verbose: bool = False,
encoding: Union[None, str] = None,
interpolate: bool = True,
override: bool = True,
) -> None:
self.dotenv_path = dotenv_path # type: Union[str,_PathLike, io.StringIO]
self.dotenv_path = dotenv_path # type: Optional[Union[str, _PathLike]]
self.stream = stream # type: Optional[IO[str]]
self._dict = None # type: Optional[Dict[str, Optional[str]]]
self.verbose = verbose # type: bool
self.encoding = encoding # type: Union[None, str]
Expand All @@ -48,14 +50,17 @@ def __init__(

@contextmanager
def _get_stream(self) -> Iterator[IO[str]]:
if isinstance(self.dotenv_path, io.StringIO):
yield self.dotenv_path
elif os.path.isfile(self.dotenv_path):
if self.dotenv_path and os.path.isfile(self.dotenv_path):
with io.open(self.dotenv_path, encoding=self.encoding) as stream:
yield stream
elif self.stream is not None:
yield self.stream
else:
if self.verbose:
logger.info("Python-dotenv could not find configuration file %s.", self.dotenv_path or '.env')
logger.info(
"Python-dotenv could not find configuration file %s.",
self.dotenv_path or '.env',
)
yield io.StringIO('')

def dict(self) -> Dict[str, Optional[str]]:
Expand Down Expand Up @@ -304,7 +309,7 @@ def _is_interactive():

def load_dotenv(
dotenv_path: Union[str, _PathLike, None] = None,
stream: Optional[io.StringIO] = None,
stream: Optional[IO[str]] = None,
verbose: bool = False,
override: bool = False,
interpolate: bool = True,
Expand All @@ -313,7 +318,8 @@ def load_dotenv(
"""Parse a .env file and then load all the variables found as environment variables.
- *dotenv_path*: absolute or relative path to .env file.
- *stream*: `StringIO` object with .env content, used if `dotenv_path` is `None`.
- *stream*: Text stream (such as `io.StringIO`) with .env content, used if
`dotenv_path` is `None`.
- *verbose*: whether to output a warning the .env file is missing. Defaults to
`False`.
- *override*: whether to override the system environment variables with the variables
Expand All @@ -322,9 +328,12 @@ def load_dotenv(
If both `dotenv_path` and `stream`, `find_dotenv()` is used to find the .env file.
"""
f = dotenv_path or stream or find_dotenv()
if dotenv_path is None and stream is None:
dotenv_path = find_dotenv()

dotenv = DotEnv(
f,
dotenv_path=dotenv_path,
stream=stream,
verbose=verbose,
interpolate=interpolate,
override=override,
Expand All @@ -335,7 +344,7 @@ def load_dotenv(

def dotenv_values(
dotenv_path: Union[str, _PathLike, None] = None,
stream: Optional[io.StringIO] = None,
stream: Optional[IO[str]] = None,
verbose: bool = False,
interpolate: bool = True,
encoding: Optional[str] = "utf-8",
Expand All @@ -352,9 +361,12 @@ def dotenv_values(
If both `dotenv_path` and `stream`, `find_dotenv()` is used to find the .env file.
"""
f = dotenv_path or stream or find_dotenv()
if dotenv_path is None and stream is None:
dotenv_path = find_dotenv()

return DotEnv(
f,
dotenv_path=dotenv_path,
stream=stream,
verbose=verbose,
interpolate=interpolate,
override=True,
Expand Down
2 changes: 1 addition & 1 deletion src/dotenv/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.18.0"
__version__ = "0.19.0"
26 changes: 24 additions & 2 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def test_load_dotenv_redefine_var_used_in_file_with_override(dotenv_file):


@mock.patch.dict(os.environ, {}, clear=True)
def test_load_dotenv_utf_8():
def test_load_dotenv_string_io_utf_8():
stream = io.StringIO("a=à")

result = dotenv.load_dotenv(stream=stream)
Expand All @@ -286,6 +286,18 @@ def test_load_dotenv_utf_8():
assert os.environ == {"a": "à"}


@mock.patch.dict(os.environ, {}, clear=True)
def test_load_dotenv_file_stream(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")

with open(dotenv_file, "r") as f:
result = dotenv.load_dotenv(stream=f)

assert result is True
assert os.environ == {"a": "b"}


def test_load_dotenv_in_current_dir(tmp_path):
dotenv_path = tmp_path / '.env'
dotenv_path.write_bytes(b'a=b')
Expand Down Expand Up @@ -353,7 +365,7 @@ def test_dotenv_values_file(dotenv_file):
({}, "a=b\nc=${a}\nd=e\nc=${d}", True, {"a": "b", "c": "e", "d": "e"}),
],
)
def test_dotenv_values_stream(env, string, interpolate, expected):
def test_dotenv_values_string_io(env, string, interpolate, expected):
with mock.patch.dict(os.environ, env, clear=True):
stream = io.StringIO(string)
stream.seek(0)
Expand All @@ -363,6 +375,16 @@ def test_dotenv_values_stream(env, string, interpolate, expected):
assert result == expected


def test_dotenv_values_file_stream(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")

with open(dotenv_file, "r") as f:
result = dotenv.dotenv_values(stream=f)

assert result == {"a": "b"}


@pytest.mark.parametrize(
"before,env_dict,after",
[
Expand Down

0 comments on commit 46c1ddb

Please sign in to comment.