From 79aa9c85c494719d8148d8f868b10072eb1b98fb Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Wed, 10 Jan 2024 10:51:43 -0700 Subject: [PATCH 1/4] Remove deprecated --- gemd/entity/link_by_uid.py | 15 ++---------- gemd/enumeration/base_enumeration.py | 30 ----------------------- gemd/json/gemd_json.py | 34 +------------------------- gemd/util/impl.py | 11 --------- scripts/run_tests.sh | 2 +- setup.py | 2 +- tests/entity/test_link_by_uid.py | 9 ------- tests/enumeration/test_enumeration.py | 26 -------------------- tests/json/test_json.py | 35 +++++---------------------- tests/units/__init__.py | 0 tests/util/test_substitute_links.py | 21 +++++----------- 11 files changed, 17 insertions(+), 168 deletions(-) delete mode 100644 tests/units/__init__.py diff --git a/gemd/entity/link_by_uid.py b/gemd/entity/link_by_uid.py index bec0b045..73cd3414 100644 --- a/gemd/entity/link_by_uid.py +++ b/gemd/entity/link_by_uid.py @@ -1,6 +1,5 @@ """A unique id that stands in for a data object.""" import uuid -from warnings import warn from gemd.entity.dict_serializable import DictSerializable @@ -27,7 +26,7 @@ def __repr__(self): return str({"scope": self.scope, "id": self.id}) @classmethod - def from_entity(cls, entity, name=None, *, scope=None): + def from_entity(cls, entity, *, scope=None): """ Create LinkByUID from in-memory object. @@ -41,8 +40,6 @@ def from_entity(cls, entity, name=None, *, scope=None): ---------- entity: BaseEntity The entity to substitute with a LinkByUID - name: str, optional (Deprecated) - The desired scope of the id. scope: str, optional The desired scope of the id. @@ -52,16 +49,8 @@ def from_entity(cls, entity, name=None, *, scope=None): A link object that references `entity` through its scope and id. """ - if name is None and scope is None: + if scope is None: scope = "auto" # set default - elif name is None and scope is not None: # The rest of these conditions to be deleted - pass # Normal workflow - elif name is not None and scope is None: - warn("The positional argument 'name' is deprecated. When selecting a default scope, " - "use the 'scope' keyword argument.", DeprecationWarning) - scope = name - elif name is not None and scope is not None: - raise ValueError("Specify the 'name' parameter or 'scope' parameter, not both.") if scope in entity.uids: uid = entity.uids[scope] diff --git a/gemd/enumeration/base_enumeration.py b/gemd/enumeration/base_enumeration.py index cb8a3df5..a6a731a8 100644 --- a/gemd/enumeration/base_enumeration.py +++ b/gemd/enumeration/base_enumeration.py @@ -66,36 +66,6 @@ def from_str(cls, val: str, *, exception: bool = False) -> Optional["BaseEnumera raise ValueError(f"{val} is not a valid {cls}; valid choices are {[x for x in cls]}") return result - @classmethod - @deprecated(deprecated_in="1.15.0", - removed_in="2.0.0", - details="Enumerations autocast to values now.") - def get_value(cls, name: str) -> str: - """ - Return a valid value associated with name. - - If name is equal to one of the enum members, or to the value - associated with an enum member, then return the relevant value. - """ - if name is None: - return None - return cls.from_str(name, exception=True).value - - @classmethod - @deprecated(deprecated_in="1.15.0", - removed_in="2.0.0", - details="Use from_str for retreiving the correct Enum object.") - def get_enum(cls, name: str) -> "BaseEnumeration": - """ - Return the enumeration associated with name. - - If name is equal to one of the enum members, or to the value - associated with an enum member, then return the relevant enumeration. - """ - if name is None: - return None - return cls.from_str(name, exception=True) - def __str__(self): """Return the value of the enumeration object.""" return self.value diff --git a/gemd/json/gemd_json.py b/gemd/json/gemd_json.py index f01276dc..a199bfa9 100644 --- a/gemd/json/gemd_json.py +++ b/gemd/json/gemd_json.py @@ -1,5 +1,4 @@ -import inspect -from deprecation import deprecated +import json as json_builtin from typing import Dict, Any, Type from gemd.entity.dict_serializable import DictSerializable @@ -7,7 +6,6 @@ from gemd.entity.link_by_uid import LinkByUID from gemd.json import GEMDEncoder from gemd.util import flatten, substitute_links, set_uuids -import json as json_builtin class GEMDJson(object): @@ -211,36 +209,6 @@ def raw_loads(self, json_str, **kwargs): object_hook=lambda x: self._load_and_index(x, index, clazz_index=clazz_index), **kwargs) - @deprecated(deprecated_in="1.13.0", removed_in="2.0.0", - details="Classes are now automatically registered when extending BaseEntity") - def register_classes(self, classes): - """ - Register additional classes to the custom deserialization object hook. - - This allows for additional DictSerializable subclasses to be registered to the class index - that is used to decode the type strings. Existing keys are overwritten, allowing classes - in the gemd package to be subclassed and overridden in the class index by their - subclass. - - Parameters - ---------- - classes: Dict[str, type] - a dict mapping the type string to the class - - """ - if not isinstance(classes, dict): - raise ValueError("Must be given a dict from str -> class") - non_string_keys = [x for x in classes.keys() if not isinstance(x, str)] - if len(non_string_keys) > 0: - raise ValueError( - "The keys must be strings, but got {} as keys".format(non_string_keys)) - non_class_values = [x for x in classes.values() if not inspect.isclass(x)] - if len(non_class_values) > 0: - raise ValueError( - "The values must be classes, but got {} as values".format(non_class_values)) - - self._clazz_index.update(classes) - @staticmethod def _load_and_index( d: Dict[str, Any], diff --git a/gemd/util/impl.py b/gemd/util/impl.py index 64f64acb..8dfca73d 100644 --- a/gemd/util/impl.py +++ b/gemd/util/impl.py @@ -3,7 +3,6 @@ import functools from typing import Optional, Union, Type, Iterable, MutableSequence, List, Tuple, Mapping, \ Callable, Any, Reversible, ByteString -from warnings import warn from gemd.entity.base_entity import BaseEntity from gemd.entity.dict_serializable import DictSerializable @@ -271,7 +270,6 @@ def _make_index(_obj: BaseEntity): def substitute_links(obj: Any, scope: Optional[str] = None, *, - native_uid: str = None, allow_fallback: bool = True, inplace: bool = False ): @@ -287,21 +285,12 @@ def substitute_links(obj: Any, target of the operation scope: Optional[str], optional preferred scope to use for creating LinkByUID objects (Default: None) - native_uid: str, optional - DEPRECATED; former name for scope argument allow_fallback: bool, optional whether to grab another scope/id if chosen scope is missing (Default: True). inplace: bool, optional whether to replace objects in place, as opposed to returning a copy (Default: False). """ - if native_uid is not None: - warn("The keyword argument 'native_uid' is deprecated. When selecting a default scope, " - "use the 'scope' keyword argument.", DeprecationWarning) - if scope is not None: - raise ValueError("Both 'scope' and 'native_uid' keywords passed.") - scope = native_uid - if inplace: method = _substitute_inplace else: diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 13683a4a..15055b9e 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -36,7 +36,7 @@ then python $REPO_DIR/scripts/validate_version_bump.py || fi flake8 $REPO_DIR/gemd || exit 1; -derp $REPO_DIR $REPO_DIR/setup.py || exit 1; +derp $REPO_DIR/gemd $REPO_DIR/setup.py || exit 1; pytest $QUIET $EXITFIRST --cov=$REPO_DIR/gemd \ --cov-report term-missing:skip-covered \ --cov-config=$REPO_DIR/tox.ini --no-cov-on-fail --cov-fail-under=100 \ diff --git a/setup.py b/setup.py index ae5cc13d..68e5dd24 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ packages.append("") setup(name='gemd', - version='1.17.0', + version='2.0.0', python_requires='>=3.8', url='http://github.com/CitrineInformatics/gemd-python', description="Python binding for Citrine's GEMD data model", diff --git a/tests/entity/test_link_by_uid.py b/tests/entity/test_link_by_uid.py index 152849e6..40b6b174 100644 --- a/tests/entity/test_link_by_uid.py +++ b/tests/entity/test_link_by_uid.py @@ -36,15 +36,6 @@ def test_from_entity(): link1 = LinkByUID.from_entity(run, scope='foo') assert (link1.scope, link1.id) == ('foo', 'bar') - with pytest.deprecated_call(): - assert LinkByUID.from_entity(run, 'foo').scope == 'foo' - - with pytest.deprecated_call(): - assert LinkByUID.from_entity(run, name='foo').scope == 'foo' - - with pytest.raises(ValueError): - LinkByUID.from_entity(run, name='scope1', scope='scope2') - def test_equality(): """Test that the __eq__ method performs as expected.""" diff --git a/tests/enumeration/test_enumeration.py b/tests/enumeration/test_enumeration.py index 80950033..fbed117a 100644 --- a/tests/enumeration/test_enumeration.py +++ b/tests/enumeration/test_enumeration.py @@ -8,32 +8,6 @@ from gemd.json import loads, dumps -def test_values(): - """Test that values can be validated and pulled from an enumeration.""" - class GoodClass(BaseEnumeration): - RED = "Red" - BLUE = "Blue" - - with pytest.deprecated_call(): - assert GoodClass.get_value("Red") == "Red" - with pytest.deprecated_call(): - assert GoodClass.get_value(GoodClass.BLUE) == "Blue" - with pytest.deprecated_call(): - assert GoodClass.get_value(None) is None - with pytest.deprecated_call(): - assert GoodClass.get_enum("Red") == GoodClass.RED - with pytest.deprecated_call(): - assert GoodClass.get_enum(GoodClass.BLUE) == GoodClass.BLUE - with pytest.deprecated_call(): - assert GoodClass.get_enum(None) is None - with pytest.deprecated_call(): - with pytest.raises(ValueError): - GoodClass.get_value("Green") - with pytest.deprecated_call(): - with pytest.raises(ValueError): - GoodClass.get_enum("Green") - - def test_json_serde(): """Test that values can be ser/de using our custom json loads/dumps.""" # Enums are only used in the context of another class -- diff --git a/tests/json/test_json.py b/tests/json/test_json.py index d915a734..aa335538 100644 --- a/tests/json/test_json.py +++ b/tests/json/test_json.py @@ -1,5 +1,5 @@ """Test serialization and deserialization of gemd objects.""" -import json +import json as json_builtin from copy import deepcopy from uuid import uuid4 @@ -37,13 +37,13 @@ def test_serialize(): parameters=parameter, material=material) # serialize the root of the tree - native_object = json.loads(dumps(measurement)) + native_object = json_builtin.loads(dumps(measurement)) # ingredients don't get serialized on the process assert(len(native_object["context"]) == 5) assert(native_object["object"]["type"] == LinkByUID.typ) - # serialize all of the nodes - native_batch = json.loads(dumps([material, process, measurement, ingredient])) + # serialize all the nodes + native_batch = json_builtin.loads(dumps([material, process, measurement, ingredient])) assert(len(native_batch["context"]) == 5) assert(len(native_batch["object"]) == 4) assert(all(x["type"] == LinkByUID.typ for x in native_batch["object"])) @@ -138,7 +138,7 @@ def test_thin_dumps(): meas_spec = MeasurementSpec("measurement", uids={'my_scope': '324324'}) meas = MeasurementRun("The measurement", spec=meas_spec, material=mat) - thin_copy = MeasurementRun.build(json.loads(GEMDJson().thin_dumps(meas))) + thin_copy = MeasurementRun.build(json_builtin.loads(GEMDJson().thin_dumps(meas))) assert isinstance(thin_copy, MeasurementRun) assert isinstance(thin_copy.material, LinkByUID) assert isinstance(thin_copy.spec, LinkByUID) @@ -188,8 +188,6 @@ class MyProcessSpec(ProcessSpec): normal = GEMDJson() custom = GEMDJson() - with pytest.warns(DeprecationWarning, match="register_classes"): - custom.register_classes({MyProcessSpec.typ: MyProcessSpec}) obj = ProcessSpec(name="foo") assert not isinstance(normal.copy(obj), MyProcessSpec),\ @@ -199,23 +197,6 @@ class MyProcessSpec(ProcessSpec): "Custom GEMDJson didn't deserialize as MyProcessSpec" -def test_register_argument_validation(): - """Test that register_classes argument is type checked.""" - orig = GEMDJson() - - with pytest.raises(ValueError): - with pytest.warns(DeprecationWarning, match="register_classes"): - orig.register_classes("foo") - - with pytest.raises(ValueError): - with pytest.warns(DeprecationWarning, match="register_classes"): - orig.register_classes({"foo": orig}) - - with pytest.raises(ValueError): - with pytest.warns(DeprecationWarning, match="register_classes"): - orig.register_classes({ProcessSpec: ProcessSpec}) - - def test_pure_substitutions(): """Make sure substitute methods don't mutate inputs.""" json_str = ''' @@ -249,11 +230,7 @@ def test_pure_substitutions(): ''' index = {} clazz_index = DictSerializable.class_mapping - original = json.loads(json_str, - object_hook=lambda x: GEMDJson()._load_and_index(x, - index, - clazz_index) - ) + original = json_builtin.loads(json_str, object_hook=lambda x: GEMDJson()._load_and_index(x, index, clazz_index)) frozen = deepcopy(original) loaded = substitute_objects(original, index) assert original == frozen diff --git a/tests/units/__init__.py b/tests/units/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/util/test_substitute_links.py b/tests/util/test_substitute_links.py index 0dea78b0..6033ff15 100644 --- a/tests/util/test_substitute_links.py +++ b/tests/util/test_substitute_links.py @@ -79,24 +79,15 @@ def test_signature(): """Exercise various permutations of the substitute_links sig.""" spec = ProcessSpec("A process spec", uids={'my': 'spec'}) - with pytest.warns(DeprecationWarning): - run1 = ProcessRun("First process run", uids={'my': 'run1'}, spec=spec) - assert isinstance(substitute_links(run1, native_uid='my').spec, LinkByUID) + run1 = ProcessRun("First process run", uids={'my': 'run1'}, spec=spec) + assert isinstance(substitute_links(run1, scope='my').spec, LinkByUID) run2 = ProcessRun("Second process run", uids={'my': 'run2'}, spec=spec) - assert isinstance(substitute_links(run2, scope='my').spec, LinkByUID) + assert isinstance(substitute_links(run2, 'my').spec, LinkByUID) - run3 = ProcessRun("Third process run", uids={'my': 'run3'}, spec=spec) - assert isinstance(substitute_links(run3, 'my').spec, LinkByUID) - - with pytest.raises(ValueError): # Test deprecated auto-population - run4 = ProcessRun("Fourth process run", uids={'my': 'run4'}, spec=spec) - assert isinstance(substitute_links(run4, 'other', allow_fallback=False).spec, LinkByUID) - - with pytest.warns(DeprecationWarning): - with pytest.raises(ValueError): # Test deprecated auto-population - run5 = ProcessRun("Fifth process run", uids={'my': 'run4'}, spec=spec) - assert isinstance(substitute_links(run5, scope="my", native_uid="my").spec, LinkByUID) + with pytest.raises(ValueError): + run3 = ProcessRun("Third process run", uids={'my': 'run3'}, spec=spec) + assert isinstance(substitute_links(run3, 'other', allow_fallback=False).spec, LinkByUID) def test_inplace_v_not(): From 025f358995a3a227f1d0baa5625be54130493f57 Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Thu, 1 Feb 2024 14:49:32 -0700 Subject: [PATCH 2/4] PR feedback --- gemd/json/gemd_json.py | 12 ++++++------ tests/units/__init__.py | 0 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 tests/units/__init__.py diff --git a/gemd/json/gemd_json.py b/gemd/json/gemd_json.py index 7765a9dd..1e2e0d60 100644 --- a/gemd/json/gemd_json.py +++ b/gemd/json/gemd_json.py @@ -1,4 +1,4 @@ -import json as json_builtin +import json from typing import Dict, Any, Type from gemd.entity.dict_serializable import DictSerializable @@ -52,7 +52,7 @@ def dumps(self, obj, **kwargs) -> str: additional = flatten(res, self.scope) res = substitute_links(res) res["context"] = additional - return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) def loads(self, json_str: str, **kwargs): """ @@ -77,7 +77,7 @@ def loads(self, json_str: str, **kwargs): index = {} clazz_index = DictSerializable.class_mapping clazz_index.update(self._clazz_index) - raw = json_builtin.loads( + raw = json.loads( json_str, object_hook=lambda x: self._load_and_index(x, index, @@ -161,7 +161,7 @@ def raw_dumps(self, obj, **kwargs): A serialized string of `obj`, which could be nested """ - return json_builtin.dumps(obj, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json.dumps(obj, cls=GEMDEncoder, sort_keys=True, **kwargs) def thin_dumps(self, obj, **kwargs): """ @@ -182,7 +182,7 @@ def thin_dumps(self, obj, **kwargs): """ set_uuids(obj, self.scope) res = substitute_links(obj) - return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) def raw_loads(self, json_str, **kwargs): """ @@ -206,7 +206,7 @@ def raw_loads(self, json_str, **kwargs): index = {} clazz_index = DictSerializable.class_mapping clazz_index.update(self._clazz_index) - return json_builtin.loads( + return json.loads( json_str, object_hook=lambda x: self._load_and_index(x, index, clazz_index=clazz_index), **kwargs) diff --git a/tests/units/__init__.py b/tests/units/__init__.py new file mode 100644 index 00000000..e69de29b From f523fbcd3fc1b9d07dce714f22a4b1a58426f919 Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Thu, 1 Feb 2024 16:00:59 -0700 Subject: [PATCH 3/4] Migrate json imports to obvious aliases --- gemd/demo/cake.py | 4 ++-- gemd/demo/strehlow_and_cook.py | 10 +++++----- gemd/entity/dict_serializable.py | 4 ++-- gemd/entity/util.py | 4 ++-- gemd/json/gemd_json.py | 12 ++++++------ tests/demo/test_sac.py | 10 +++++----- tests/entity/object/test_material_run.py | 4 ++-- tests/test_examples.py | 4 ++-- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/gemd/demo/cake.py b/gemd/demo/cake.py index fb266340..ccf7f1fb 100644 --- a/gemd/demo/cake.py +++ b/gemd/demo/cake.py @@ -1,6 +1,6 @@ """Bake a cake.""" from io import BytesIO -import json +import json as json_builtin import random from gemd.entity.attribute import Condition, Parameter, Property, PropertyAndConditions @@ -1064,7 +1064,7 @@ def _find_name(name, material): with open("example_gemd_material_history.json", "w") as f: context_list = complete_material_history(cake) - f.write(json.dumps(context_list, indent=2)) + f.write(json_builtin.dumps(context_list, indent=2)) with open("example_gemd_material_template.json", "w") as f: f.write(encoder.thin_dumps(cake.template, indent=2)) diff --git a/gemd/demo/strehlow_and_cook.py b/gemd/demo/strehlow_and_cook.py index bc6f768a..1ff94a95 100644 --- a/gemd/demo/strehlow_and_cook.py +++ b/gemd/demo/strehlow_and_cook.py @@ -46,8 +46,8 @@ def import_table(filename=SMALL_TABLE): """Return the deserialized JSON table.""" from importlib.resources import read_text - import json - table = json.loads(read_text("gemd.demo", filename)) + import json as json_builtin + table = json_builtin.loads(read_text("gemd.demo", filename)) return table @@ -461,7 +461,7 @@ def make_display_table(structured): Defaults to DEMO_TEMPLATE_SCOPE if none provided. """ import os.path - import json + import json as json_builtin import sys args = sys.argv[1:] @@ -486,11 +486,11 @@ def make_display_table(structured): break with open(os.path.join(os.path.dirname(__file__), SMALL_TABLE), 'w') as f: - json.dump(reduced_list, f, indent=2) + json_builtin.dump(reduced_list, f, indent=2) print("\n\nJSON -- Training table") import gemd.json as je - print(json.dumps(json.loads(je.dumps(full_table))["object"], indent=2)) + print(json_builtin.dumps(json_builtin.loads(je.dumps(full_table))["object"], indent=2)) print("\n\nCSV -- Display table") display = make_display_table(full_table) diff --git a/gemd/entity/dict_serializable.py b/gemd/entity/dict_serializable.py index 664af86b..b151239f 100644 --- a/gemd/entity/dict_serializable.py +++ b/gemd/entity/dict_serializable.py @@ -1,7 +1,7 @@ from abc import ABC, ABCMeta from logging import getLogger -import json +import json as json_builtin import inspect import functools from typing import TypeVar, Union, Iterable, List, Mapping, Dict, Set, Any @@ -122,7 +122,7 @@ def dump(self) -> Dict[str, Any]: """ from gemd.json import GEMDJson encoder = GEMDJson() - return json.loads(encoder.raw_dumps(self)) + return json_builtin.loads(encoder.raw_dumps(self)) @staticmethod def build(d: Mapping[str, Any]) -> DictSerializableType: diff --git a/gemd/entity/util.py b/gemd/entity/util.py index 1cb8585a..cc6ecc35 100644 --- a/gemd/entity/util.py +++ b/gemd/entity/util.py @@ -116,7 +116,7 @@ def complete_material_history(mat) -> List[Dict[str, Any]]: """ from gemd.entity.base_entity import BaseEntity - import json + import json as json_builtin from gemd.json import dumps, loads from gemd.util.impl import substitute_links @@ -124,7 +124,7 @@ def complete_material_history(mat) -> List[Dict[str, Any]]: def body(obj: BaseEntity): copy = substitute_links(loads(dumps(obj))) - result.append(json.loads(dumps(copy))["context"][0]) + result.append(json_builtin.loads(dumps(copy))["context"][0]) recursive_foreach(mat, body, apply_first=False) diff --git a/gemd/json/gemd_json.py b/gemd/json/gemd_json.py index 1e2e0d60..7765a9dd 100644 --- a/gemd/json/gemd_json.py +++ b/gemd/json/gemd_json.py @@ -1,4 +1,4 @@ -import json +import json as json_builtin from typing import Dict, Any, Type from gemd.entity.dict_serializable import DictSerializable @@ -52,7 +52,7 @@ def dumps(self, obj, **kwargs) -> str: additional = flatten(res, self.scope) res = substitute_links(res) res["context"] = additional - return json.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) def loads(self, json_str: str, **kwargs): """ @@ -77,7 +77,7 @@ def loads(self, json_str: str, **kwargs): index = {} clazz_index = DictSerializable.class_mapping clazz_index.update(self._clazz_index) - raw = json.loads( + raw = json_builtin.loads( json_str, object_hook=lambda x: self._load_and_index(x, index, @@ -161,7 +161,7 @@ def raw_dumps(self, obj, **kwargs): A serialized string of `obj`, which could be nested """ - return json.dumps(obj, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json_builtin.dumps(obj, cls=GEMDEncoder, sort_keys=True, **kwargs) def thin_dumps(self, obj, **kwargs): """ @@ -182,7 +182,7 @@ def thin_dumps(self, obj, **kwargs): """ set_uuids(obj, self.scope) res = substitute_links(obj) - return json.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) def raw_loads(self, json_str, **kwargs): """ @@ -206,7 +206,7 @@ def raw_loads(self, json_str, **kwargs): index = {} clazz_index = DictSerializable.class_mapping clazz_index.update(self._clazz_index) - return json.loads( + return json_builtin.loads( json_str, object_hook=lambda x: self._load_and_index(x, index, clazz_index=clazz_index), **kwargs) diff --git a/tests/demo/test_sac.py b/tests/demo/test_sac.py index 1baea622..446e1096 100644 --- a/tests/demo/test_sac.py +++ b/tests/demo/test_sac.py @@ -1,8 +1,8 @@ """Test Strehlow & Cook demo.""" from gemd.demo.strehlow_and_cook import make_strehlow_table, make_strehlow_objects, \ minimal_subset, import_table -import gemd.json as je -import json +import gemd.json as gemd_json +import json as json_builtin def test_sac(): @@ -12,7 +12,7 @@ def test_sac(): # Check that all shapes of records serialize and deserialize for comp in sac: - assert je.loads(je.dumps(comp)) == comp + assert gemd_json.loads(gemd_json.dumps(comp)) == comp # Verify that specs are shared when compounds match for comp1 in sac: @@ -27,7 +27,7 @@ def test_sac(): # Make sure there's no migration with repeated serialization for row in sac_tbl: - assert je.dumps(je.loads(je.dumps(row))) == je.dumps(row) + assert gemd_json.dumps(gemd_json.loads(gemd_json.dumps(row))) == gemd_json.dumps(row) # Verify that the serialization trick for mocking a structured table works - json.dumps(json.loads(je.dumps(sac_tbl))["object"], indent=2) + json_builtin.dumps(json_builtin.loads(gemd_json.dumps(sac_tbl))["object"], indent=2) diff --git a/tests/entity/object/test_material_run.py b/tests/entity/object/test_material_run.py index 386cad80..b633f3e4 100644 --- a/tests/entity/object/test_material_run.py +++ b/tests/entity/object/test_material_run.py @@ -1,6 +1,6 @@ """Test of the material run object.""" import pytest -import json +import json as json_builtin from uuid import uuid4 from copy import deepcopy @@ -33,7 +33,7 @@ def test_material_run(): ) # Make sure that when property is serialized, origin (an enumeration) is serialized as a string - copy_prop = json.loads(dumps(mat_spec)) + copy_prop = json_builtin.loads(dumps(mat_spec)) copy_origin = copy_prop["context"][0]["properties"][0]['property']['origin'] assert isinstance(copy_origin, str) diff --git a/tests/test_examples.py b/tests/test_examples.py index 05052a0d..9ca9c125 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,5 +1,5 @@ """Test of a complicated set of interlocking data objects.""" -import json +import json as json_builtin from gemd.entity.object.ingredient_run import IngredientRun from toolz import keymap, merge, keyfilter @@ -167,4 +167,4 @@ def test_access_data(): # check that the serialization results in the correct number of objects in the preface # (note that neither measurements nor ingredients are serialized) - assert(len(json.loads(dumps(island))["context"]) == 26) + assert(len(json_builtin.loads(dumps(island))["context"]) == 26) From f5e326bfd99e30c4909111732551928e337028de Mon Sep 17 00:00:00 2001 From: Ken Kroenlein Date: Mon, 5 Feb 2024 10:53:41 -0700 Subject: [PATCH 4/4] Distinguish json & gemd.json imports of methods with the same name --- gemd/demo/cake.py | 5 +++-- gemd/demo/strehlow_and_cook.py | 8 +++---- gemd/entity/dict_serializable.py | 5 +++-- gemd/entity/util.py | 6 +++--- gemd/json/gemd_json.py | 12 +++++------ tests/entity/object/test_material_run.py | 16 +++++++------- tests/json/test_json.py | 27 ++++++++++++------------ tests/test_examples.py | 4 ++-- 8 files changed, 43 insertions(+), 40 deletions(-) diff --git a/gemd/demo/cake.py b/gemd/demo/cake.py index ccf7f1fb..95dc2bda 100644 --- a/gemd/demo/cake.py +++ b/gemd/demo/cake.py @@ -1,6 +1,5 @@ """Bake a cake.""" from io import BytesIO -import json as json_builtin import random from gemd.entity.attribute import Condition, Parameter, Property, PropertyAndConditions @@ -1059,12 +1058,14 @@ def _find_name(name, material): if __name__ == "__main__": + import json + encoder = GEMDJson() cake = make_cake(seed=42) with open("example_gemd_material_history.json", "w") as f: context_list = complete_material_history(cake) - f.write(json_builtin.dumps(context_list, indent=2)) + f.write(json.dumps(context_list, indent=2)) with open("example_gemd_material_template.json", "w") as f: f.write(encoder.thin_dumps(cake.template, indent=2)) diff --git a/gemd/demo/strehlow_and_cook.py b/gemd/demo/strehlow_and_cook.py index 1ff94a95..9c5a37f2 100644 --- a/gemd/demo/strehlow_and_cook.py +++ b/gemd/demo/strehlow_and_cook.py @@ -46,8 +46,8 @@ def import_table(filename=SMALL_TABLE): """Return the deserialized JSON table.""" from importlib.resources import read_text - import json as json_builtin - table = json_builtin.loads(read_text("gemd.demo", filename)) + import json + table = json.loads(read_text("gemd.demo", filename)) return table @@ -462,6 +462,7 @@ def make_display_table(structured): """ import os.path import json as json_builtin + import gemd.json as gemd_json import sys args = sys.argv[1:] @@ -489,8 +490,7 @@ def make_display_table(structured): json_builtin.dump(reduced_list, f, indent=2) print("\n\nJSON -- Training table") - import gemd.json as je - print(json_builtin.dumps(json_builtin.loads(je.dumps(full_table))["object"], indent=2)) + print(json_builtin.dumps(json_builtin.loads(gemd_json.dumps(full_table))["object"], indent=2)) print("\n\nCSV -- Display table") display = make_display_table(full_table) diff --git a/gemd/entity/dict_serializable.py b/gemd/entity/dict_serializable.py index b151239f..777ed1a2 100644 --- a/gemd/entity/dict_serializable.py +++ b/gemd/entity/dict_serializable.py @@ -1,7 +1,6 @@ from abc import ABC, ABCMeta from logging import getLogger -import json as json_builtin import inspect import functools from typing import TypeVar, Union, Iterable, List, Mapping, Dict, Set, Any @@ -121,8 +120,10 @@ def dump(self) -> Dict[str, Any]: """ from gemd.json import GEMDJson + import json + encoder = GEMDJson() - return json_builtin.loads(encoder.raw_dumps(self)) + return json.loads(encoder.raw_dumps(self)) @staticmethod def build(d: Mapping[str, Any]) -> DictSerializableType: diff --git a/gemd/entity/util.py b/gemd/entity/util.py index cc6ecc35..4d445266 100644 --- a/gemd/entity/util.py +++ b/gemd/entity/util.py @@ -117,14 +117,14 @@ def complete_material_history(mat) -> List[Dict[str, Any]]: """ from gemd.entity.base_entity import BaseEntity import json as json_builtin - from gemd.json import dumps, loads + import gemd.json as gemd_json from gemd.util.impl import substitute_links result = [] def body(obj: BaseEntity): - copy = substitute_links(loads(dumps(obj))) - result.append(json_builtin.loads(dumps(copy))["context"][0]) + copy = substitute_links(gemd_json.loads(gemd_json.dumps(obj))) + result.append(json_builtin.loads(gemd_json.dumps(copy))["context"][0]) recursive_foreach(mat, body, apply_first=False) diff --git a/gemd/json/gemd_json.py b/gemd/json/gemd_json.py index 7765a9dd..1e2e0d60 100644 --- a/gemd/json/gemd_json.py +++ b/gemd/json/gemd_json.py @@ -1,4 +1,4 @@ -import json as json_builtin +import json from typing import Dict, Any, Type from gemd.entity.dict_serializable import DictSerializable @@ -52,7 +52,7 @@ def dumps(self, obj, **kwargs) -> str: additional = flatten(res, self.scope) res = substitute_links(res) res["context"] = additional - return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) def loads(self, json_str: str, **kwargs): """ @@ -77,7 +77,7 @@ def loads(self, json_str: str, **kwargs): index = {} clazz_index = DictSerializable.class_mapping clazz_index.update(self._clazz_index) - raw = json_builtin.loads( + raw = json.loads( json_str, object_hook=lambda x: self._load_and_index(x, index, @@ -161,7 +161,7 @@ def raw_dumps(self, obj, **kwargs): A serialized string of `obj`, which could be nested """ - return json_builtin.dumps(obj, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json.dumps(obj, cls=GEMDEncoder, sort_keys=True, **kwargs) def thin_dumps(self, obj, **kwargs): """ @@ -182,7 +182,7 @@ def thin_dumps(self, obj, **kwargs): """ set_uuids(obj, self.scope) res = substitute_links(obj) - return json_builtin.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) + return json.dumps(res, cls=GEMDEncoder, sort_keys=True, **kwargs) def raw_loads(self, json_str, **kwargs): """ @@ -206,7 +206,7 @@ def raw_loads(self, json_str, **kwargs): index = {} clazz_index = DictSerializable.class_mapping clazz_index.update(self._clazz_index) - return json_builtin.loads( + return json.loads( json_str, object_hook=lambda x: self._load_and_index(x, index, clazz_index=clazz_index), **kwargs) diff --git a/tests/entity/object/test_material_run.py b/tests/entity/object/test_material_run.py index b633f3e4..c15e948e 100644 --- a/tests/entity/object/test_material_run.py +++ b/tests/entity/object/test_material_run.py @@ -4,7 +4,7 @@ from uuid import uuid4 from copy import deepcopy -from gemd.json import loads, dumps +import gemd.json as gemd_json from gemd.entity.attribute import PropertyAndConditions, Property from gemd.entity.object import MaterialRun, ProcessSpec, ProcessRun, MaterialSpec, MeasurementRun from gemd.entity.template import MaterialTemplate @@ -33,7 +33,7 @@ def test_material_run(): ) # Make sure that when property is serialized, origin (an enumeration) is serialized as a string - copy_prop = json_builtin.loads(dumps(mat_spec)) + copy_prop = json_builtin.loads(gemd_json.dumps(mat_spec)) copy_origin = copy_prop["context"][0]["properties"][0]['property']['origin'] assert isinstance(copy_origin, str) @@ -43,8 +43,8 @@ def test_material_run(): mat = MaterialRun("name", spec=mat_spec, sample_type="virtual") # ensure that serialization does not change the MaterialRun - copy = loads(dumps(mat)) - assert dumps(copy) == dumps(mat), \ + copy = gemd_json.loads(gemd_json.dumps(mat)) + assert gemd_json.dumps(copy) == gemd_json.dumps(mat), \ "Material run is modified by serialization or deserialization" @@ -57,8 +57,8 @@ def test_process_run(): assert material_run.process == process_run assert process_run.output_material == material_run - copy_material = loads(dumps(material_run)) - assert dumps(copy_material) == dumps(material_run) + copy_material = gemd_json.loads(gemd_json.dumps(material_run)) + assert gemd_json.dumps(copy_material) == gemd_json.dumps(material_run) assert 'output_material' in repr(process_run) assert 'process' in repr(material_run) @@ -69,8 +69,8 @@ def test_process_id_link(): uid = str(uuid4()) proc_link = LinkByUID(scope='id', id=uid) mat_run = MaterialRun("Another cake", process=proc_link) - copy_material = loads(dumps(mat_run)) - assert dumps(copy_material) == dumps(mat_run) + copy_material = gemd_json.loads(gemd_json.dumps(mat_run)) + assert gemd_json.dumps(copy_material) == gemd_json.dumps(mat_run) def test_process_reassignment(): diff --git a/tests/json/test_json.py b/tests/json/test_json.py index aa335538..69f360bf 100644 --- a/tests/json/test_json.py +++ b/tests/json/test_json.py @@ -5,7 +5,8 @@ import pytest -from gemd.json import dumps, loads, GEMDJson +from gemd.json import GEMDJson +import gemd.json as gemd_json from gemd.entity.attribute.property import Property from gemd.entity.bounds.real_bounds import RealBounds from gemd.entity.case_insensitive_dict import CaseInsensitiveDict @@ -37,13 +38,13 @@ def test_serialize(): parameters=parameter, material=material) # serialize the root of the tree - native_object = json_builtin.loads(dumps(measurement)) + native_object = json_builtin.loads(gemd_json.dumps(measurement)) # ingredients don't get serialized on the process assert(len(native_object["context"]) == 5) assert(native_object["object"]["type"] == LinkByUID.typ) # serialize all the nodes - native_batch = json_builtin.loads(dumps([material, process, measurement, ingredient])) + native_batch = json_builtin.loads(gemd_json.dumps([material, process, measurement, ingredient])) assert(len(native_batch["context"]) == 5) assert(len(native_batch["object"]) == 4) assert(all(x["type"] == LinkByUID.typ for x in native_batch["object"])) @@ -105,7 +106,7 @@ def test_deserialize_extra_fields(): """Extra JSON fields should be ignored in deserialization.""" json_data = '{"context": [],' \ ' "object": {"nominal": 5, "type": "nominal_integer", "extra garbage": "foo"}}' - assert(loads(json_data) == NominalInteger(nominal=5)) + assert(gemd_json.loads(json_data) == NominalInteger(nominal=5)) def test_enumeration_serde(): @@ -127,8 +128,8 @@ def test_attribute_serde(): ) meas_spec = MeasurementSpec("a spec") meas = MeasurementRun("a measurement", spec=meas_spec, properties=[prop]) - assert loads(dumps(prop)) == prop - assert loads(dumps(meas)) == meas + assert gemd_json.loads(gemd_json.dumps(prop)) == prop + assert gemd_json.loads(gemd_json.dumps(meas)) == meas assert isinstance(prop.template, PropertyTemplate) @@ -157,7 +158,7 @@ def test_uid_deser(): """Test that uids continue to be a CaseInsensitiveDict after deserialization.""" material = MaterialRun("Input material", tags="input", uids={'Sample ID': '500-B'}) ingredient = IngredientRun(material=material) - ingredient_copy = loads(dumps(ingredient)) + ingredient_copy = gemd_json.loads(gemd_json.dumps(ingredient)) assert isinstance(ingredient_copy.uids, CaseInsensitiveDict) assert ingredient_copy.material == material assert ingredient_copy.material.uids['sample id'] == material.uids['Sample ID'] @@ -170,7 +171,7 @@ def __init__(self, foo): self.foo = foo with pytest.raises(TypeError): - dumps(ProcessRun("A process", notes=DummyClass("something"))) + gemd_json.dumps(ProcessRun("A process", notes=DummyClass("something"))) def test_unexpected_deserialization(): @@ -178,7 +179,7 @@ def test_unexpected_deserialization(): # DummyClass cannot be serialized since dumps will round-robin serialize # in the substitute_links method with pytest.raises(TypeError): - dumps(ProcessRun("A process", notes={"type": "unknown"})) + gemd_json.dumps(ProcessRun("A process", notes={"type": "unknown"})) def test_register_classes_override(): @@ -283,7 +284,7 @@ def test_case_insensitive_rehydration(): } } ''' - loaded_ingredient = loads(json_str) + loaded_ingredient = gemd_json.loads(json_str) # The ingredient's material will either be a MaterialRun (pass) or a LinkByUID (fail) assert isinstance(loaded_ingredient.material, MaterialRun) @@ -298,7 +299,7 @@ def test_many_ingredients(): IngredientRun(process=proc, material=mat, spec=i_spec) expected.append("i{}".format(i)) - reloaded = loads(dumps(proc)) + reloaded = gemd_json.loads(gemd_json.dumps(proc)) assert len(list(reloaded.ingredients)) == 10 names = [x.name for x in reloaded.ingredients] assert sorted(names) == sorted(expected) @@ -644,10 +645,10 @@ def test_deeply_nested_rehydration(): } } ''' - material_history = loads(json_str) + material_history = gemd_json.loads(json_str) assert isinstance(material_history.process.ingredients[1].spec, IngredientSpec) assert isinstance(material_history.measurements[0], MeasurementRun) - copied = loads(dumps(material_history)) + copied = gemd_json.loads(gemd_json.dumps(material_history)) assert isinstance(copied.process.ingredients[1].spec, IngredientSpec) assert isinstance(copied.measurements[0], MeasurementRun) diff --git a/tests/test_examples.py b/tests/test_examples.py index 1d8d6ab4..9f9c1ee7 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,7 +1,7 @@ """Test of a complicated set of interlocking data objects.""" import json as json_builtin +import gemd.json as gemd_json -from gemd.json import dumps from gemd.entity.attribute.condition import Condition from gemd.entity.attribute.parameter import Parameter from gemd.entity.attribute.property import Property @@ -162,4 +162,4 @@ def test_access_data(): # check that the serialization results in the correct number of objects in the preface # (note that neither measurements nor ingredients are serialized) - assert(len(json_builtin.loads(dumps(island))["context"]) == 26) + assert(len(json_builtin.loads(gemd_json.dumps(island))["context"]) == 26)