diff --git a/bindings/python/dlite-storage.i b/bindings/python/dlite-storage.i index 780767ce8..c7aced65e 100644 --- a/bindings/python/dlite-storage.i +++ b/bindings/python/dlite-storage.i @@ -52,7 +52,7 @@ Returns next instance or None if exhausted.") next; if (dlite_storage_iter_next($self->s, $self->state, uuid) == 0) { DLiteInstance *inst = dlite_instance_load($self->s, uuid); // Why isn't the refcount already increased? - dlite_instance_incref(inst); + if (inst) dlite_instance_incref(inst); return inst; } return NULL; diff --git a/bindings/python/scripts/CMakeLists.txt b/bindings/python/scripts/CMakeLists.txt index d93eb9a3d..5ebdd5afb 100644 --- a/bindings/python/scripts/CMakeLists.txt +++ b/bindings/python/scripts/CMakeLists.txt @@ -32,26 +32,30 @@ install( # Tests test_success( dlite-validate-Person - dlite-validate ../tests/Person.json + dlite-validate ../tests/entities/Person.json ) test_success( dlite-validate-persons - dlite-validate -p ../tests/Person.json -i a1d8d35f-723c-5ea1-abaf-8fc8f1d0982f - ../tests/persons.json + dlite-validate + -p ../tests/entities/Person.json + -i a1d8d35f-723c-5ea1-abaf-8fc8f1d0982f + ../tests/input/persons.json ) test_success( dlite-validate-persons2 dlite-validate - --storage-path=../tests + --storage-path=../tests/entities --id=Ada --show - ../tests/persons.json + ../tests/input/persons.json ) # No --id for storage with multiple instances test_failure( dlite-validate-persons-fail2 - dlite-validate --storage-path ../tests/Person.json --show ../tests/persons.json + dlite-validate + --storage-path ../tests/entities/Person.json + --show ../tests/input/persons.json ) # The "dimensions" keyword is required diff --git a/bindings/python/tests/.gitignore b/bindings/python/tests/.gitignore index 41706a5db..7d0735cd2 100644 --- a/bindings/python/tests/.gitignore +++ b/bindings/python/tests/.gitignore @@ -1,16 +1,2 @@ .gdb_history __pycache__ - -inst.ttl -inst.yaml -test.json -test.yaml - -xxx.json -xxx2.json -yyy.json - -myentity.json -persons2.json - -db.xml diff --git a/bindings/python/tests/CMakeLists.txt b/bindings/python/tests/CMakeLists.txt index 2e1da655c..b6280f2ee 100644 --- a/bindings/python/tests/CMakeLists.txt +++ b/bindings/python/tests/CMakeLists.txt @@ -23,6 +23,7 @@ set(tests test_postgresql2_read test_ref_type test_pydantic + test_iri ) foreach(test ${tests}) diff --git a/bindings/python/tests/Person.json b/bindings/python/tests/Person.json deleted file mode 100644 index 97c608791..000000000 --- a/bindings/python/tests/Person.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "uri": "http://onto-ns.com/meta/0.1/Person", - "description": "A person.", - "dimensions": { - "N": "Number of skills." - }, - "properties": { - "name": { - "type": "string", - "description": "Full name." - }, - "age": { - "type": "float", - "unit": "years", - "description": "Age of person." - }, - "skills": { - "type": "string", - "shape": ["N"], - "description": "List of skills." - } - } -} diff --git a/bindings/python/tests/entities/Invalid1.json b/bindings/python/tests/entities/Invalid1.json index 8401f9f18..d7693cff0 100644 --- a/bindings/python/tests/entities/Invalid1.json +++ b/bindings/python/tests/entities/Invalid1.json @@ -1,7 +1,19 @@ { - "name": "Missing version", - "namespace": "http://onto-ns.com/meta", - "meta": "http://onto-ns.com/meta/0.3/EntitySchema", - "dimensions": {} - "properties": {} + "uri": "http://onto-ns.com/meta/0.1/Invalid1", + "description": "An datamodel for an item with float type and invalid shape name.", + "dimensions": { + "nf": "Number of eigen-frequencies." + }, + "properties": { + "name": { + "type": "str", + "description": "Name of the item." + }, + "f": { + "type": "float64", + "shape": ["nf_MISPELLED"], + "unit": "Hz", + "description": "The magic eigen-frequencies of the item." + } + } } diff --git a/bindings/python/tests/entities/Invalid2.json b/bindings/python/tests/entities/Invalid2.json index 4792bc587..e0a51fdf3 100644 --- a/bindings/python/tests/entities/Invalid2.json +++ b/bindings/python/tests/entities/Invalid2.json @@ -1,7 +1,15 @@ { - "name": "Missing namespace", - "version": "0.0.1", - "meta": "http://onto-ns.com/meta/0.3/EntitySchema", - "dimensions": {} - "properties": {} + "uri": "http://onto-ns.com/meta/0.1/Invalid2", + "description": "A datamodel with ref-types with invalid shape name...", + "dimensions": { + "nrefs": "Number of references to Ref datamodels." + }, + "properties": { + "items": { + "type": "ref", + "$ref": "http://onto-ns.com/meta/0.1/Item", + "shape": ["INVALID_nrefs"], + "description": "List of Item datamodels." + } + } } diff --git a/bindings/python/tests/entities/Invalid3.json b/bindings/python/tests/entities/Invalid3.json index 4f91de558..cb1ed38bb 100644 --- a/bindings/python/tests/entities/Invalid3.json +++ b/bindings/python/tests/entities/Invalid3.json @@ -1,5 +1,19 @@ { - "url": "http://onto-ns.com/meta/0.1/Invalid3", - "description": "Missing properties", - "dimensions": {} + "uri": "http://onto-ns.com/meta/0.1/Invalid3", + "description": "Invalid JSON (square bracket for dimensions instead of braces).", + "dimensions": [ + "nfrequencies": "Number of eigen-frequencies." + ], + "properties": { + "name": { + "type": "str", + "description": "Name of the item." + }, + "f": { + "type": "float64", + "shape": ["nf"], + "unit": "Hz", + "description": "The magic eigen-frequencies of the item." + } + } } diff --git a/bindings/python/tests/entities/Invalid5.json b/bindings/python/tests/entities/Invalid5.json new file mode 100644 index 000000000..8401f9f18 --- /dev/null +++ b/bindings/python/tests/entities/Invalid5.json @@ -0,0 +1,7 @@ +{ + "name": "Missing version", + "namespace": "http://onto-ns.com/meta", + "meta": "http://onto-ns.com/meta/0.3/EntitySchema", + "dimensions": {} + "properties": {} +} diff --git a/bindings/python/tests/entities/Invalid6.json b/bindings/python/tests/entities/Invalid6.json new file mode 100644 index 000000000..4792bc587 --- /dev/null +++ b/bindings/python/tests/entities/Invalid6.json @@ -0,0 +1,7 @@ +{ + "name": "Missing namespace", + "version": "0.0.1", + "meta": "http://onto-ns.com/meta/0.3/EntitySchema", + "dimensions": {} + "properties": {} +} diff --git a/bindings/python/tests/entities/Invalid7.json b/bindings/python/tests/entities/Invalid7.json new file mode 100644 index 000000000..a1d112bc7 --- /dev/null +++ b/bindings/python/tests/entities/Invalid7.json @@ -0,0 +1,5 @@ +{ + "url": "http://onto-ns.com/meta/0.1/Invalid7", + "description": "Missing properties", + "dimensions": {} +} diff --git a/bindings/python/tests/input/Item.json b/bindings/python/tests/entities/Item.json similarity index 100% rename from bindings/python/tests/input/Item.json rename to bindings/python/tests/entities/Item.json diff --git a/bindings/python/tests/MyEntity.json b/bindings/python/tests/entities/MyEntity.json similarity index 100% rename from bindings/python/tests/MyEntity.json rename to bindings/python/tests/entities/MyEntity.json diff --git a/bindings/python/tests/entities/Person.json b/bindings/python/tests/entities/Person.json index 7e0dab81f..97c608791 100644 --- a/bindings/python/tests/entities/Person.json +++ b/bindings/python/tests/entities/Person.json @@ -1,34 +1,23 @@ { - "name": "Person", - "version": "0.1", - "namespace": "http://onto-ns.com/meta", - "meta": "http://onto-ns.com/meta/0.3/EntitySchema", + "uri": "http://onto-ns.com/meta/0.1/Person", "description": "A person.", - "dimensions": [ - { - "name": "N", - "description": "Number of skills." - } - ], - "properties": [ - { - "name": "name", + "dimensions": { + "N": "Number of skills." + }, + "properties": { + "name": { "type": "string", "description": "Full name." }, - { - "name": "age", + "age": { "type": "float", "unit": "years", "description": "Age of person." }, - { - "name": "skills", + "skills": { "type": "string", - "dims": [ - "N" - ], + "shape": ["N"], "description": "List of skills." } - ] + } } diff --git a/bindings/python/tests/input/Ref.json b/bindings/python/tests/entities/Ref.json similarity index 100% rename from bindings/python/tests/input/Ref.json rename to bindings/python/tests/entities/Ref.json diff --git a/bindings/python/tests/SimplePerson.json b/bindings/python/tests/entities/SimplePerson.json similarity index 100% rename from bindings/python/tests/SimplePerson.json rename to bindings/python/tests/entities/SimplePerson.json diff --git a/bindings/python/tests/global_dlite_state_mod2.py b/bindings/python/tests/global_dlite_state_mod2.py index 1476774cb..de8a8d826 100644 --- a/bindings/python/tests/global_dlite_state_mod2.py +++ b/bindings/python/tests/global_dlite_state_mod2.py @@ -1,15 +1,16 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import os +from pathlib import Path import dlite from dlite import Instance, Dimension, Property, Relation assert len(dlite.istore_get_uuids()) == 3 + 3 -thisdir = os.path.abspath(os.path.dirname(__file__)) -url = "json://" + thisdir + "/MyEntity.json" +thisdir = Path(__file__).absolute().parent +entitydir = thisdir / "entities" + +url = f"json://{entitydir}/MyEntity.json" # myentity is already defined via test_global_dlite_state, no new instance is added to istore myentity = Instance.from_url(url) diff --git a/bindings/python/tests/input/Invalid1.json b/bindings/python/tests/input/Invalid1.json deleted file mode 100644 index d7693cff0..000000000 --- a/bindings/python/tests/input/Invalid1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "uri": "http://onto-ns.com/meta/0.1/Invalid1", - "description": "An datamodel for an item with float type and invalid shape name.", - "dimensions": { - "nf": "Number of eigen-frequencies." - }, - "properties": { - "name": { - "type": "str", - "description": "Name of the item." - }, - "f": { - "type": "float64", - "shape": ["nf_MISPELLED"], - "unit": "Hz", - "description": "The magic eigen-frequencies of the item." - } - } -} diff --git a/bindings/python/tests/input/Invalid2.json b/bindings/python/tests/input/Invalid2.json deleted file mode 100644 index e0a51fdf3..000000000 --- a/bindings/python/tests/input/Invalid2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "uri": "http://onto-ns.com/meta/0.1/Invalid2", - "description": "A datamodel with ref-types with invalid shape name...", - "dimensions": { - "nrefs": "Number of references to Ref datamodels." - }, - "properties": { - "items": { - "type": "ref", - "$ref": "http://onto-ns.com/meta/0.1/Item", - "shape": ["INVALID_nrefs"], - "description": "List of Item datamodels." - } - } -} diff --git a/bindings/python/tests/input/Invalid3.json b/bindings/python/tests/input/Invalid3.json deleted file mode 100644 index cb1ed38bb..000000000 --- a/bindings/python/tests/input/Invalid3.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "uri": "http://onto-ns.com/meta/0.1/Invalid3", - "description": "Invalid JSON (square bracket for dimensions instead of braces).", - "dimensions": [ - "nfrequencies": "Number of eigen-frequencies." - ], - "properties": { - "name": { - "type": "str", - "description": "Name of the item." - }, - "f": { - "type": "float64", - "shape": ["nf"], - "unit": "Hz", - "description": "The magic eigen-frequencies of the item." - } - } -} diff --git a/bindings/python/tests/persons.json b/bindings/python/tests/input/persons.json similarity index 100% rename from bindings/python/tests/persons.json rename to bindings/python/tests/input/persons.json diff --git a/bindings/python/tests/rdf.ttl b/bindings/python/tests/input/rdf.ttl similarity index 100% rename from bindings/python/tests/rdf.ttl rename to bindings/python/tests/input/rdf.ttl diff --git a/bindings/python/tests/test_ref_type.json b/bindings/python/tests/input/test_ref_type.json similarity index 100% rename from bindings/python/tests/test_ref_type.json rename to bindings/python/tests/input/test_ref_type.json diff --git a/bindings/python/tests/inst.json b/bindings/python/tests/inst.json deleted file mode 100644 index 1aaefb7e3..000000000 --- a/bindings/python/tests/inst.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "ce592ff9-a7dc-548a-bbe5-3c53800afaf3": { - "uri": "my-data", - "meta": "http://onto-ns.com/meta/0.1/MyEntity", - "dimensions": { - "N": 2, - "M": 3 - }, - "properties": { - "a-blob": "000102030405060708090a0b0c0d0e0f", - "a-blob-array": [["00aa00ff", "00bb00dd"], ["001100aa", "0000cc00"]], - "a-bool": false, - "a-bool-array": [true, false], - "an-int": 42, - "an-int-array": [0, 1, -1], - "a-float": 0, - "a-float64-array": [0, 3.14, -1e-6], - "a-fixstring": "", - "a-fixstring-array": [["abc", "def"], ["ghi", "jkl"]], - "a-string": "en af dem der red med fane", - "a-string-array": [[null, "a", "b"], ["abc", "a longer string", "and one that is not shorter..."]], - "a-relation": ["Cat", "isA", "Mammal"], - "a-relation-array": [["Shark", "isA", "Fish"], ["Fish", "isA", "Animal"]] - } - } -} diff --git a/bindings/python/tests/output/.gitignore b/bindings/python/tests/output/.gitignore index 5c0c65f19..5b880214c 100644 --- a/bindings/python/tests/output/.gitignore +++ b/bindings/python/tests/output/.gitignore @@ -1,2 +1,4 @@ *.json *.yaml +*.ttl +db.xml diff --git a/bindings/python/tests/test_collection.py b/bindings/python/tests/test_collection.py index 54a2286c7..72a5b7247 100755 --- a/bindings/python/tests/test_collection.py +++ b/bindings/python/tests/test_collection.py @@ -6,6 +6,8 @@ thisdir = Path(__file__).resolve().parent outdir = thisdir / "output" +indir = thisdir / "input" +entitydir = thisdir / "entities" # Create collection @@ -23,7 +25,7 @@ assert rel is None # Create instances -url = f"json://{thisdir}/MyEntity.json?mode=r" +url = f"json://{entitydir}/MyEntity.json?mode=r" e = dlite.Instance.from_url(url) inst1 = dlite.Instance.from_metaid(e.uri, [3, 2]) inst2 = dlite.Instance.from_metaid(e.uri, (3, 4), "myinst") diff --git a/bindings/python/tests/test_entity.py b/bindings/python/tests/test_entity.py index 76c255dc9..87aa4ad03 100755 --- a/bindings/python/tests/test_entity.py +++ b/bindings/python/tests/test_entity.py @@ -11,16 +11,15 @@ thisdir = Path(__file__).absolute().parent +outdir = thisdir / "output" indir = thisdir / "input" entitydir = thisdir / "entities" dlite.storage_path.append(indir / "*.json") dlite.storage_path.append(entitydir / "*.json") -url = f"json://{thisdir}/MyEntity.json" - # Load metadata (i.e. an instance of meta-metadata) from url -myentity = Instance.from_url(url) +myentity = Instance.from_url(f"json://{entitydir}/MyEntity.json") print(myentity.uuid) # Check some properties of the entity @@ -32,15 +31,11 @@ assert not myentity.is_metameta # Store the entity to a new file -myentity.save("json://xxx.json?mode=w") +myentity.save(f"json://{outdir}/test_entity.json?mode=w") # Try to overwrite without mode - should fail because metadata is immutable -try: - myentity.save("json://xxx.json") -except dlite.DLiteError: - dlite.errclr() -else: - assert False, "overwriting single-entity formatted file" +with raises(dlite.DLiteStorageSaveError): + myentity.save(f"json://{outdir}/test_entity.json") # Create an instance of `myentity` with dimensions 2, 3 # For convinience, we give it an unique label "myid" that can be used @@ -86,61 +81,51 @@ # print(inst) # Check save and load -inst.save("json://inst.json?mode=w") -inst2 = Instance.from_url("json://inst.json") +inst.save(f"json://{outdir}/test_entity_inst.json?mode=w") +inst2 = Instance.from_url(f"json://{outdir}/test_entity_inst.json") blob = inst2["a-blob"] del inst2 inst2 = Instance.from_url( - "json://inst.json?mode=r#46a67765-3d8b-5764-9583-3aec59a17983" + f"json://{outdir}/test_entity_inst.json?" + "mode=r#46a67765-3d8b-5764-9583-3aec59a17983" ) assert inst2["a-blob"] == blob del inst2 -inst2 = Instance.from_location("json", "inst.json") +inst2 = Instance.from_location("json", outdir / "test_entity_inst.json") assert inst2["a-blob"] == blob del inst2 inst2 = Instance.from_location( - "json", "inst.json", id="46a67765-3d8b-5764-9583-3aec59a17983" + "json", outdir / "test_entity_inst.json", + id="46a67765-3d8b-5764-9583-3aec59a17983" ) assert inst2["a-blob"] == blob del inst2 -with dlite.Storage("json", "inst.json") as s: +with dlite.Storage("json", outdir / "test_entity_inst.json") as s: inst2 = dlite.Instance.from_storage(s) assert inst2["a-blob"] == blob del inst2 -with dlite.Storage("json", "inst.json") as s: +with dlite.Storage("json", outdir / "test_entity_inst.json") as s: inst2 = s.load(id="46a67765-3d8b-5764-9583-3aec59a17983") assert inst2["a-blob"] == blob del inst2 # Make sure we fail with an exception for pathetic cases -try: +with raises(dlite.DLiteStorageOpenError): Instance.from_location("json", "/", "mode=r") -except dlite.DLiteError: - print('*** catched error loading "/" in read mode') - dlite.errclr() -try: +with raises(dlite.DLiteStorageLoadError): Instance.from_location("json", "/", "mode=w") -except dlite.DLiteError: - print('*** catched error loading "/" in write mode') - dlite.errclr() -try: +with raises(dlite.DLiteStorageLoadError): Instance.from_location("json", "") -except dlite.DLiteError: - print('*** catched error loading ""') - dlite.errclr() -try: +with raises(dlite.DLiteStorageLoadError): Instance.from_location("json", "non-existing-path...") -except dlite.DLiteError: - print('*** catched error loading "non-existing-path..."') - dlite.errclr() # Test for issue #352 - improved error message for missing dimensions @@ -154,17 +139,8 @@ } } """ -try: - entity = dlite.Instance.from_json(json_repr) -except dlite.DLiteError as exc: - assert str(exc) == ( - "DLiteOtherError: metadata does not confirm to schema, please check " - "dimensions, properties and/or relations: " - "http://onto-ns.com/ex/0.1/test" - ) - dlite.errclr() -else: - assert False # missing dimensions should raise an exception +with raises(dlite.DLiteParseError): + dlite.Instance.from_json(json_repr) # Test copy @@ -252,14 +228,14 @@ # Test save -inst.save("json://yyy.json?mode=w") +inst.save(f"json://{outdir}/test_entity2.json?mode=w") try: import yaml except ImportError: pass else: - inst.save("yaml://yyy.yaml?mode=w") + inst.save(f"yaml://{outdir}/test_entity.yaml?mode=w") # Test metadata @@ -304,10 +280,12 @@ # Metadata schema schema = dlite.get_instance(dlite.ENTITY_SCHEMA) -schema.save("entity_schema.json?mode=w;arrays=false") -schema.meta.save("basic_metadata_schema.json?mode=w;arrays=false") +schema.save(f"json://{outdir}/entity_schema.json?mode=w;arrays=false") +schema.meta.save( + f"json://{outdir}/basic_metadata_schema.json?mode=w;arrays=false" +) -mm = dlite.Instance.from_url("json://entity_schema.json") +mm = dlite.Instance.from_url(f"json://{outdir}/entity_schema.json") assert mm.uri == dlite.ENTITY_SCHEMA @@ -317,7 +295,6 @@ with raises(dlite.DLiteMissingInstanceError, dlite.DLiteSyntaxError): invalid1 = Invalid1([2], properties={"name": "a", "f": [3.14, 2.72]}) - # For issue #686 Invalid2 = dlite.get_instance("http://onto-ns.com/meta/0.1/Invalid2") with raises(dlite.DLiteMissingInstanceError, dlite.DLiteSyntaxError): @@ -325,8 +302,20 @@ # For issue #691 -with raises(dlite.DLiteStorageOpenError): - Invalid3 = dlite.Instance.from_location("json", indir / "Invalid3.json") +with raises(dlite.DLiteStorageOpenError, dlite.DLiteUnknownError): + dlite.Instance.from_location("json", entitydir / "Invalid3.json") + +with raises(dlite.DLiteStorageOpenError, dlite.DLiteUnknownError): + dlite.Instance.from_location("json", entitydir / "Invalid4.json") + +with raises(dlite.DLiteStorageOpenError, dlite.DLiteUnknownError): + dlite.Instance.from_location("json", entitydir / "Invalid5.json") + +with raises(dlite.DLiteStorageOpenError, dlite.DLiteUnknownError): + dlite.Instance.from_location("json", entitydir / "Invalid6.json") + +with raises(dlite.DLiteStorageOpenError, dlite.DLiteUnknownError): + dlite.Instance.from_location("json", entitydir / "Invalid7.json") # For issue #702 diff --git a/bindings/python/tests/test_factory.py b/bindings/python/tests/test_factory.py index 541b59ccf..5a32d7434 100755 --- a/bindings/python/tests/test_factory.py +++ b/bindings/python/tests/test_factory.py @@ -7,7 +7,9 @@ thisdir = Path(__file__).resolve().parent rootdir = thisdir.parent.parent.parent +indir = thisdir / "input" outdir = thisdir / "output" +entitydir = thisdir / "entities" class Person: @@ -20,17 +22,15 @@ def __repr__(self): return "Person(%r, %r, %r)" % (self.name, self.age, list(self.skills)) -url = f"json://{thisdir}/Person.json" - print("-- create: ExPerson") -ExPerson = dlite.classfactory(Person, url=url) +ExPerson = dlite.classfactory(Person, url=f"json://{entitydir}/Person.json") print("-- create: person1") person1 = Person("Jack Daniel", 42, ["distilling", "tasting"]) print("-- create: person2") person2 = ExPerson("Jack Daniel", 42, ["distilling", "tasting"]) -person2.dlite_inst.save("json", f"{outdir}/persons.json", "mode=w") +person2.dlite_inst.save("json", outdir / "persons.json", "mode=w") # Print json-representation of person2 using dlite print(person2.dlite_inst.asjson(indent=2)) diff --git a/bindings/python/tests/test_global_dlite_state.py b/bindings/python/tests/test_global_dlite_state.py index 849fcc351..bae1b2ac5 100644 --- a/bindings/python/tests/test_global_dlite_state.py +++ b/bindings/python/tests/test_global_dlite_state.py @@ -1,11 +1,16 @@ -import os +from pathlib import Path import importlib import dlite from dlite import Instance from global_dlite_state_mod1 import assert_exists_in_module -thisdir = os.path.abspath(os.path.dirname(__file__)) + +thisdir = Path(__file__).absolute().parent +outdir = thisdir / "output" +indir = thisdir / "input" +entitydir = thisdir / "entities" +#dlite.storage_path.append(entitydir / "*.json") assert len(dlite.istore_get_uuids()) == 3 # 3 Hardcoded dlite instances @@ -17,7 +22,7 @@ # Must exist in imported dlite in different module (mod1) assert_exists_in_module(coll.uuid) -url = "json://" + thisdir + "/MyEntity.json" + "?mode=r" +url = f"json://{entitydir}/MyEntity.json" + "?mode=r" e = Instance.from_url(url) # (2) assert len(dlite.istore_get_uuids()) == 3 + 2 @@ -32,7 +37,7 @@ # Use compile and exec with dlite defined in globals env = globals().copy() -filename = os.path.join(thisdir, "global_dlite_state_mod2.py") +filename = thisdir / "global_dlite_state_mod2.py" with open(filename) as fd: exec(compile(fd.read(), filename, "exec"), env) diff --git a/bindings/python/tests/test_iri.py b/bindings/python/tests/test_iri.py index 0ce438a09..869faed68 100644 --- a/bindings/python/tests/test_iri.py +++ b/bindings/python/tests/test_iri.py @@ -1,14 +1,14 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import os +from pathlib import Path import dlite -thisdir = os.path.abspath(os.path.dirname(__file__)) -url = "json://" + thisdir + "/MyEntity.json" + "?mode=r" +thisdir = Path(__file__).parent.absolute() +entitydir = thisdir / "entities" +dlite.storage_path.append(f"{entitydir}/*.json") -E = dlite.Instance.from_url(url) +E = dlite.Instance.from_url(url=f"json://{entitydir}/MyEntity.json?mode=r") E.iri = "http://emmo.info/emmo/EMMO_Physical" E.iri = None E.iri = "http://emmo.info/emmo/EMMO_Physical" diff --git a/bindings/python/tests/test_mapping.py b/bindings/python/tests/test_mapping.py index f58e61886..168f0b555 100755 --- a/bindings/python/tests/test_mapping.py +++ b/bindings/python/tests/test_mapping.py @@ -6,11 +6,12 @@ # Configure search paths thisdir = Path(__file__).parent.absolute() -dlite.storage_path.append(f"{thisdir}/*.json") +entitydir = thisdir / "entities" +dlite.storage_path.append(f"{entitydir}/*.json") dlite.python_mapping_plugin_path.append(f"{thisdir}/python-mapping-plugins") # Create an instance of Person -Person = dlite.Instance.from_url(f"json:{thisdir}/Person.json?mode=r") +Person = dlite.Instance.from_url(f"json:{entitydir}/Person.json?mode=r") person = Person(dimensions=[2]) person.name = "Neil Armstrong" person.age = 39 diff --git a/bindings/python/tests/test_postgresql1_write.py b/bindings/python/tests/test_postgresql1_write.py index 88825ed20..62e9398cd 100644 --- a/bindings/python/tests/test_postgresql1_write.py +++ b/bindings/python/tests/test_postgresql1_write.py @@ -9,6 +9,9 @@ # Paths thisdir = Path(__file__).resolve().parent +indir = thisdir / "input" +outdir = thisdir / "output" +entitydir = thisdir / "entities" def parse_pgconf(): @@ -54,14 +57,14 @@ def ping_server(server="localhost", port=5432, timeout=3): ping_server() # Add metadata to search path -dlite.storage_path.append(f"{thisdir}/Person.json") -dlite.storage_path.append(f"{thisdir}/SimplePerson.json") +dlite.storage_path.append(f"{entitydir}/Person.json") +dlite.storage_path.append(f"{entitydir}/SimplePerson.json") # Load dataset host, user, database, password = parse_pgconf() inst = dlite.Instance.from_location( "json", - f"{thisdir}/persons.json", + f"{indir}/persons.json", id="Cleopatra", ) diff --git a/bindings/python/tests/test_python_storage.py b/bindings/python/tests/test_python_storage.py index e0802daa1..903ac6fe9 100755 --- a/bindings/python/tests/test_python_storage.py +++ b/bindings/python/tests/test_python_storage.py @@ -29,6 +29,8 @@ # thisdir = os.path.abspath(os.path.dirname(__file__)) thisdir = Path(__file__).resolve().parent +outdir = thisdir / "output" +entitydir = thisdir / "entities" def equal_rdf_files(path1, path2): @@ -46,21 +48,18 @@ def equal_rdf_files(path1, path2): # Test JSON - -url = "json://" + os.path.join(thisdir, "Person.json") -Person = dlite.Instance.from_url(url) - +Person = dlite.Instance.from_url(f"json://{entitydir}/Person.json") person = Person(dims=[2]) person.name = "Ada" person.age = 12.5 person.skills = ["skiing", "jumping"] print("=== saving...") -with dlite.Storage("json", "test.json", "mode=w") as s: +with dlite.Storage("json", outdir / "test_python_storage.json", "mode=w") as s: s.save(person) print("=== loading...", person.uuid) -with dlite.Storage("json", "test.json", "mode=r") as s: +with dlite.Storage("json", outdir / "test_python_storage.json", "mode=r") as s: inst = s.load(id=person.uuid) @@ -68,11 +67,11 @@ def equal_rdf_files(path1, path2): person2.name = "Berry" person2.age = 24.3 person2.skills = ["eating", "sleeping", "reading"] -with dlite.Storage("json://test.json") as s: +with dlite.Storage(f"json://{outdir}/test_python_storage.json") as s: s.save(person2) -s = dlite.Storage("json://test.json") +s = dlite.Storage(f"json://{outdir}/test_python_storage.json") uuids = s.get_uuids() del s del uuids diff --git a/bindings/python/tests/test_rdf.py b/bindings/python/tests/test_rdf.py index ab35e88f5..485ab633c 100644 --- a/bindings/python/tests/test_rdf.py +++ b/bindings/python/tests/test_rdf.py @@ -12,9 +12,10 @@ thisdir = Path(__file__).resolve().parent +indir = thisdir / "input" id = "http://onto-ns.com/data#my_test_instance" -inst = from_rdf(thisdir / "rdf.ttl", id=id) +inst = from_rdf(indir / "rdf.ttl", id=id) # Serialise `inst` to string `s` s = to_rdf( @@ -25,6 +26,6 @@ ) # Check that content matches original serialisation -with open(thisdir / "rdf.ttl", "r") as f: +with open(indir / "rdf.ttl", "r") as f: orig = f.read() assert s == orig diff --git a/bindings/python/tests/test_ref_type.py b/bindings/python/tests/test_ref_type.py index d970c2f3e..5d7e62c5b 100644 --- a/bindings/python/tests/test_ref_type.py +++ b/bindings/python/tests/test_ref_type.py @@ -4,8 +4,9 @@ thisdir = Path(__file__).resolve().parent +indir = thisdir / "input" -dlite.storage_path.append(thisdir / "test_ref_type.json") +dlite.storage_path.append(indir / "test_ref_type.json") Top = dlite.get_instance("http://onto-ns.com/meta/0.1/Top") Middle = dlite.get_instance("http://onto-ns.com/meta/0.1/Middle") diff --git a/bindings/python/tests/test_storage.py b/bindings/python/tests/test_storage.py index 7c7be74ba..4b93c394b 100755 --- a/bindings/python/tests/test_storage.py +++ b/bindings/python/tests/test_storage.py @@ -1,6 +1,5 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -import os +from pathlib import Path import dlite from dlite.testutils import raises @@ -12,10 +11,13 @@ HAVE_YAML = False -thisdir = os.path.abspath(os.path.dirname(__file__)) -outdir = f"{thisdir}/output" +thisdir = Path(__file__).absolute().parent +outdir = thisdir / "output" +indir = thisdir / "input" +entitydir = thisdir / "entities" +dlite.storage_path.append(entitydir / "*.json") -url = "json://" + thisdir + "/MyEntity.json" +url = f"json://{entitydir}/MyEntity.json" # Load metadata (i.e. an instance of meta-metadata) from url @@ -36,7 +38,7 @@ inst["a-bool-array"] = True, False # Test Storage.save() -with dlite.Storage("json", f"{outdir}/tmp.json", "mode=w") as s: +with dlite.Storage("json", outdir / "test_storage_tmp.json", "mode=w") as s: s.save(inst) # Test query @@ -44,18 +46,18 @@ # Test json print("--- testing json") -myentity.save(f"json://{outdir}/myentity.json?mode=w") -inst.save(f"json://{outdir}/inst.json?mode=w") +myentity.save(f"json://{outdir}/test_storage_myentity.json?mode=w") +inst.save(f"json://{outdir}/test_storage_inst.json?mode=w") del inst -inst = dlite.Instance.from_url(f"json://{outdir}/inst.json#my-data") +inst = dlite.Instance.from_url(f"json://{outdir}/test_storage_inst.json#my-data") # Test yaml if HAVE_YAML: print('--- testing yaml') - inst.save(f"yaml://{outdir}/inst.yaml?mode=w") + inst.save(f"yaml://{outdir}/test_storage_inst.yaml?mode=w") del inst - inst = dlite.Instance.from_url(f"yaml://{outdir}/inst.yaml#my-data") + inst = dlite.Instance.from_url(f"yaml://{outdir}/test_storage_inst.yaml#my-data") # test help() expected = """\ @@ -74,7 +76,9 @@ - `single`: Whether the input is assumed to be in single-entity form. If "auto" (default) the form will be inferred automatically. """ - s = dlite.Storage("yaml", f"{outdir}/inst.yaml", options="mode=a") + s = dlite.Storage( + "yaml", outdir / "test_storage_inst.yaml", options="mode=a" + ) assert s.help().strip() == expected.strip() # Test delete() @@ -95,13 +99,27 @@ # Test rdf try: print("--- testing rdf") - inst.save("rdf:db.xml?mode=w;store=file;filename=inst.ttl;format=turtle") -except dlite.DLiteError: + inst.save( + f"rdf:{outdir}/db.xml?mode=w;" + "store=file;" + f"filename={outdir}/test_storage_inst.ttl;" + "format=turtle" + ) +except (dlite.DLiteUnsupportedError, dlite.DLiteStorageOpenError): print(" skipping rdf test") else: # del inst # FIXME: read from inst.ttl not db.xml - inst3 = dlite.Instance.from_url("rdf://db.xml#my-data") + inst3 = dlite.Instance.from_url("rdf://{outdir}/db.xml#my-data") + + with raises(dlite.DLiteIOError): + inst.save( + f"rdf://{outdir}/db.xml?mode=w;" + "store=file;" + f"filename={outdir}/non-existing/test_storage_inst.ttl;" + "format=turtle" + ) + # Tests for issue #587 @@ -113,8 +131,7 @@ inst.to_bytes("json") -dlite.storage_path.append(thisdir) -s = dlite.Storage("json", f"{thisdir}/persons.json", "mode=r") +s = dlite.Storage("json", f"{indir}/persons.json", "mode=r") #assert len(list(s.instances())) == 5 diff --git a/bindings/python/tests/test_utils.py b/bindings/python/tests/test_utils.py index cd2c3351a..d346bf5d8 100644 --- a/bindings/python/tests/test_utils.py +++ b/bindings/python/tests/test_utils.py @@ -14,9 +14,10 @@ thisdir = Path(__file__).absolute().parent -dlite.storage_path.append(thisdir / "input" / "*.json") +entitydir = thisdir / "entities" +dlite.storage_path.append(entitydir / "*.json") -with open(thisdir / "Person.json", "rt") as f: +with open(entitydir / "Person.json", "rt") as f: d = json.load(f) Person = dlite.utils.instance_from_dict(d) @@ -67,9 +68,7 @@ print(inst) -url = "json://" + os.path.join(thisdir, "Person.json") -Person = dlite.Instance.from_url(url) - +Person = dlite.Instance.from_url(f"json://{entitydir}/Person.json") person = Person([2]) person.name = "Ada" person.age = 12.5 diff --git a/bindings/python/testutils.py b/bindings/python/testutils.py index b60da1309..0e09156a9 100644 --- a/bindings/python/testutils.py +++ b/bindings/python/testutils.py @@ -49,6 +49,7 @@ def __exit__(self, exc_type, exc_value, tb): # was raised for exc in self.exceptions: if issubclass(exc_type, exc): + dlite.errclr() return True raise UnexpectedExceptionError( diff --git a/src/dlite-json.c b/src/dlite-json.c index 18e593671..2761408c8 100644 --- a/src/dlite-json.c +++ b/src/dlite-json.c @@ -612,8 +612,9 @@ static DLiteInstance *parse_instance(const char *src, jsmntok_t *obj, if ((t = jsmn_item(src, obj, "properties"))) dims[n++] = t->size; if ((t = jsmn_item(src, obj, "relations"))) dims[n++] = t->size; if (n != meta->_ndimensions) - FAIL1("metadata does not confirm to schema, please check dimensions, " - "properties and/or relations: %s", id); + FAILCODE1(dliteParseError, "metadata does not confirm to schema, " + "please check dimensions, properties and/or relations: %s", + id); } else { if (meta->_ndimensions > 0) { diff --git a/src/dlite-misc.c b/src/dlite-misc.c index 919e022f1..77ab8c078 100644 --- a/src/dlite-misc.c +++ b/src/dlite-misc.c @@ -693,6 +693,7 @@ int dlite_err_ignored_get(DLiteErrCode code) { DLiteErrMask *mask = _dlite_err_mask_get(); if (!mask) return 0; + if (code > 0 && (*mask & DLITE_ERRBIT(dliteUnknownError))) return 1; return *mask & DLITE_ERRBIT(code); } diff --git a/storages/rdf/dlite-rdf.c b/storages/rdf/dlite-rdf.c index 37572c4e4..85aa793af 100644 --- a/storages/rdf/dlite-rdf.c +++ b/storages/rdf/dlite-rdf.c @@ -232,6 +232,7 @@ DLiteStorage *rdf_open(const DLiteStoragePlugin *api, const char *uri, int rdf_close(DLiteStorage *storage) { RdfStorage *s = (RdfStorage *)storage; + int retval = 0; if (s->flags & dliteWritable) { librdf_world *world = triplestore_get_world(s->ts); @@ -247,6 +248,7 @@ int rdf_close(DLiteStorage *storage) if (s->filename) { unsigned char *buf; librdf_uri *base_uri=NULL, *type_uri=NULL; + FILE *fp; if (s->base_uri) base_uri = librdf_new_uri(world, (unsigned char *)s->base_uri); if (s->type_uri) @@ -257,10 +259,11 @@ int rdf_close(DLiteStorage *storage) if (strcmp(s->filename, "-") == 0) { fprintf(stdout, "%s", buf); - } else { - FILE *fp = fopen(s->filename, "w"); + } else if ((fp = fopen(s->filename, "w"))) { fprintf(fp, "%s", buf); fclose(fp); + } else { + retval = err(dliteIOError, "cannot write rdf file: %s", s->filename); } if (base_uri) librdf_free_uri(base_uri); @@ -276,7 +279,7 @@ int rdf_close(DLiteStorage *storage) if (s->format) free(s->format); if (s->mime_type) free(s->mime_type); if (s->type_uri) free(s->type_uri); - return 0; + return retval; }