Skip to content

Commit 5b539b3

Browse files
Merge pull request openMetadataInitiative#82 from apdavison/prepare-release
Prepare 0.4.0 release
2 parents 8ebae02 + dc27438 commit 5b539b3

File tree

4 files changed

+63
-3
lines changed

4 files changed

+63
-3
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,17 @@ For more detail see #29.
6666
- addition of a `Link` class, to allow making reference to remote graph nodes defined by their `@id`
6767
that are not present locally.
6868
- improved CI testing: we now test v3 and v4, as well as "latest".
69+
70+
## Release 0.4.0 (2025-11-18)
71+
72+
- drop support for Python 3.8, add support for Python 3.14.
73+
- more forgiving import of JSON-LD:
74+
- an option to allow additional (non-openMINDS) keys in a JSON-LD document [#63](https://github.com/openMetadataInitiative/openMINDS_Python/pull/63)
75+
- support fully-expanded IRIs as keys in JSON-LD documents [#64](https://github.com/openMetadataInitiative/openMINDS_Python/pull/64)
76+
- accept `datetime` strings for properties with type `date` [#65](https://github.com/openMetadataInitiative/openMINDS_Python/pull/65)
77+
- accept `"@type": [<IRI>]` as well as `"@type": <IRI>` [#66](https://github.com/openMetadataInitiative/openMINDS_Python/pull/66)
78+
- make the class registry reusable by other packages [#70](https://github.com/openMetadataInitiative/openMINDS_Python/pull/70)
79+
- bug fix: prevent infinite recursion in `validate()` where there are loops in the graph [#76](https://github.com/openMetadataInitiative/openMINDS_Python/pull/76)
80+
- allow the user to specify which openMINDS version should be used by `Collection.load()` [#77](https://github.com/openMetadataInitiative/openMINDS_Python/pull/77)
81+
- add the option to group files into subdirectories by schema when saving [#80](https://github.com/openMetadataInitiative/openMINDS_Python/pull/80)
82+
- improvements to the `by_name()` method [#81](https://github.com/openMetadataInitiative/openMINDS_Python/pull/81)

build.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120

121121
env = Environment(loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))), autoescape=select_autoescape())
122122
context = {
123-
"version": "0.3.1",
123+
"version": "0.4.0",
124124
}
125125
if args.branch == "development":
126126
context["version"] += ".dev"

pipeline/src/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ def to_jsonld(self):
284284
"@id": self.identifier
285285
}
286286

287+
287288
class IRI:
288289
"""
289290
Representation of an International Resource Identifier

pipeline/src/collection.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
The collection can be saved to and loaded from disk, in JSON-LD format.
66
"""
77

8+
from collections import Counter
89
from glob import glob
10+
from importlib import import_module
911
import json
1012
import os
1113
from .registry import lookup_type
@@ -70,6 +72,30 @@ def _sort_nodes_by_id(self):
7072
sorted_nodes = dict(sorted(self.nodes.items()))
7173
self.nodes = sorted_nodes
7274

75+
def generate_ids(self, id_generator):
76+
"""
77+
Generate an IRI id for all nodes in the graph that do not possess one.
78+
79+
Args
80+
----
81+
82+
id_generator (function):
83+
a function that takes the node as an argument, and returns a unique IRI
84+
"""
85+
for node_id in list(self.nodes.keys()):
86+
if node_id.startswith("_:"):
87+
node = self.nodes.pop(node_id)
88+
node.id = id_generator(node)
89+
self.nodes[node.id] = node
90+
91+
@property
92+
def complete(self):
93+
"""Do all nodes have an IRI?"""
94+
for node_id in self.nodes:
95+
if node_id.startswith("_:"):
96+
return False
97+
return True
98+
7399
def save(self, path, individual_files=False, include_empty_properties=False, group_by_schema=False):
74100
"""
75101
Save the node collection to disk in JSON-LD format.
@@ -171,8 +197,18 @@ def load(self, *paths, version=DEFAULT_VERSION):
171197
2) one or more JSON-LD files, which will all be loaded.
172198
173199
By default, openMINDS v4 will be used.
174-
If the JSON-LD files use a different openMINDS version, specify it with the `version` argument.
200+
If the JSON-LD files use a different openMINDS version, specify it
201+
with the `version` argument, e.g.::
202+
203+
import openminds.latest
204+
205+
c = Collection()
206+
c.load("/path/to/my/metadata.jsonld", version="latest")
207+
175208
"""
209+
210+
import_module(f"openminds.{version}")
211+
176212
if len(paths) == 1 and os.path.isdir(paths[0]):
177213
data_dir = paths[0]
178214
json_paths = (
@@ -199,7 +235,7 @@ def load(self, *paths, version=DEFAULT_VERSION):
199235
self.add(node)
200236
else:
201237
if "@type" in data:
202-
cls = lookup_type(data["@type"])
238+
cls = lookup_type(data["@type"], version=version)
203239
node = cls.from_jsonld(data)
204240
else:
205241
# allow links to metadata instances outside this collection
@@ -260,3 +296,12 @@ def sort_nodes_for_upload(self):
260296
newly_sorted.append(node_id)
261297
unsorted -= set(newly_sorted)
262298
return [self.nodes[node_id] for node_id in sorted]
299+
300+
def statistics(self):
301+
"""
302+
Return a counter containing the number of nodes of each type.
303+
"""
304+
stats = Counter(
305+
node.__class__.__name__ for node in self.nodes.values()
306+
)
307+
return stats

0 commit comments

Comments
 (0)