Skip to content

Commit 1070058

Browse files
authored
Merge pull request #1 from Peyman-N/pipeline
Pipeline
2 parents 08ca7ca + d25af55 commit 1070058

File tree

10 files changed

+143
-107
lines changed

10 files changed

+143
-107
lines changed

build.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
include_instances = True # to speed up the build during development, set this to False
1717

1818
parser = argparse.ArgumentParser(prog=sys.argv[0], description="Generate Python package for openMINDS")
19-
parser.add_argument('--branch', help="The branch to build from ('main' or 'development')", default="main")
19+
parser.add_argument("--branch", help="The branch to build from ('main' or 'development')", default="main")
2020
args = parser.parse_args()
2121

2222
print("*******************************************************************************")
@@ -47,6 +47,7 @@
4747
instances[version][instance_data["@type"]].append(instance_data)
4848

4949
python_modules = defaultdict(list)
50+
5051
for schema_version in schema_loader.get_schema_versions():
5152

5253
# Step 3 - find all involved schemas for the current version
@@ -55,14 +56,17 @@
5556
# Step 4a - figure out which schemas are embedded and which are linked
5657
embedded = set()
5758
linked = set()
59+
class_to_module_map = {}
5860
for schema_file_path in schemas_file_paths:
5961
emb, lnk = PythonBuilder(schema_file_path, schema_loader.schemas_sources).get_edges()
62+
class_to_module_map = PythonBuilder(
63+
schema_file_path, schema_loader.schemas_sources
64+
).update_class_to_module_map(class_to_module_map)
6065
embedded.update(emb)
6166
linked.update(lnk)
6267
conflicts = linked.intersection(embedded)
6368
if conflicts:
64-
print(f"Found schema(s) in version {schema_version} "
65-
f"that are both linked and embedded: {conflicts}")
69+
print(f"Found schema(s) in version {schema_version} " f"that are both linked and embedded: {conflicts}")
6670
# conflicts should not happen in new versions.
6771
# There is one conflict in v1.0, QuantitativeValue,
6872
# which we treat as embedded
@@ -76,7 +80,7 @@
7680
schema_loader.schemas_sources,
7781
instances=instances.get(schema_version, None),
7882
additional_methods=additional_methods,
79-
).build(embedded=embedded)
83+
).build(embedded=embedded, class_to_module_map=class_to_module_map)
8084

8185
parts = module_path.split(".")
8286
parent_path = ".".join(parts[:-1])
@@ -106,10 +110,7 @@
106110
with open(init_file_path, "w") as fp:
107111
fp.write(f"from . import ({', '.join(sorted(module_list))})\n")
108112

109-
env = Environment(
110-
loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))),
111-
autoescape=select_autoescape()
112-
)
113+
env = Environment(loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))), autoescape=select_autoescape())
113114
context = {
114115
"version": "0.3.0",
115116
}

pipeline/src/base.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ def value_to_jsonld(value, include_empty_properties=True, embed_linked_nodes=Tru
2727
)
2828
else:
2929
if hasattr(value, "id") and value.id is None:
30-
raise ValueError(
31-
"Exporting as a stand-alone JSON-LD document requires @id to be defined."
32-
)
30+
raise ValueError("Exporting as a stand-alone JSON-LD document requires @id to be defined.")
3331
item = {"@id": value.id}
3432
elif isinstance(value, EmbeddedMetadata):
3533
item = value.to_jsonld(
@@ -64,16 +62,17 @@ def has_property(self, name):
6462
return True
6563
return False
6664

67-
def to_jsonld(
68-
self, include_empty_properties=True, embed_linked_nodes=True, with_context=True
69-
):
65+
def to_jsonld(self, include_empty_properties=True, embed_linked_nodes=True, with_context=True):
7066
"""
7167
Return a represention of this metadata node as a dictionary that can be directly serialized to JSON-LD.
7268
"""
7369

7470
data = {"@type": self.type_}
7571
if with_context:
76-
data["@context"] = {"@vocab": "https://openminds.ebrains.eu/vocab/"}
72+
if self.type_.startswith("https://openminds.ebrains.eu/"):
73+
data["@context"] = {"@vocab": "https://openminds.ebrains.eu/vocab/"}
74+
else:
75+
data["@context"] = {"@vocab": "https://openminds.om-i.org/props/"}
7776
if hasattr(self, "id") and self.id:
7877
data["@id"] = self.id
7978
for property in self.__class__.properties:

pipeline/src/collection.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ def save(self, path, individual_files=False, include_empty_properties=False):
9090
# we first re-add all child nodes to the collection.
9191
# This is probably not the most elegant or fast way to do this, but it is simple and robust.
9292
for node in tuple(self.nodes.values()):
93+
94+
if node.type_.startswith("https://openminds.ebrains.eu/"):
95+
data_context = {"@vocab": "https://openminds.ebrains.eu/vocab/"}
96+
else:
97+
data_context = {"@vocab": "https://openminds.om-i.org/props/"}
98+
9399
for linked_node in node.links:
94100
self._add_node(linked_node)
95101
# Now we can actually save the nodes
@@ -103,7 +109,7 @@ def save(self, path, individual_files=False, include_empty_properties=False):
103109
os.makedirs(parent_dir, exist_ok=True)
104110
self._sort_nodes_by_id()
105111
data = {
106-
"@context": {"@vocab": "https://openminds.ebrains.eu/vocab/"},
112+
"@context": data_context,
107113
"@graph": [
108114
node.to_jsonld(
109115
embed_linked_nodes=False, include_empty_properties=include_empty_properties, with_context=False
@@ -118,7 +124,9 @@ def save(self, path, individual_files=False, include_empty_properties=False):
118124
if not os.path.exists(path):
119125
os.makedirs(path, exist_ok=True)
120126
if not os.path.isdir(path):
121-
raise OSError(f"If saving to multiple files, `path` must be a directory. path={path}, pwd={os.getcwd()}")
127+
raise OSError(
128+
f"If saving to multiple files, `path` must be a directory. path={path}, pwd={os.getcwd()}"
129+
)
122130
self._sort_nodes_by_id()
123131
output_paths = []
124132
for node in self:
@@ -161,9 +169,13 @@ def load(self, *paths):
161169
with open(path, "r") as fp:
162170
data = json.load(fp)
163171
if "@graph" in data:
172+
if data["@context"]["@vocab"].startswith("https://openminds.ebrains.eu/"):
173+
version = "v3"
174+
else:
175+
version = "latest"
164176
for item in data["@graph"]:
165177
if "@type" in item:
166-
cls = lookup_type(item["@type"])
178+
cls = lookup_type(item["@type"], version=version)
167179
node = cls.from_jsonld(item)
168180
else:
169181
# allow links to metadata instances outside this collection

pipeline/src/module_template.py.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class {{ class_name }}({{ base_class }}):
1616
"""
1717
type_ = "{{ openminds_type }}"
1818
context = {
19-
"@vocab": "https://openminds.ebrains.eu/vocab/"
19+
"@vocab": "{{ context_vocab }}"
2020
}
2121
schema_version = "{{ schema_version }}"
2222

@@ -61,4 +61,4 @@ class {{ class_name }}({{ base_class }}):
6161
{{key}}={{value}},
6262
{%- endif %}
6363
{% endfor -%}
64-
){% endfor %}
64+
){% endfor %}

pipeline/src/properties.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def validate(self, value, ignore=None):
118118
failures["type"].append(
119119
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, "
120120
f"value contains {type(item)}"
121-
)
121+
)
122122
elif isinstance(item, (Node, IRI)):
123123
failures.update(item.validate(ignore=ignore))
124124
if self.min_items:
@@ -148,7 +148,8 @@ def validate(self, value, ignore=None):
148148
elif not isinstance(value, self.types):
149149
if "type" not in ignore:
150150
failures["type"].append(
151-
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, " f"value is {type(value)}"
151+
f"{self.name}: Expected {', '.join(t.__name__ for t in self.types)}, "
152+
f"value is {type(value)}"
152153
)
153154
elif isinstance(value, (Node, IRI)):
154155
failures.update(value.validate(ignore=ignore))

pipeline/src/registry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def lookup_type(class_type: str, version: str = "latest") -> Node:
6868

6969
class Registry(type):
7070
"""Metaclass for registering Knowledge Graph classes."""
71+
7172
properties: List[Property] = []
7273
type_: Union[str, List[str]]
7374
context: Dict[str, str]
@@ -107,4 +108,3 @@ def property_names(cls) -> List[str]:
107108
@property
108109
def required_property_names(cls) -> List[str]:
109110
return [p.name for p in cls.properties if p.required]
110-

pipeline/tests/test_instantiation.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,7 @@ def test_json_roundtrip():
5555

5656

5757
def test_IRI():
58-
valid_iris = [
59-
"https://example.com/path/to/my/file.txt",
60-
"file:///path/to/my/file.txt"
61-
]
58+
valid_iris = ["https://example.com/path/to/my/file.txt", "file:///path/to/my/file.txt"]
6259
for value in valid_iris:
6360
iri = IRI(value)
6461
assert iri.value == value
@@ -67,9 +64,7 @@ def test_IRI():
6764
assert not failures
6865
else:
6966
assert failures["value"][0] == "IRI points to a local file path"
70-
invalid_iris = [
71-
"/path/to/my/file.txt"
72-
]
67+
invalid_iris = ["/path/to/my/file.txt"]
7368
for value in invalid_iris:
7469
with pytest.raises(ValueError) as exc_info:
7570
iri = IRI(value)

pipeline/tests/test_regressions.py

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_issue_0002():
1212

1313
node = build_fake_node(omcore.Person)
1414
data = node.to_jsonld()
15-
assert data["@type"] == "https://openminds.ebrains.eu/core/Person"
15+
assert data["@type"] == "https://openminds.om-i.org/types/Person"
1616

1717

1818
def test_issue_0003():
@@ -38,21 +38,22 @@ def test_issue_0003():
3838
)
3939
# on export, a single item should be wrapped in a list, where the property expects an array
4040
expected = {
41-
"@context": {"@vocab": "https://openminds.ebrains.eu/vocab/"},
42-
"@type": "https://openminds.ebrains.eu/core/FileArchive",
41+
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
42+
"@type": "https://openminds.om-i.org/types/FileArchive",
4343
"IRI": "http://example.com/archive.zip",
4444
"format": {
45-
"@type": "https://openminds.ebrains.eu/core/ContentType",
45+
"@type": "https://openminds.om-i.org/types/ContentType",
4646
"name": "application/zip",
4747
},
4848
"sourceData": [
4949
{
50-
"@type": "https://openminds.ebrains.eu/core/File",
50+
"@type": "https://openminds.om-i.org/types/File",
5151
"IRI": "http://example.com/some_file.txt",
5252
"name": "some_file.txt",
5353
}
5454
],
5555
}
56+
5657
assert (
5758
node1.to_jsonld(include_empty_properties=False) == node2.to_jsonld(include_empty_properties=False) == expected
5859
)
@@ -89,23 +90,19 @@ def test_issue0007():
8990

9091
actual = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True)
9192
expected = {
92-
"@context": {"@vocab": "https://openminds.ebrains.eu/vocab/"},
93+
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
9394
"@id": "_:001",
94-
"@type": "https://openminds.ebrains.eu/core/Person",
95+
"@type": "https://openminds.om-i.org/types/Person",
9596
"familyName": "Professor",
9697
"givenName": "A",
9798
"affiliation": [
9899
{
99-
"@type": "https://openminds.ebrains.eu/core/Affiliation",
100-
"memberOf": {
101-
"@id": "_:002"
102-
},
100+
"@type": "https://openminds.om-i.org/types/Affiliation",
101+
"memberOf": {"@id": "_:002"},
103102
},
104103
{
105-
"@type": "https://openminds.ebrains.eu/core/Affiliation",
106-
"memberOf": {
107-
"@id": "_:003"
108-
},
104+
"@type": "https://openminds.om-i.org/types/Affiliation",
105+
"memberOf": {"@id": "_:003"},
109106
},
110107
],
111108
}
@@ -119,36 +116,32 @@ def test_issue0007():
119116
saved_data = json.load(fp)
120117
os.remove("issue0007.jsonld")
121118
expected_saved_data = {
122-
"@context": {"@vocab": "https://openminds.ebrains.eu/vocab/"},
119+
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
123120
"@graph": [
124121
{
125122
"@id": "_:001",
126-
"@type": "https://openminds.ebrains.eu/core/Person",
123+
"@type": "https://openminds.om-i.org/types/Person",
127124
"affiliation": [
128125
{
129-
"@type": "https://openminds.ebrains.eu/core/Affiliation",
130-
"memberOf": {
131-
"@id": "_:002"
132-
},
126+
"@type": "https://openminds.om-i.org/types/Affiliation",
127+
"memberOf": {"@id": "_:002"},
133128
},
134129
{
135-
"@type": "https://openminds.ebrains.eu/core/Affiliation",
136-
"memberOf": {
137-
"@id": "_:003"
138-
},
130+
"@type": "https://openminds.om-i.org/types/Affiliation",
131+
"memberOf": {"@id": "_:003"},
139132
},
140133
],
141134
"familyName": "Professor",
142135
"givenName": "A",
143136
},
144137
{
145138
"@id": "_:002",
146-
"@type": "https://openminds.ebrains.eu/core/Organization",
139+
"@type": "https://openminds.om-i.org/types/Organization",
147140
"fullName": "University of This Place",
148141
},
149142
{
150143
"@id": "_:003",
151-
"@type": "https://openminds.ebrains.eu/core/Organization",
144+
"@type": "https://openminds.om-i.org/types/Organization",
152145
"fullName": "University of That Place",
153146
},
154147
],
@@ -170,16 +163,14 @@ def test_issue0008():
170163
)
171164
actual = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True)
172165
expected = {
173-
"@context": {"@vocab": "https://openminds.ebrains.eu/vocab/"},
166+
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
174167
"@id": "_:002",
175-
"@type": "https://openminds.ebrains.eu/core/Person",
168+
"@type": "https://openminds.om-i.org/types/Person",
176169
"affiliation": [
177170
{
178-
"@type": "https://openminds.ebrains.eu/core/Affiliation",
171+
"@type": "https://openminds.om-i.org/types/Affiliation",
179172
"endDate": "2023-09-30",
180-
"memberOf": {
181-
"@id": "_:001"
182-
},
173+
"memberOf": {"@id": "_:001"},
183174
}
184175
],
185176
"familyName": "Professor",
@@ -195,10 +186,7 @@ def test_issue0026():
195186

196187
uni1 = omcore.Organization(full_name="University of This Place", id="_:uthisp")
197188
person = omcore.Person(
198-
given_name="A",
199-
family_name="Professor",
200-
affiliations = [omcore.Affiliation(member_of=uni1)],
201-
id="_:ap"
189+
given_name="A", family_name="Professor", affiliations=[omcore.Affiliation(member_of=uni1)], id="_:ap"
202190
)
203191

204192
c = Collection(person)
@@ -223,16 +211,9 @@ def test_issue0023():
223211

224212
uni1 = omcore.Organization(full_name="University of This Place", id="_:uthisp")
225213
person = omcore.Person(
226-
given_name="A",
227-
family_name="Professor",
228-
affiliations = [omcore.Affiliation(member_of=uni1)],
229-
id="_:ap"
230-
)
231-
dv = omcore.DatasetVersion(
232-
full_name="The name of the dataset version",
233-
custodians=[person],
234-
id="_:dv"
214+
given_name="A", family_name="Professor", affiliations=[omcore.Affiliation(member_of=uni1)], id="_:ap"
235215
)
216+
dv = omcore.DatasetVersion(full_name="The name of the dataset version", custodians=[person], id="_:dv")
236217

237218
c = Collection(dv)
238219

0 commit comments

Comments
 (0)