From bc3520f670ffe7744f21306e0d405bbd8841806a Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Wed, 6 Oct 2021 20:16:28 -0600 Subject: [PATCH 1/3] Changed tuple or list to iterable --- gemd/util/impl.py | 21 +++++++++++++-------- gemd/util/tests/test_foreach.py | 17 +++++++++++++++++ setup.py | 2 +- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/gemd/util/impl.py b/gemd/util/impl.py index e6f00060..37867e96 100644 --- a/gemd/util/impl.py +++ b/gemd/util/impl.py @@ -5,6 +5,8 @@ from gemd.entity.base_entity import BaseEntity from gemd.entity.dict_serializable import DictSerializable from gemd.entity.link_by_uid import LinkByUID + +from collections.abc import Reversible, Iterable from toolz import concatv @@ -63,7 +65,8 @@ def func(obj): # The overhead for all the invocations of isinstance was substantial isinstance_base_entity = _cached_isinstance_generator(BaseEntity) -isinstance_list_or_tuple = _cached_isinstance_generator((list, tuple)) +isinstance_iterable = _cached_isinstance_generator(Iterable) +isinstance_reversible = _cached_isinstance_generator(Reversible) isinstance_list = _cached_isinstance_generator(list) isinstance_tuple = _cached_isinstance_generator(tuple) isinstance_dict = _cached_isinstance_generator(dict) @@ -289,15 +292,15 @@ def recursive_foreach(obj: Union[List, Tuple, Dict, BaseEntity, DictSerializable if apply_first and isinstance_base_entity(this): func(this) - if isinstance_list_or_tuple(this): - for x in this: - queue.append(x) - elif isinstance_dict(this): + if isinstance_dict(this): for x in concatv(this.keys(), this.values()): queue.append(x) elif isinstance_dict_serializable(this): for k, x in this.__dict__.items(): queue.append(x) + elif isinstance_iterable(this): + for x in this: + queue.append(x) if not apply_first and isinstance_base_entity(this): func(this) @@ -343,15 +346,17 @@ def recursive_flatmap(obj: Union[List, Tuple, Dict, BaseEntity, DictSerializable if isinstance_base_entity(this): res.extend(func(this)) - if isinstance_list_or_tuple(this): - queue.extend(reversed(this)) # Preserve order of the list/tuple - elif isinstance_dict(this): + if isinstance_dict(this): queue.extend(concatv(this.keys(), this.values())) elif isinstance_dict_serializable(this): for k, x in sorted(this.__dict__.items()): if unidirectional and isinstance_base_entity(this) and k in this.skip: continue queue.append(x) + elif isinstance_reversible(this): + queue.extend(reversed(this)) # Preserve order of the list/tuple + elif isinstance_iterable(this): + queue.extend(this) # Preserve order of the list/tuple return res diff --git a/gemd/util/tests/test_foreach.py b/gemd/util/tests/test_foreach.py index a267efe3..600e586b 100644 --- a/gemd/util/tests/test_foreach.py +++ b/gemd/util/tests/test_foreach.py @@ -28,3 +28,20 @@ def test_recursive_foreach(): "property_template" ] assert sorted(types) == sorted(expected) + + +def test_more_iterable_types(): + obj = MaterialRun("foo", tags=["1", "2", "3"]) + + assert "1" in obj.tags + recursive_foreach({obj}, lambda x: x.tags.remove("1")) + assert "1" not in obj.tags + + dct = {obj: obj} + assert "2" in obj.tags + recursive_foreach(dct.keys(), lambda x: x.tags.remove("2")) + assert "2" not in obj.tags + + assert "3" in obj.tags + recursive_foreach(dct.values(), lambda x: x.tags.remove("3")) + assert "3" not in obj.tags diff --git a/setup.py b/setup.py index 0fcf7a03..3b030436 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup(name='gemd', - version='1.2.0', + version='1.2.1', url='http://github.com/CitrineInformatics/gemd-python', description="Python binding for Citrine's GEMD data model", author='Max Hutchinson', From ec55af45529a4a061dac2e70c9f99109516f626c Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Wed, 6 Oct 2021 20:24:47 -0600 Subject: [PATCH 2/3] flake8, complete testing --- gemd/util/tests/test_flatten.py | 21 +++++++++++++++++++++ gemd/util/tests/test_foreach.py | 1 + 2 files changed, 22 insertions(+) diff --git a/gemd/util/tests/test_flatten.py b/gemd/util/tests/test_flatten.py index b237f51b..af5825cf 100644 --- a/gemd/util/tests/test_flatten.py +++ b/gemd/util/tests/test_flatten.py @@ -98,3 +98,24 @@ def test_recursive_flatmap_maintains_order(): p2 = ProcessSpec(name="two") orig = [p1, p2] assert [x.name for x in orig] == recursive_flatmap(orig, lambda x: [x.name]) + + +def test_more_iterable_types(): + """Verify recursive_flatmap behaves for additional iterable types.""" + obj = MaterialRun("foo", tags=["1", "2", "3"]) + + assert "1" in obj.tags + res = recursive_flatmap({obj}, lambda x: [x.tags.pop(0)]) + assert "1" in res + assert "1" not in obj.tags + + dct = {obj: obj} + assert "2" in obj.tags + res = recursive_flatmap(dct.keys(), lambda x: [x.tags.pop(0)]) + assert "2" in res + assert "2" not in obj.tags + + assert "3" in obj.tags + res = recursive_flatmap(dct.values(), lambda x: [x.tags.pop(0)]) + assert "3" in res + assert "3" not in obj.tags diff --git a/gemd/util/tests/test_foreach.py b/gemd/util/tests/test_foreach.py index 600e586b..6334fa98 100644 --- a/gemd/util/tests/test_foreach.py +++ b/gemd/util/tests/test_foreach.py @@ -31,6 +31,7 @@ def test_recursive_foreach(): def test_more_iterable_types(): + """Verify recursive_foreach behaves for additional iterable types.""" obj = MaterialRun("foo", tags=["1", "2", "3"]) assert "1" in obj.tags From ee3a07311d2b483cb36a05860b37dda2e8659139 Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Thu, 7 Oct 2021 10:39:54 -0600 Subject: [PATCH 3/3] Remove copy-pasta comment --- gemd/util/impl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gemd/util/impl.py b/gemd/util/impl.py index 37867e96..efefa52f 100644 --- a/gemd/util/impl.py +++ b/gemd/util/impl.py @@ -356,7 +356,7 @@ def recursive_flatmap(obj: Union[List, Tuple, Dict, BaseEntity, DictSerializable elif isinstance_reversible(this): queue.extend(reversed(this)) # Preserve order of the list/tuple elif isinstance_iterable(this): - queue.extend(this) # Preserve order of the list/tuple + queue.extend(this) # No control over order return res