Skip to content

Commit

Permalink
Fix #154, handle empty pmap as leaf node in transformations
Browse files Browse the repository at this point in the history
  • Loading branch information
tobgu committed May 11, 2019
1 parent 6ec9bf0 commit 30f1381
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 5 deletions.
18 changes: 15 additions & 3 deletions pyrsistent/_transformations.py
Expand Up @@ -10,6 +10,9 @@
from inspect import getargspec


_EMPTY_SENTINEL = object()


def inc(x):
""" Add one to the current value """
return x + 1
Expand Down Expand Up @@ -39,6 +42,7 @@ def ny(_):
""" Matcher that matches any value """
return True


# Support functions
def _chunks(l, n):
for i in range(0, len(l), n):
Expand Down Expand Up @@ -80,7 +84,6 @@ def _get(structure, key, default):


def _get_keys_and_values(structure, key_spec):
from pyrsistent._pmap import pmap
if callable(key_spec):
# Support predicates as callable objects in the path
arity = _get_arity(key_spec)
Expand All @@ -99,7 +102,7 @@ def _get_keys_and_values(structure, key_spec):
)

# Non-callables are used as-is as a key.
return [(key_spec, _get(structure, key_spec, pmap()))]
return [(key_spec, _get(structure, key_spec, _EMPTY_SENTINEL))]


if signature is None:
Expand All @@ -116,16 +119,25 @@ def _get_arity(f):
and p.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD)
)


def _update_structure(structure, kvs, path, command):
from pyrsistent._pmap import pmap
e = structure.evolver()
if not path and command is discard:
# Do this in reverse to avoid index problems with vectors. See #92.
for k, v in reversed(kvs):
discard(e, k)
else:
for k, v in kvs:
is_empty = False
if v is _EMPTY_SENTINEL:
# Allow expansion of structure but make sure to cover the case
# when an empty pmap is added as leaf node. See #154.
is_empty = True
v = pmap()

result = _do_to_path(v, path, command)
if result is not v:
if result is not v or is_empty:
e[k] = result

return e.persistent()
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -84,7 +84,7 @@ def build_extension(self, ext):
'Programming Language :: Python :: Implementation :: PyPy',
],
test_suite='tests',
tests_require=['pytest','hypothesis<5'],
tests_require=['pytest', 'hypothesis<5'],
scripts=[],
setup_requires=pytest_runner,
ext_modules=extensions,
Expand Down
7 changes: 6 additions & 1 deletion tests/transform_test.py
@@ -1,4 +1,4 @@
from pyrsistent import freeze, inc, discard, rex, ny, field, PClass
from pyrsistent import freeze, inc, discard, rex, ny, field, PClass, pmap


def test_callable_command():
Expand Down Expand Up @@ -110,3 +110,8 @@ def test_no_transformation_returns_the_same_structure():

def test_discard_multiple_elements_in_pvector():
assert freeze([0, 1, 2, 3, 4]).transform([lambda i: i % 2], discard) == freeze([0, 2, 4])


def test_transform_insert_empty_pmap():
m = pmap().transform(['123'], pmap())
assert m == pmap({'123': pmap()})

0 comments on commit 30f1381

Please sign in to comment.