Fix type reference order in code generated by gen-python #181
7 changed files with 100 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = '5.3.3'
|
||||
__version__ = '5.3.4'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
49
dump_things_service/patches/pythongen_gen_references.py
Normal file
49
dump_things_service/patches/pythongen_gen_references.py
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue