python-dotenv
Advanced tools
| 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 |
+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 |
+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 |
+33
-7
| 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 |
+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 |
+19
-9
| 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 |
+41
-52
| 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() |
+86
-110
@@ -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"} |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
160044
4.19%43
2.38%1583
3.67%