Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept Python 3.6 path-like objects for read_env #313

Merged
merged 3 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Added
- Python 3.9, 3.10 and pypy 3.7 are now supported
- Django 3.1 and 3.2 are now supported
- Added missed classifiers to ``setup.py``
- Accept Python 3.6 path-like objects for ``read_env``

Fixed
+++++
Expand Down
9 changes: 8 additions & 1 deletion environ/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@

from .compat import DJANGO_POSTGRES, ImproperlyConfigured, json, REDIS_DRIVER

try:
from os import PathLike
Openable = (str, PathLike)
except ImportError:
Openable = (str,)


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -735,7 +742,7 @@ def read_env(cls, env_file=None, **overrides):
return

try:
if isinstance(env_file, str):
if isinstance(env_file, Openable):
with open(env_file) as f:
content = f.read()
else:
Expand Down
6 changes: 0 additions & 6 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
[bumpversion]
current_version = 0.6.0
commit = True
tag = True
files = setup.py environ/environ.py docs/conf.py

[bdist_wheel]
universal = 1

28 changes: 28 additions & 0 deletions tests/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,34 @@ def setup_method(self, method):
PATH_VAR=Path(__file__, is_file=True).__root__
)

def test_read_env_path_like(self):
import pathlib
import tempfile

path_like = (pathlib.Path(tempfile.gettempdir()) / 'test_pathlib.env')
try:
path_like.unlink()
except FileNotFoundError:
pass

assert not path_like.exists()

env_key = 'SECRET'
env_val = 'enigma'
env_str = env_key + '=' + env_val

# open() doesn't take path-like on Python < 3.6
try:
with open(path_like, 'w', encoding='utf-8') as f:
f.write(env_str + '\n')
except TypeError:
return

assert path_like.exists()
self.env.read_env(path_like)
assert env_key in self.env.ENVIRON
assert self.env.ENVIRON[env_key] == env_val


class TestSubClass(TestEnv):
def setup_method(self, method):
Expand Down
26 changes: 16 additions & 10 deletions tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,28 @@ def test_comparison():


def test_sum():
"""Make sure Path correct handle __add__."""
assert Path('/') + 'home' == Path('/home')
assert Path('/') + '/home/public' == Path('/home/public')


def test_subtraction():
"""Make sure Path correct handle __sub__."""
assert Path('/home/dev/public') - 2 == Path('/home')
assert Path('/home/dev/public') - 'public' == Path('/home/dev')


def test_subtraction_not_int():
"""Subtraction with an invalid type should raise TypeError."""
with pytest.raises(TypeError) as excinfo:
Path('/home/dev/') - 'not int'
assert str(excinfo.value) == (
"unsupported operand type(s) for -: '<class 'environ.environ.Path'>' "
"and '<class 'str'>' unless value of <class 'environ.environ.Path'> "
"ends with value of <class 'str'>"
)


def test_required_path():
root = Path('/home')
with pytest.raises(ImproperlyConfigured) as excinfo:
Expand All @@ -81,16 +97,6 @@ def test_required_path():
assert "Create required path:" in str(excinfo.value)


def test_subtraction_not_int():
with pytest.raises(TypeError) as excinfo:
Path('/home/dev/') - 'not int'
assert str(excinfo.value) == (
"unsupported operand type(s) for -: '<class 'environ.environ.Path'>' "
"and '<class 'str'>' unless value of <class 'environ.environ.Path'> "
"ends with value of <class 'str'>"
)


def test_complex_manipulation(volume):
root = Path('/home')
public = root.path('public')
Expand Down