Skip to content

Commit

Permalink
Add support for defaults in dict interface (#61)
Browse files Browse the repository at this point in the history
Add support for default in dict interface

Also detects broken symlink by raising FileNotFoundError
  • Loading branch information
ticosax committed Mar 26, 2018
1 parent de7d921 commit cf05379
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
24 changes: 17 additions & 7 deletions envdir/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ class _EmptyFile(Exception):
pass


try:
FileNotFoundError
except NameError: # <python3
FileNotFoundError = OSError

_sentinel = object()


class Env(UserDict):
"""
An dict-like object to represent an envdir environment with extensive
Expand All @@ -36,11 +44,13 @@ def __enter__(self):
def __exit__(self, type, value, traceback):
self.clear()

def __getitem__(self, name):
def __getitem__(self, name, default=_sentinel):
try:
return self._get(name)
except _EmptyFile:
pass
return self._get(name, default=default)
except (_EmptyFile, FileNotFoundError):
if default is _sentinel:
raise KeyError(name)
return default

def __setitem__(self, name, value):
self._write(**{name: value})
Expand Down Expand Up @@ -69,12 +79,12 @@ def _load(self):
def _open(self, name, mode='r'):
return open(os.path.join(self.path, name), mode)

def _get(self, name, default=None):
def _get(self, name, default=_sentinel):
path = os.path.join(self.path, name)
if not os.path.exists(path):
return default
if os.stat(path).st_size == 0:
raise _EmptyFile
if not os.path.exists(path):
return default
with self._open(name) as var:
return var.read().strip('\n').replace('\x00', '\n')

Expand Down
24 changes: 23 additions & 1 deletion envdir/test_envdir.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
import envdir
from envdir.runner import Response

try:
FileNotFoundError
except NameError: # <python3
FileNotFoundError = OSError


@pytest.fixture(scope="module")
def run():
Expand Down Expand Up @@ -379,6 +384,10 @@ def test_dict_like(tmpenvdir):
env.clear()
assert list(env.items()) == []
assert 'ITER' not in os.environ
with pytest.raises(KeyError):
env['DOESNOTEXISTS']
default = object()
assert env.get('DOESNOTEXISTS', default) is default

with envdir.open(str(tmpenvdir)) as env:
assert list(env.items()) == [('ITER', 'test')]
Expand Down Expand Up @@ -428,7 +437,7 @@ def test_context_manager_item(tmpenvdir):
@pytest.mark.skipif(sys.platform == 'win32',
reason="Symlinks are not supported on windows")
def test_envdir_follows_symlinks(run, tmpenvdir, monkeypatch):
"Default cases."
"""Check envdir follows symbolic links"""
monkeypatch.setattr(os, 'execvpe', functools.partial(mocked_execvpe,
monkeypatch))
tmpenvdir.join('DEFAULT').mksymlinkto('SYMLINK_ENV')
Expand All @@ -440,3 +449,16 @@ def test_envdir_follows_symlinks(run, tmpenvdir, monkeypatch):
assert os.environ['SYMLINK_ENV'] == 'test'
assert response.value.status == 0
assert response.value.message == ''


@pytest.mark.skipif(sys.platform == 'win32',
reason="Symlinks are not supported on windows")
def test_envdir_raise_broken_symlinks(run, tmpenvdir, monkeypatch):
"""If broken symlink is encountered, raise loudly"""
monkeypatch.setattr(os, 'execvpe', functools.partial(mocked_execvpe,
monkeypatch))
tmpenvdir.join('DEFAULT').mksymlinkto('SYMLINK_ENV')
tmpenvdir.join('DEFAULT').write('test')
tmpenvdir.join('SYMLINK_ENV').remove()
with pytest.raises(FileNotFoundError):
run('envdir', str(tmpenvdir), 'ls')

0 comments on commit cf05379

Please sign in to comment.