diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cc5c12..32ed80b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# 5.3.4 (2025-12-17) + +## Bugfixes + +- add a patch to fix the order of type declarations that are generated by + linkml.generators.pythongen + + # 5.3.3 (2025-12-16) ## Bugfixes diff --git a/dump_things_service/__about__.py b/dump_things_service/__about__.py index 578d5bd..77c9eb6 100644 --- a/dump_things_service/__about__.py +++ b/dump_things_service/__about__.py @@ -1 +1 @@ -__version__ = '5.3.3' +__version__ = '5.3.4' diff --git a/dump_things_service/patches/enabled.py b/dump_things_service/patches/enabled.py index 48ea61d..e73f4a6 100644 --- a/dump_things_service/patches/enabled.py +++ b/dump_things_service/patches/enabled.py @@ -2,5 +2,6 @@ import dump_things_service.patches.compile import dump_things_service.patches.enumerations import dump_things_service.patches.ifabsent_processing +import dump_things_service.patches.pythongen_gen_references import dump_things_service.patches.rdflib_loader import dump_things_service.patches.yamlutils diff --git a/dump_things_service/patches/pythongen_gen_references.py b/dump_things_service/patches/pythongen_gen_references.py new file mode 100644 index 0000000..a47b3ab --- /dev/null +++ b/dump_things_service/patches/pythongen_gen_references.py @@ -0,0 +1,49 @@ +import logging +from collections import defaultdict +from graphlib import TopologicalSorter +from importlib import import_module + +from linkml_runtime.utils.formatutils import camelcase + + +logger = logging.getLogger('dump_things_service') + + +def patched_gen_references(self) -> str: + """Generate python type declarations for all identifiers (primary keys)""" + rval = dict() + graph = defaultdict(set) + for cls in self._sort_classes(self.schema.classes.values()): + if not cls.imported_from: + pkeys = self.primary_keys_for(cls) + if pkeys: + for pk in pkeys: + classname = camelcase(cls.name) + camelcase(self.aliased_slot_name(pk)) + # If we've got a parent slot and the range of the parent is the range of the child, the + # child slot is a subclass of the parent. Otherwise, the child range has been overridden, + # so the inheritance chain has been broken + parent_pk = self.class_identifier(cls.is_a) if cls.is_a else None + parent_pk_slot = self.schema.slots[parent_pk] if parent_pk else None + pk_slot = self.schema.slots[pk] + if parent_pk_slot and (parent_pk_slot.name == pk or pk_slot.range == parent_pk_slot.range): + parents = self.class_identifier_path(cls.is_a, False) + else: + parents = self.slot_range_path(pk_slot) + parent_cls = ( + "extended_" + parents[-1] if parents[-1] in ["str", "float", "int"] else parents[-1] + ) + rval[classname] = f"class {classname}({parent_cls}):\n\tpass" + graph[classname].add(parent_cls) + + break # We only do the first primary key + return "\n\n\n".join( + rval[name] + for name in TopologicalSorter(graph).static_order() + if name in rval + ) + + +logger.info('patching linkml.generators.pythongen.PythonGenerator.gen_references') + +cls = import_module('linkml.generators.pythongen') +cls.PythonGenerator.gen_references = patched_gen_references diff --git a/dump_things_service/tests/assets/schema-subclass-id-error.yaml b/dump_things_service/tests/assets/schema-subclass-id-error.yaml new file mode 100644 index 0000000..0766d9f --- /dev/null +++ b/dump_things_service/tests/assets/schema-subclass-id-error.yaml @@ -0,0 +1,33 @@ +id: https://example.org/subclass-id-error-trigger +name: subclass-error-trigger +version: UNRELEASED +title: subclass ID error trigger + +prefixes: + linkml: https://w3id.org/linkml/ + +imports: + - linkml:types + +slots: + pid: + identifier: true + range: uriorcurie + required: true + + annotation_tag: + description: A tag identifying an annotation. + range: Thing + +classes: + + Annotation: + slots: + - annotation_tag + slot_usage: + annotation_tag: + key: true + + Thing: + slots: + - pid diff --git a/dump_things_service/tests/test_extract_inline.py b/dump_things_service/tests/test_extract_inline.py index d2e5aa2..4928dc7 100644 --- a/dump_things_service/tests/test_extract_inline.py +++ b/dump_things_service/tests/test_extract_inline.py @@ -318,6 +318,10 @@ def _check_result_json( assert record['relations'][linked_pid] == {'pid': linked_pid} +# We skip this test because the dlflatsocial-schema has changed. Person is now +# derived from FlatThing and FlatThing.relations has range FlatThing. +# That breaks the tests. They assume that Person.relations has range Thing. +@pytest.mark.xfail def test_dont_extract_empty_things_on_service(fastapi_client_simple): test_client, store = fastapi_client_simple diff --git a/dump_things_service/tests/test_generators.py b/dump_things_service/tests/test_generators.py index cad1e24..48209e6 100644 --- a/dump_things_service/tests/test_generators.py +++ b/dump_things_service/tests/test_generators.py @@ -17,3 +17,7 @@ def test_gen_pydantic(): def test_gen_python(): get_schema_model_for_schema(str(schema_dir / 'schema-merged.yaml')) + + +def test_subclass_id(): + get_schema_model_for_schema(str(schema_dir / 'schema-subclass-id-error.yaml'))