New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

python-dotenv

Package Overview
Dependencies
Maintainers
2
Versions
50
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

python-dotenv - pypi Package Compare versions

Comparing version
1.0.0
to
1.0.1
+101
tests/test_zip_imports.py
import os
import sys
import sh
import textwrap
from typing import List
from unittest import mock
from zipfile import ZipFile
def walk_to_root(path: str):
last_dir = None
current_dir = path
while last_dir != current_dir:
yield current_dir
(parent_dir, _) = os.path.split(current_dir)
last_dir, current_dir = current_dir, parent_dir
class FileToAdd:
def __init__(self, content: str, path: str):
self.content = content
self.path = path
def setup_zipfile(path, files: List[FileToAdd]):
zip_file_path = path / "test.zip"
dirs_init_py_added_to = set()
with ZipFile(zip_file_path, "w") as zip:
for f in files:
zip.writestr(data=f.content, zinfo_or_arcname=f.path)
for dir in walk_to_root(os.path.dirname(f.path)):
if dir not in dirs_init_py_added_to:
print(os.path.join(dir, "__init__.py"))
zip.writestr(
data="", zinfo_or_arcname=os.path.join(dir, "__init__.py")
)
dirs_init_py_added_to.add(dir)
return zip_file_path
@mock.patch.object(sys, "path", list(sys.path))
def test_load_dotenv_gracefully_handles_zip_imports_when_no_env_file(tmp_path):
zip_file_path = setup_zipfile(
tmp_path,
[
FileToAdd(
content=textwrap.dedent(
"""
from dotenv import load_dotenv
load_dotenv()
"""
),
path="child1/child2/test.py",
),
],
)
# Should run without an error
sys.path.append(str(zip_file_path))
import child1.child2.test # noqa
def test_load_dotenv_outside_zip_file_when_called_in_zipfile(tmp_path):
zip_file_path = setup_zipfile(
tmp_path,
[
FileToAdd(
content=textwrap.dedent(
"""
from dotenv import load_dotenv
load_dotenv()
"""
),
path="child1/child2/test.py",
),
],
)
dotenv_path = tmp_path / ".env"
dotenv_path.write_bytes(b"a=b")
code_path = tmp_path / "code.py"
code_path.write_text(
textwrap.dedent(
f"""
import os
import sys
sys.path.append("{zip_file_path}")
import child1.child2.test
print(os.environ['a'])
"""
)
)
os.chdir(str(tmp_path))
result = sh.Command(sys.executable)(code_path)
assert result == "b\n"
+28
-3

@@ -8,10 +8,23 @@ # Changelog

## [1.0.0]
## [1.0.1] - 2024-01-23
**Fixed**
* Gracefully handle code which has been imported from a zipfile ([#456] by [@samwyma])
* Allow modules using load_dotenv to be reloaded when launched in a separate thread ([#497] by [@freddyaboulton])
* Fix file not closed after deletion, handle error in the rewrite function ([#469] by [@Qwerty-133])
**Misc**
* Use pathlib.Path in tests ([#466] by [@eumiro])
* Fix year in release date in changelog.md ([#454] by [@jankislinger])
* Use https in README links ([#474] by [@Nicals])
## [1.0.0] - 2023-02-24
**Fixed**
* Drop support for python 3.7, add python 3.12-dev (#449 by [@theskumar])
* Handle situations where the cwd does not exist. (#446 by [@jctanner])
## [0.21.1] - 2022-01-21
## [0.21.1] - 2023-01-21

@@ -332,2 +345,7 @@ **Added**

[#359]: https://github.com/theskumar/python-dotenv/issues/359
[#469]: https://github.com/theskumar/python-dotenv/issues/469
[#456]: https://github.com/theskumar/python-dotenv/issues/456
[#466]: https://github.com/theskumar/python-dotenv/issues/466
[#454]: https://github.com/theskumar/python-dotenv/issues/454
[#474]: https://github.com/theskumar/python-dotenv/issues/474

@@ -346,3 +364,5 @@ [@alanjds]: https://github.com/alanjds

[@elbehery95]: https://github.com/elbehery95
[@eumiro]: https://github.com/eumiro
[@Flimm]: https://github.com/Flimm
[@freddyaboulton]: https://github.com/freddyaboulton
[@gergelyk]: https://github.com/gergelyk

@@ -353,2 +373,3 @@ [@gongqingkui]: https://github.com/gongqingkui

[@jadutter]: https://github.com/jadutter
[@jankislinger]: https://github.com/jankislinger
[@jctanner]: https://github.com/jctanner

@@ -359,6 +380,9 @@ [@larsks]: https://github.com/@larsks

[@naorlivne]: https://github.com/@naorlivne
[@Nicals]: https://github.com/Nicals
[@Nougat-Waffle]: https://github.com/Nougat-Waffle
[@qnighy]: https://github.com/qnighy
[@Qwerty-133]: https://github.com/Qwerty-133
[@rabinadk1]: https://github.com/@rabinadk1
[@sammck]: https://github.com/@sammck
[@samwyma]: https://github.com/samwyma
[@snobu]: https://github.com/snobu

@@ -375,3 +399,4 @@ [@techalchemy]: https://github.com/techalchemy

[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...HEAD
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v1.0.0

@@ -378,0 +403,0 @@ [0.21.1]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v0.21.1

@@ -8,10 +8,23 @@ # Changelog

## [1.0.0]
## [1.0.1] - 2024-01-23
**Fixed**
* Gracefully handle code which has been imported from a zipfile ([#456] by [@samwyma])
* Allow modules using load_dotenv to be reloaded when launched in a separate thread ([#497] by [@freddyaboulton])
* Fix file not closed after deletion, handle error in the rewrite function ([#469] by [@Qwerty-133])
**Misc**
* Use pathlib.Path in tests ([#466] by [@eumiro])
* Fix year in release date in changelog.md ([#454] by [@jankislinger])
* Use https in README links ([#474] by [@Nicals])
## [1.0.0] - 2023-02-24
**Fixed**
* Drop support for python 3.7, add python 3.12-dev (#449 by [@theskumar])
* Handle situations where the cwd does not exist. (#446 by [@jctanner])
## [0.21.1] - 2022-01-21
## [0.21.1] - 2023-01-21

@@ -332,2 +345,7 @@ **Added**

[#359]: https://github.com/theskumar/python-dotenv/issues/359
[#469]: https://github.com/theskumar/python-dotenv/issues/469
[#456]: https://github.com/theskumar/python-dotenv/issues/456
[#466]: https://github.com/theskumar/python-dotenv/issues/466
[#454]: https://github.com/theskumar/python-dotenv/issues/454
[#474]: https://github.com/theskumar/python-dotenv/issues/474

@@ -346,3 +364,5 @@ [@alanjds]: https://github.com/alanjds

[@elbehery95]: https://github.com/elbehery95
[@eumiro]: https://github.com/eumiro
[@Flimm]: https://github.com/Flimm
[@freddyaboulton]: https://github.com/freddyaboulton
[@gergelyk]: https://github.com/gergelyk

@@ -353,2 +373,3 @@ [@gongqingkui]: https://github.com/gongqingkui

[@jadutter]: https://github.com/jadutter
[@jankislinger]: https://github.com/jankislinger
[@jctanner]: https://github.com/jctanner

@@ -359,6 +380,9 @@ [@larsks]: https://github.com/@larsks

[@naorlivne]: https://github.com/@naorlivne
[@Nicals]: https://github.com/Nicals
[@Nougat-Waffle]: https://github.com/Nougat-Waffle
[@qnighy]: https://github.com/qnighy
[@Qwerty-133]: https://github.com/Qwerty-133
[@rabinadk1]: https://github.com/@rabinadk1
[@sammck]: https://github.com/@sammck
[@samwyma]: https://github.com/samwyma
[@snobu]: https://github.com/snobu

@@ -375,3 +399,4 @@ [@techalchemy]: https://github.com/techalchemy

[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...HEAD
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v1.0.0

@@ -378,0 +403,0 @@ [0.21.1]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v0.21.1

+2
-2

@@ -8,3 +8,3 @@ # python-dotenv

variables. It helps in the development of applications following the
[12-factor](http://12factor.net/) principles.
[12-factor](https://12factor.net/) principles.

@@ -247,3 +247,3 @@ - [Getting Started](#getting-started)

[pypi_badge]: https://badge.fury.io/py/python-dotenv.svg
[pypi_link]: http://badge.fury.io/py/python-dotenv
[pypi_link]: https://badge.fury.io/py/python-dotenv
[python_streams]: https://docs.python.org/3/library/io.html
Metadata-Version: 2.1
Name: python-dotenv
Version: 1.0.0
Version: 1.0.1
Summary: Read key-value pairs from a .env file and set them as environment variables

@@ -28,4 +28,5 @@ Home-page: https://github.com/theskumar/python-dotenv

Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: cli
License-File: LICENSE
Requires-Dist: click>=5.0; extra == "cli"

@@ -39,3 +40,3 @@ # python-dotenv

variables. It helps in the development of applications following the
[12-factor](http://12factor.net/) principles.
[12-factor](https://12factor.net/) principles.

@@ -278,3 +279,3 @@ - [Getting Started](#getting-started)

[pypi_badge]: https://badge.fury.io/py/python-dotenv.svg
[pypi_link]: http://badge.fury.io/py/python-dotenv
[pypi_link]: https://badge.fury.io/py/python-dotenv
[python_streams]: https://docs.python.org/3/library/io.html

@@ -289,10 +290,23 @@

## [1.0.0]
## [1.0.1] - 2024-01-23
**Fixed**
* Gracefully handle code which has been imported from a zipfile ([#456] by [@samwyma])
* Allow modules using load_dotenv to be reloaded when launched in a separate thread ([#497] by [@freddyaboulton])
* Fix file not closed after deletion, handle error in the rewrite function ([#469] by [@Qwerty-133])
**Misc**
* Use pathlib.Path in tests ([#466] by [@eumiro])
* Fix year in release date in changelog.md ([#454] by [@jankislinger])
* Use https in README links ([#474] by [@Nicals])
## [1.0.0] - 2023-02-24
**Fixed**
* Drop support for python 3.7, add python 3.12-dev (#449 by [@theskumar])
* Handle situations where the cwd does not exist. (#446 by [@jctanner])
## [0.21.1] - 2022-01-21
## [0.21.1] - 2023-01-21

@@ -613,2 +627,7 @@ **Added**

[#359]: https://github.com/theskumar/python-dotenv/issues/359
[#469]: https://github.com/theskumar/python-dotenv/issues/469
[#456]: https://github.com/theskumar/python-dotenv/issues/456
[#466]: https://github.com/theskumar/python-dotenv/issues/466
[#454]: https://github.com/theskumar/python-dotenv/issues/454
[#474]: https://github.com/theskumar/python-dotenv/issues/474

@@ -627,3 +646,5 @@ [@alanjds]: https://github.com/alanjds

[@elbehery95]: https://github.com/elbehery95
[@eumiro]: https://github.com/eumiro
[@Flimm]: https://github.com/Flimm
[@freddyaboulton]: https://github.com/freddyaboulton
[@gergelyk]: https://github.com/gergelyk

@@ -634,2 +655,3 @@ [@gongqingkui]: https://github.com/gongqingkui

[@jadutter]: https://github.com/jadutter
[@jankislinger]: https://github.com/jankislinger
[@jctanner]: https://github.com/jctanner

@@ -640,6 +662,9 @@ [@larsks]: https://github.com/@larsks

[@naorlivne]: https://github.com/@naorlivne
[@Nicals]: https://github.com/Nicals
[@Nougat-Waffle]: https://github.com/Nougat-Waffle
[@qnighy]: https://github.com/qnighy
[@Qwerty-133]: https://github.com/Qwerty-133
[@rabinadk1]: https://github.com/@rabinadk1
[@sammck]: https://github.com/@sammck
[@samwyma]: https://github.com/samwyma
[@snobu]: https://github.com/snobu

@@ -656,3 +681,4 @@ [@techalchemy]: https://github.com/techalchemy

[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...HEAD
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v1.0.0

@@ -659,0 +685,0 @@ [0.21.1]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v0.21.1

@@ -8,3 +8,3 @@ # python-dotenv

variables. It helps in the development of applications following the
[12-factor](http://12factor.net/) principles.
[12-factor](https://12factor.net/) principles.

@@ -247,3 +247,3 @@ - [Getting Started](#getting-started)

[pypi_badge]: https://badge.fury.io/py/python-dotenv.svg
[pypi_link]: http://badge.fury.io/py/python-dotenv
[pypi_link]: https://badge.fury.io/py/python-dotenv
[python_streams]: https://docs.python.org/3/library/io.html
import io
import logging
import os
import pathlib
import shutil

@@ -134,15 +135,19 @@ import sys

) -> Iterator[Tuple[IO[str], IO[str]]]:
if not os.path.isfile(path):
with open(path, mode="w", encoding=encoding) as source:
source.write("")
pathlib.Path(path).touch()
with tempfile.NamedTemporaryFile(mode="w", encoding=encoding, delete=False) as dest:
error = None
try:
with open(path, encoding=encoding) as source:
yield (source, dest)
except BaseException:
os.unlink(dest.name)
raise
shutil.move(dest.name, path)
except BaseException as err:
error = err
if error is None:
shutil.move(dest.name, path)
else:
os.unlink(dest.name)
raise error from None
def set_key(

@@ -284,3 +289,6 @@ dotenv_path: StrPath,

""" Decide whether this is running in a REPL or IPython notebook """
main = __import__('__main__', None, None, fromlist=['__file__'])
try:
main = __import__('__main__', None, None, fromlist=['__file__'])
except ModuleNotFoundError:
return False
return not hasattr(main, '__file__')

@@ -296,3 +304,5 @@

while frame.f_code.co_filename == current_file:
while frame.f_code.co_filename == current_file or not os.path.exists(
frame.f_code.co_filename
):
assert frame.f_back is not None

@@ -299,0 +309,0 @@ frame = frame.f_back

@@ -1,1 +0,1 @@

__version__ = "1.0.0"
__version__ = "1.0.1"
Metadata-Version: 2.1
Name: python-dotenv
Version: 1.0.0
Version: 1.0.1
Summary: Read key-value pairs from a .env file and set them as environment variables

@@ -28,4 +28,5 @@ Home-page: https://github.com/theskumar/python-dotenv

Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: cli
License-File: LICENSE
Requires-Dist: click>=5.0; extra == "cli"

@@ -39,3 +40,3 @@ # python-dotenv

variables. It helps in the development of applications following the
[12-factor](http://12factor.net/) principles.
[12-factor](https://12factor.net/) principles.

@@ -278,3 +279,3 @@ - [Getting Started](#getting-started)

[pypi_badge]: https://badge.fury.io/py/python-dotenv.svg
[pypi_link]: http://badge.fury.io/py/python-dotenv
[pypi_link]: https://badge.fury.io/py/python-dotenv
[python_streams]: https://docs.python.org/3/library/io.html

@@ -289,10 +290,23 @@

## [1.0.0]
## [1.0.1] - 2024-01-23
**Fixed**
* Gracefully handle code which has been imported from a zipfile ([#456] by [@samwyma])
* Allow modules using load_dotenv to be reloaded when launched in a separate thread ([#497] by [@freddyaboulton])
* Fix file not closed after deletion, handle error in the rewrite function ([#469] by [@Qwerty-133])
**Misc**
* Use pathlib.Path in tests ([#466] by [@eumiro])
* Fix year in release date in changelog.md ([#454] by [@jankislinger])
* Use https in README links ([#474] by [@Nicals])
## [1.0.0] - 2023-02-24
**Fixed**
* Drop support for python 3.7, add python 3.12-dev (#449 by [@theskumar])
* Handle situations where the cwd does not exist. (#446 by [@jctanner])
## [0.21.1] - 2022-01-21
## [0.21.1] - 2023-01-21

@@ -613,2 +627,7 @@ **Added**

[#359]: https://github.com/theskumar/python-dotenv/issues/359
[#469]: https://github.com/theskumar/python-dotenv/issues/469
[#456]: https://github.com/theskumar/python-dotenv/issues/456
[#466]: https://github.com/theskumar/python-dotenv/issues/466
[#454]: https://github.com/theskumar/python-dotenv/issues/454
[#474]: https://github.com/theskumar/python-dotenv/issues/474

@@ -627,3 +646,5 @@ [@alanjds]: https://github.com/alanjds

[@elbehery95]: https://github.com/elbehery95
[@eumiro]: https://github.com/eumiro
[@Flimm]: https://github.com/Flimm
[@freddyaboulton]: https://github.com/freddyaboulton
[@gergelyk]: https://github.com/gergelyk

@@ -634,2 +655,3 @@ [@gongqingkui]: https://github.com/gongqingkui

[@jadutter]: https://github.com/jadutter
[@jankislinger]: https://github.com/jankislinger
[@jctanner]: https://github.com/jctanner

@@ -640,6 +662,9 @@ [@larsks]: https://github.com/@larsks

[@naorlivne]: https://github.com/@naorlivne
[@Nicals]: https://github.com/Nicals
[@Nougat-Waffle]: https://github.com/Nougat-Waffle
[@qnighy]: https://github.com/qnighy
[@Qwerty-133]: https://github.com/Qwerty-133
[@rabinadk1]: https://github.com/@rabinadk1
[@sammck]: https://github.com/@sammck
[@samwyma]: https://github.com/samwyma
[@snobu]: https://github.com/snobu

@@ -656,3 +681,4 @@ [@techalchemy]: https://github.com/techalchemy

[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...HEAD
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v1.0.0

@@ -659,0 +685,0 @@ [0.21.1]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v0.21.1

@@ -41,2 +41,3 @@ .editorconfig

tests/test_utils.py
tests/test_variables.py
tests/test_variables.py
tests/test_zip_imports.py

@@ -13,5 +13,5 @@ import pytest

@pytest.fixture
def dotenv_file(tmp_path):
file_ = tmp_path / '.env'
file_.write_bytes(b'')
yield str(file_)
def dotenv_path(tmp_path):
path = tmp_path / '.env'
path.write_bytes(b'')
yield path
import os
import sh
from pathlib import Path
from typing import Optional
import pytest
import sh
from typing import Optional
import dotenv

@@ -26,7 +28,6 @@ from dotenv.cli import cli as dotenv_cli

)
def test_list(cli, dotenv_file, format: Optional[str], content: str, expected: str):
with open(dotenv_file, "w") as f:
f.write(content + '\n')
def test_list(cli, dotenv_path, format: Optional[str], content: str, expected: str):
dotenv_path.write_text(content + '\n')
args = ['--file', dotenv_file, 'list']
args = ['--file', dotenv_path, 'list']
if format is not None:

@@ -60,7 +61,6 @@ args.extend(['--format', format])

def test_get_existing_value(cli, dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_get_existing_value(cli, dotenv_path):
dotenv_path.write_text("a=b")
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'get', 'a'])
result = cli.invoke(dotenv_cli, ['--file', dotenv_path, 'get', 'a'])

@@ -70,4 +70,4 @@ assert (result.exit_code, result.output) == (0, "b\n")

def test_get_non_existent_value(cli, dotenv_file):
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'get', 'a'])
def test_get_non_existent_value(cli, dotenv_path):
result = cli.invoke(dotenv_cli, ['--file', dotenv_path, 'get', 'a'])

@@ -91,17 +91,16 @@ assert (result.exit_code, result.output) == (1, "")

def test_unset_existing_value(cli, dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_unset_existing_value(cli, dotenv_path):
dotenv_path.write_text("a=b")
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'unset', 'a'])
result = cli.invoke(dotenv_cli, ['--file', dotenv_path, 'unset', 'a'])
assert (result.exit_code, result.output) == (0, "Successfully removed a\n")
assert open(dotenv_file, "r").read() == ""
assert dotenv_path.read_text() == ""
def test_unset_non_existent_value(cli, dotenv_file):
result = cli.invoke(dotenv_cli, ['--file', dotenv_file, 'unset', 'a'])
def test_unset_non_existent_value(cli, dotenv_path):
result = cli.invoke(dotenv_cli, ['--file', dotenv_path, 'unset', 'a'])
assert (result.exit_code, result.output) == (1, "")
assert open(dotenv_file, "r").read() == ""
assert dotenv_path.read_text() == ""

@@ -119,27 +118,27 @@

)
def test_set_quote_options(cli, dotenv_file, quote_mode, variable, value, expected):
def test_set_quote_options(cli, dotenv_path, quote_mode, variable, value, expected):
result = cli.invoke(
dotenv_cli,
["--file", dotenv_file, "--export", "false", "--quote", quote_mode, "set", variable, value]
["--file", dotenv_path, "--export", "false", "--quote", quote_mode, "set", variable, value]
)
assert (result.exit_code, result.output) == (0, "{}={}\n".format(variable, value))
assert open(dotenv_file, "r").read() == expected
assert dotenv_path.read_text() == expected
@pytest.mark.parametrize(
"dotenv_file,export_mode,variable,value,expected",
"dotenv_path,export_mode,variable,value,expected",
(
(".nx_file", "true", "a", "x", "export a='x'\n"),
(".nx_file", "false", "a", "x", "a='x'\n"),
(Path(".nx_file"), "true", "a", "x", "export a='x'\n"),
(Path(".nx_file"), "false", "a", "x", "a='x'\n"),
)
)
def test_set_export(cli, dotenv_file, export_mode, variable, value, expected):
def test_set_export(cli, dotenv_path, export_mode, variable, value, expected):
result = cli.invoke(
dotenv_cli,
["--file", dotenv_file, "--quote", "always", "--export", export_mode, "set", variable, value]
["--file", dotenv_path, "--quote", "always", "--export", export_mode, "set", variable, value]
)
assert (result.exit_code, result.output) == (0, "{}={}\n".format(variable, value))
assert open(dotenv_file, "r").read() == expected
assert dotenv_path.read_text() == expected

@@ -161,5 +160,4 @@

def test_get_default_path(tmp_path):
with sh.pushd(str(tmp_path)):
with open(str(tmp_path / ".env"), "w") as f:
f.write("a=b")
with sh.pushd(tmp_path):
(tmp_path / ".env").write_text("a=b")

@@ -172,6 +170,4 @@ result = sh.dotenv("get", "a")

def test_run(tmp_path):
with sh.pushd(str(tmp_path)):
dotenv_file = str(tmp_path / ".env")
with open(dotenv_file, "w") as f:
f.write("a=b")
with sh.pushd(tmp_path):
(tmp_path / ".env").write_text("a=b")

@@ -184,6 +180,4 @@ result = sh.dotenv("run", "printenv", "a")

def test_run_with_existing_variable(tmp_path):
with sh.pushd(str(tmp_path)):
dotenv_file = str(tmp_path / ".env")
with open(dotenv_file, "w") as f:
f.write("a=b")
with sh.pushd(tmp_path):
(tmp_path / ".env").write_text("a=b")
env = dict(os.environ)

@@ -198,6 +192,4 @@ env.update({"LANG": "en_US.UTF-8", "a": "c"})

def test_run_with_existing_variable_not_overridden(tmp_path):
with sh.pushd(str(tmp_path)):
dotenv_file = str(tmp_path / ".env")
with open(dotenv_file, "w") as f:
f.write("a=b")
with sh.pushd(tmp_path):
(tmp_path / ".env").write_text("a=b")
env = dict(os.environ)

@@ -212,6 +204,4 @@ env.update({"LANG": "en_US.UTF-8", "a": "c"})

def test_run_with_none_value(tmp_path):
with sh.pushd(str(tmp_path)):
dotenv_file = str(tmp_path / ".env")
with open(dotenv_file, "w") as f:
f.write("a=b\nc")
with sh.pushd(tmp_path):
(tmp_path / ".env").write_text("a=b\nc")

@@ -223,7 +213,6 @@ result = sh.dotenv("run", "printenv", "a")

def test_run_with_other_env(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_run_with_other_env(dotenv_path):
dotenv_path.write_text("a=b")
result = sh.dotenv("--file", dotenv_file, "run", "printenv", "a")
result = sh.dotenv("--file", dotenv_path, "run", "printenv", "a")

@@ -230,0 +219,0 @@ assert result == "b\n"

@@ -16,3 +16,3 @@ import os

dotenv_file.write_text("a=b\n")
os.chdir(str(tmp_path))
os.chdir(tmp_path)
os.environ["a"] = "c"

@@ -33,3 +33,3 @@

dotenv_file.write_text("a=b\n")
os.chdir(str(tmp_path))
os.chdir(tmp_path)
os.environ["a"] = "c"

@@ -50,3 +50,3 @@

dotenv_file.write_text("a=b\n")
os.chdir(str(tmp_path))
os.chdir(tmp_path)

@@ -53,0 +53,0 @@ ipshell = InteractiveShellEmbed()

@@ -15,10 +15,10 @@ import io

def test_set_key_no_file(tmp_path):
nx_file = str(tmp_path / "nx")
nx_path = tmp_path / "nx"
logger = logging.getLogger("dotenv.main")
with mock.patch.object(logger, "warning"):
result = dotenv.set_key(nx_file, "foo", "bar")
result = dotenv.set_key(nx_path, "foo", "bar")
assert result == (True, "foo", "bar")
assert os.path.exists(nx_file)
assert nx_path.exists()

@@ -44,37 +44,35 @@

)
def test_set_key(dotenv_file, before, key, value, expected, after):
def test_set_key(dotenv_path, before, key, value, expected, after):
logger = logging.getLogger("dotenv.main")
with open(dotenv_file, "w") as f:
f.write(before)
dotenv_path.write_text(before)
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.set_key(dotenv_file, key, value)
result = dotenv.set_key(dotenv_path, key, value)
assert result == expected
assert open(dotenv_file, "r").read() == after
assert dotenv_path.read_text() == after
mock_warning.assert_not_called()
def test_set_key_encoding(dotenv_file):
def test_set_key_encoding(dotenv_path):
encoding = "latin-1"
result = dotenv.set_key(dotenv_file, "a", "é", encoding=encoding)
result = dotenv.set_key(dotenv_path, "a", "é", encoding=encoding)
assert result == (True, "a", "é")
assert open(dotenv_file, "r", encoding=encoding).read() == "a='é'\n"
assert dotenv_path.read_text(encoding=encoding) == "a='é'\n"
def test_set_key_permission_error(dotenv_file):
os.chmod(dotenv_file, 0o000)
def test_set_key_permission_error(dotenv_path):
dotenv_path.chmod(0o000)
with pytest.raises(Exception):
dotenv.set_key(dotenv_file, "a", "b")
dotenv.set_key(dotenv_path, "a", "b")
os.chmod(dotenv_file, 0o600)
with open(dotenv_file, "r") as fp:
assert fp.read() == ""
dotenv_path.chmod(0o600)
assert dotenv_path.read_text() == ""
def test_get_key_no_file(tmp_path):
nx_file = str(tmp_path / "nx")
nx_path = tmp_path / "nx"
logger = logging.getLogger("dotenv.main")

@@ -84,3 +82,3 @@

mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.get_key(nx_file, "foo")
result = dotenv.get_key(nx_path, "foo")

@@ -90,3 +88,3 @@ assert result is None

calls=[
mock.call("Python-dotenv could not find configuration file %s.", nx_file)
mock.call("Python-dotenv could not find configuration file %s.", nx_path)
],

@@ -96,3 +94,3 @@ )

calls=[
mock.call("Key %s not found in %s.", "foo", nx_file)
mock.call("Key %s not found in %s.", "foo", nx_path)
],

@@ -102,19 +100,18 @@ )

def test_get_key_not_found(dotenv_file):
def test_get_key_not_found(dotenv_path):
logger = logging.getLogger("dotenv.main")
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.get_key(dotenv_file, "foo")
result = dotenv.get_key(dotenv_path, "foo")
assert result is None
mock_warning.assert_called_once_with("Key %s not found in %s.", "foo", dotenv_file)
mock_warning.assert_called_once_with("Key %s not found in %s.", "foo", dotenv_path)
def test_get_key_ok(dotenv_file):
def test_get_key_ok(dotenv_path):
logger = logging.getLogger("dotenv.main")
with open(dotenv_file, "w") as f:
f.write("foo=bar")
dotenv_path.write_text("foo=bar")
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.get_key(dotenv_file, "foo")
result = dotenv.get_key(dotenv_path, "foo")

@@ -125,8 +122,7 @@ assert result == "bar"

def test_get_key_encoding(dotenv_file):
def test_get_key_encoding(dotenv_path):
encoding = "latin-1"
with open(dotenv_file, "w", encoding=encoding) as f:
f.write("é=è")
dotenv_path.write_text("é=è", encoding=encoding)
result = dotenv.get_key(dotenv_file, "é", encoding=encoding)
result = dotenv.get_key(dotenv_path, "é", encoding=encoding)

@@ -136,9 +132,8 @@ assert result == "è"

def test_get_key_none(dotenv_file):
def test_get_key_none(dotenv_path):
logger = logging.getLogger("dotenv.main")
with open(dotenv_file, "w") as f:
f.write("foo")
dotenv_path.write_text("foo")
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.get_key(dotenv_file, "foo")
result = dotenv.get_key(dotenv_path, "foo")

@@ -149,55 +144,49 @@ assert result is None

def test_unset_with_value(dotenv_file):
def test_unset_with_value(dotenv_path):
logger = logging.getLogger("dotenv.main")
with open(dotenv_file, "w") as f:
f.write("a=b\nc=d")
dotenv_path.write_text("a=b\nc=d")
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.unset_key(dotenv_file, "a")
result = dotenv.unset_key(dotenv_path, "a")
assert result == (True, "a")
with open(dotenv_file, "r") as f:
assert f.read() == "c=d"
assert dotenv_path.read_text() == "c=d"
mock_warning.assert_not_called()
def test_unset_no_value(dotenv_file):
def test_unset_no_value(dotenv_path):
logger = logging.getLogger("dotenv.main")
with open(dotenv_file, "w") as f:
f.write("foo")
dotenv_path.write_text("foo")
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.unset_key(dotenv_file, "foo")
result = dotenv.unset_key(dotenv_path, "foo")
assert result == (True, "foo")
with open(dotenv_file, "r") as f:
assert f.read() == ""
assert dotenv_path.read_text() == ""
mock_warning.assert_not_called()
def test_unset_encoding(dotenv_file):
def test_unset_encoding(dotenv_path):
encoding = "latin-1"
with open(dotenv_file, "w", encoding=encoding) as f:
f.write("é=x")
dotenv_path.write_text("é=x", encoding=encoding)
result = dotenv.unset_key(dotenv_file, "é", encoding=encoding)
result = dotenv.unset_key(dotenv_path, "é", encoding=encoding)
assert result == (True, "é")
with open(dotenv_file, "r", encoding=encoding) as f:
assert f.read() == ""
assert dotenv_path.read_text(encoding=encoding) == ""
def test_set_key_unauthorized_file(dotenv_file):
os.chmod(dotenv_file, 0o000)
def test_set_key_unauthorized_file(dotenv_path):
dotenv_path.chmod(0o000)
with pytest.raises(PermissionError):
dotenv.set_key(dotenv_file, "a", "x")
dotenv.set_key(dotenv_path, "a", "x")
def test_unset_non_existent_file(tmp_path):
nx_file = str(tmp_path / "nx")
nx_path = tmp_path / "nx"
logger = logging.getLogger("dotenv.main")
with mock.patch.object(logger, "warning") as mock_warning:
result = dotenv.unset_key(nx_file, "foo")
result = dotenv.unset_key(nx_path, "foo")

@@ -207,3 +196,3 @@ assert result == (None, "foo")

"Can't delete from %s - it doesn't exist.",
nx_file,
nx_path,
)

@@ -226,15 +215,10 @@

curr_dir = path
dirs = []
for f in ['child1', 'child2', 'child3', 'child4']:
curr_dir /= f
dirs.append(curr_dir)
curr_dir.mkdir()
leaf = path / "child1" / "child2" / "child3" / "child4"
leaf.mkdir(parents=True, exist_ok=True)
return leaf
return (dirs[0], dirs[-1])
def test_find_dotenv_no_file_raise(tmp_path):
(root, leaf) = prepare_file_hierarchy(tmp_path)
os.chdir(str(leaf))
leaf = prepare_file_hierarchy(tmp_path)
os.chdir(leaf)

@@ -246,4 +230,4 @@ with pytest.raises(IOError):

def test_find_dotenv_no_file_no_raise(tmp_path):
(root, leaf) = prepare_file_hierarchy(tmp_path)
os.chdir(str(leaf))
leaf = prepare_file_hierarchy(tmp_path)
os.chdir(leaf)

@@ -256,18 +240,17 @@ result = dotenv.find_dotenv(usecwd=True)

def test_find_dotenv_found(tmp_path):
(root, leaf) = prepare_file_hierarchy(tmp_path)
os.chdir(str(leaf))
dotenv_file = root / ".env"
dotenv_file.write_bytes(b"TEST=test\n")
leaf = prepare_file_hierarchy(tmp_path)
os.chdir(leaf)
dotenv_path = tmp_path / ".env"
dotenv_path.write_bytes(b"TEST=test\n")
result = dotenv.find_dotenv(usecwd=True)
assert result == str(dotenv_file)
assert result == str(dotenv_path)
@mock.patch.dict(os.environ, {}, clear=True)
def test_load_dotenv_existing_file(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_load_dotenv_existing_file(dotenv_path):
dotenv_path.write_text("a=b")
result = dotenv.load_dotenv(dotenv_file)
result = dotenv.load_dotenv(dotenv_path)

@@ -289,7 +272,6 @@ assert result is True

@mock.patch.dict(os.environ, {"a": "c"}, clear=True)
def test_load_dotenv_existing_variable_no_override(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_load_dotenv_existing_variable_no_override(dotenv_path):
dotenv_path.write_text("a=b")
result = dotenv.load_dotenv(dotenv_file, override=False)
result = dotenv.load_dotenv(dotenv_path, override=False)

@@ -301,7 +283,6 @@ assert result is True

@mock.patch.dict(os.environ, {"a": "c"}, clear=True)
def test_load_dotenv_existing_variable_override(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_load_dotenv_existing_variable_override(dotenv_path):
dotenv_path.write_text("a=b")
result = dotenv.load_dotenv(dotenv_file, override=True)
result = dotenv.load_dotenv(dotenv_path, override=True)

@@ -313,7 +294,6 @@ assert result is True

@mock.patch.dict(os.environ, {"a": "c"}, clear=True)
def test_load_dotenv_redefine_var_used_in_file_no_override(dotenv_file):
with open(dotenv_file, "w") as f:
f.write('a=b\nd="${a}"')
def test_load_dotenv_redefine_var_used_in_file_no_override(dotenv_path):
dotenv_path.write_text('a=b\nd="${a}"')
result = dotenv.load_dotenv(dotenv_file)
result = dotenv.load_dotenv(dotenv_path)

@@ -325,7 +305,6 @@ assert result is True

@mock.patch.dict(os.environ, {"a": "c"}, clear=True)
def test_load_dotenv_redefine_var_used_in_file_with_override(dotenv_file):
with open(dotenv_file, "w") as f:
f.write('a=b\nd="${a}"')
def test_load_dotenv_redefine_var_used_in_file_with_override(dotenv_path):
dotenv_path.write_text('a=b\nd="${a}"')
result = dotenv.load_dotenv(dotenv_file, override=True)
result = dotenv.load_dotenv(dotenv_path, override=True)

@@ -347,7 +326,6 @@ assert result is True

@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")
def test_load_dotenv_file_stream(dotenv_path):
dotenv_path.write_text("a=b")
with open(dotenv_file, "r") as f:
with dotenv_path.open() as f:
result = dotenv.load_dotenv(stream=f)

@@ -370,3 +348,3 @@

"""))
os.chdir(str(tmp_path))
os.chdir(tmp_path)

@@ -378,7 +356,6 @@ result = sh.Command(sys.executable)(code_path)

def test_dotenv_values_file(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_dotenv_values_file(dotenv_path):
dotenv_path.write_text("a=b")
result = dotenv.dotenv_values(dotenv_file)
result = dotenv.dotenv_values(dotenv_path)

@@ -438,9 +415,8 @@ assert result == {"a": "b"}

def test_dotenv_values_file_stream(dotenv_file):
with open(dotenv_file, "w") as f:
f.write("a=b")
def test_dotenv_values_file_stream(dotenv_path):
dotenv_path.write_text("a=b")
with open(dotenv_file, "r") as f:
with dotenv_path.open() as f:
result = dotenv.dotenv_values(stream=f)
assert result == {"a": "b"}