Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9615791
wip
apdavison May 20, 2024
f18e789
Semi-manual merge of branch 'master' into inherit-ompy1
apdavison Jul 13, 2025
7b3835b
adapt tests
apdavison Jul 16, 2025
7852125
rename `from_kg_instance()` to `from_json_ld()` for consistency with …
apdavison Jul 17, 2025
2843b75
Apply changes from [0b889480]
apdavison Jul 17, 2025
946470d
bug fixes and improvements
apdavison Jul 18, 2025
50f465a
Use `@vocab` in contexts; fix method resolution order by re-ordering …
apdavison Jul 30, 2025
ba49cea
Changes to openminds module due to recent builder changes
apdavison Jul 30, 2025
0471219
Use new namespace (openMINDS v4+) everywhere internally; all namespac…
apdavison Jul 31, 2025
b25091a
wip
apdavison Sep 8, 2025
e4df6ff
Cast openMINDS terminology instances to their fairgraph subclasses
apdavison Sep 9, 2025
e35e8be
Fix __repr__ for the case when not all properties have been set
apdavison Sep 9, 2025
00f98bf
When setting error handling for a class, set the same value for all e…
apdavison Sep 9, 2025
5853d18
In query generation, cast openMINDS classes (in property definitions)…
apdavison Sep 15, 2025
0411a3f
Fix `KGClient.configure_space()` and `KGClient.space_info()` to work …
apdavison Sep 15, 2025
1813184
Handle retrieving KG-independent (openMINDS) URIs for controlled terms
apdavison Sep 16, 2025
3d1e236
Avoid instantiating nodes as KGObjects when cleaning an entire space
apdavison Sep 16, 2025
cb7107d
Fix more bugs relating to the openMINDS v3-v4 transition
apdavison Sep 16, 2025
9f4738e
A better way to make openMINDS terminology instances available as fai…
apdavison Sep 17, 2025
314a0bc
Adapt unit tests to work with a non-privileged user token (i.e., not …
apdavison Sep 17, 2025
5f40f4a
Preparations for tying fairgraph.openminds to a stable openMINDS version
apdavison Sep 17, 2025
d75c686
When constructing filters, check that the keys actually correspond to…
apdavison Sep 26, 2025
65b5034
Assorted fixes
apdavison Oct 3, 2025
461a0a5
Do not add values for reverse properties (as KGProxy instances) unles…
apdavison Nov 2, 2025
e943caa
Merge branch 'master' into inherit-ompy
apdavison Nov 3, 2025
52c4929
Add openMINDS Python as a dependency to pyproject.toml and requiremen…
apdavison Nov 3, 2025
39f9fcd
Update CI test matrix
apdavison Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
4 changes: 2 additions & 2 deletions builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
To update the `fairgraph.openminds` module, run:

```
python update_openminds.py /path/to/openMINDS
python update_openminds.py /path/to/openMINDS/schemas/latest
```

Where the various submodules have already been cloned and the desired version branches checked out.
Where /path/to/openMINDS is a clone of the main branch of https://github.com/openMetadataInitiative/openMINDS.git

Before committing the resulting generated files, check that any changed introduced seem correct.
Currently a few changes are applied by hand on top of the generated files, be sure not to overwrite these.
22 changes: 8 additions & 14 deletions builder/fairgraph_module_template.py.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,22 @@

# this file was auto-generated

from fairgraph import {{ base_class }}, IRI
from fairgraph.properties import Property
from openminds.properties import Property
from openminds.{{ openminds_version }}.{{ module_name }} import {{ class_name }} as OM{{ class_name }}
from fairgraph import {{ base_class }}

{{preamble}}


class {{ class_name }}({{ base_class }}):
class {{ class_name }}({{base_class}}, OM{{ class_name }}):
"""
{{ docstring }}
"""
type_ = "{{ openminds_type }}"
{%- if default_space %}
default_space = "{{ default_space }}"
{%- endif %}
type_ = "{{ openminds_type }}"
properties = [
{% for prop in properties -%}
Property("{{prop.name}}", {{prop.type_str}}, "{{prop.iri}}",
{%- if prop.allow_multiple %}multiple={{prop.allow_multiple}},{% endif -%}
{%- if prop.required %}required={{prop.required}},{% endif -%}
doc="{{prop.doc}}"),
{% endfor %}
]
# forward properties are defined in the parent class (in openMINDS-Python)
reverse_properties = [
{% for prop in reverse_properties -%}
Property(
Expand All @@ -42,7 +36,7 @@ class {{ class_name }}({{ base_class }}):
{% endif -%}
{%- if prop.allow_multiple %}multiple={{prop.allow_multiple}},{% endif -%}
{%- if prop.required %}, required={{prop.required}},{% endif -%}
doc="{{prop.doc}}"),
description="{{prop.doc}}"),
{% endfor %}
]
{%- if aliases %}
Expand All @@ -53,5 +47,5 @@ class {{ class_name }}({{ base_class }}):
{%- endif %}

def __init__(self {%- for arg in constructor_arguments -%}, {{arg}}=None{%- endfor -%}, id=None, data=None, space=None, scope=None):
return super().__init__({{ standard_init_properties }}data=data {%- for arg in constructor_arguments -%}, {{arg}}={{arg}}{%- endfor -%})
return {{ base_class }}.__init__(self, {{ standard_init_properties }}data=data {%- for arg in constructor_arguments -%}, {{arg}}={{arg}}{%- endfor -%})
{{ additional_methods }}
31 changes: 10 additions & 21 deletions builder/update_openminds.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from jinja2 import Environment, select_autoescape, FileSystemLoader

OPENMINDS_VERSION = "latest"

name_map = {
"scope": "model_scope", # this is because 'scope' is already a keyword
Expand Down Expand Up @@ -275,7 +276,7 @@ def invert_dict(D):


DEFAULT_SPACES = {
"chemicals": {"default": "dataset"},
"chemicals": {"default": "in-depth"},
"core": invert_dict(
{
"common": [
Expand Down Expand Up @@ -387,7 +388,6 @@ def invert_dict(D):
),
"publications": {"default": "livepapers"},
"ephys": {"default": "in-depth"},
"chemicals": {"default": "in-depth"},
"specimen_prep": {"default": "in-depth"},
"stimulation": {"default": "in-depth"},
}
Expand Down Expand Up @@ -489,7 +489,7 @@ def generate_class_name(iri, module_map=None):
assert isinstance(iri, str)
class_name = iri.split("/")[-1]
module_name = generate_python_name(module_map[iri])
return f"openminds.{module_name}.{class_name}"
return f"openminds.{OPENMINDS_VERSION}.{module_name}.{class_name}"


def get_controlled_terms_table(type_):
Expand Down Expand Up @@ -586,17 +586,6 @@ def get_controlled_terms_table(type_):
}


def get_type_from_schema(schema_payload, override=True):
if override: # temporarily use the old namespaces, until the KG is updated
cls_name = schema_payload["_type"].split("/")[-1]
module_name = schema_payload['_module']
if module_name == "SANDS":
module_name = "sands"
return f"https://openminds.ebrains.eu/{module_name}/{cls_name}"
else:
return schema_payload["_type"]


class FairgraphClassBuilder:
"""docstring"""

Expand Down Expand Up @@ -631,7 +620,6 @@ def get_type(prop):
"email": "str", # todo: add an Email class for validation?
"ECMA262": "str", # ...
}
#breakpoint()
if "_linkedTypes" in prop:
types = []
for item in prop["_linkedTypes"]:
Expand Down Expand Up @@ -697,7 +685,7 @@ def get_type(prop):
{
"name": python_name,
"type_str": get_type(prop), # compress using JSON-LD context
"iri": f"vocab:{prop['name']}",
"iri": f"{prop['name']}",
"allow_multiple": allow_multiple,
"required": iri in self._schema_payload.get("required", []),
"doc": generate_doc(prop, class_name),
Expand Down Expand Up @@ -732,7 +720,7 @@ def get_type(prop):
# todo: we should fix this at some point, using just the first forward_link_name causes things to break
# making this a dictionary keyed by class names should work?
_forward_link_name_python = generate_python_name(forward_link_name)
iri = f"^vocab:{forward_iri}"
iri = forward_iri
doc = f"reverse of '{_forward_link_name_python}'"
types_str = sorted(types_str)
if len(types_str) == 1:
Expand All @@ -749,7 +737,7 @@ def get_type(prop):
forward_iri = linked_from[reverse_link_name][0]
forward_link_name = linked_from[reverse_link_name][1]
_forward_link_name_python = [generate_python_name(name) for name in forward_link_name]
iri = [f"^vocab:{part}" for part in forward_iri]
iri = [part for part in forward_iri]
doc = "reverse of " + ", ".join(name for name in _forward_link_name_python)
reverse_name_python = generate_python_name(reverse_link_name)
if reverse_name_python in forward_property_names:
Expand Down Expand Up @@ -777,12 +765,14 @@ def get_type(prop):
with open(f"additional_methods/{class_name}.py.txt") as fp:
additional_methods = fp.read()
self.context = {
"openminds_version": OPENMINDS_VERSION,
"docstring": self._schema_payload.get("description", "<description not available>"),
"base_class": base_class,
"preamble": preamble.get(class_name, ""), # default value, may be updated below
"module_name": module_name,
"class_name": class_name,
"default_space": default_space,
"openminds_type": get_type_from_schema(self._schema_payload, override=True),
"openminds_type": self._schema_payload["_type"],
"properties": sorted(properties, key=lambda p: p["name"]),
"reverse_properties": sorted(reverse_properties, key=lambda p: p["name"]),
"additional_methods": "",
Expand All @@ -799,7 +789,7 @@ def get_type(prop):
"date": "from datetime import date",
"datetime": "from datetime import datetime",
"time": "from datetime import time",
"IRI": "from fairgraph.base import IRI",
"IRI": "from openminds import IRI",
"[datetime, time]": "from datetime import datetime, time",
"Real": "from numbers import Real"
}
Expand Down Expand Up @@ -849,7 +839,6 @@ def get_edges(self):
reverse_link_name,
) # linked from (cls, prop name, prop name plural, reverse name)
# if self._schema_payload["_type"].endswith("File"):
# breakpoint()
return embedded, linked

def get_module_map(self):
Expand Down
16 changes: 13 additions & 3 deletions fairgraph/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,24 @@
limitations under the License.
"""

from openminds import IRI
from .client import KGClient
from .kgobject import KGObject
from .embedded import EmbeddedMetadata
from .kgproxy import KGProxy
from .kgquery import KGQuery
from .base import IRI
from . import client, errors, openminds, utility

__version__ = "0.12.2"

# from . import (
# base, client, errors, utility, openminds)
utility.initialise_instances([
openminds.sands.BrainAtlas,
openminds.sands.BrainAtlasVersion,
openminds.sands.CommonCoordinateSpace,
openminds.sands.CommonCoordinateSpaceVersion,
openminds.core.ContentType,
openminds.core.License,
openminds.sands.ParcellationEntity,
openminds.sands.ParcellationEntityVersion] +
openminds.controlled_terms.list_kg_classes()
)
Loading