linkml 1.5.8rc1__py3-none-any.whl → 1.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- linkml/generators/jsonschemagen.py +8 -0
- linkml/generators/legacy/__init__.py +0 -0
- linkml/generators/owlgen.py +674 -391
- linkml/generators/pythongen.py +121 -17
- linkml/utils/generator.py +0 -1
- {linkml-1.5.8rc1.dist-info → linkml-1.6.0.dist-info}/METADATA +3 -3
- {linkml-1.5.8rc1.dist-info → linkml-1.6.0.dist-info}/RECORD +10 -9
- {linkml-1.5.8rc1.dist-info → linkml-1.6.0.dist-info}/LICENSE +0 -0
- {linkml-1.5.8rc1.dist-info → linkml-1.6.0.dist-info}/WHEEL +0 -0
- {linkml-1.5.8rc1.dist-info → linkml-1.6.0.dist-info}/entry_points.txt +0 -0
linkml/generators/pythongen.py
CHANGED
@@ -2,11 +2,13 @@ import keyword
|
|
2
2
|
import logging
|
3
3
|
import os
|
4
4
|
import re
|
5
|
+
from copy import copy
|
5
6
|
from dataclasses import dataclass, field
|
6
7
|
from types import ModuleType
|
7
8
|
from typing import Callable, Dict, Iterator, List, Optional, Set, Tuple, Union
|
8
9
|
|
9
10
|
import click
|
11
|
+
from linkml_runtime import SchemaView
|
10
12
|
from linkml_runtime.linkml_model import linkml_files
|
11
13
|
from linkml_runtime.linkml_model.meta import (
|
12
14
|
ClassDefinition,
|
@@ -65,6 +67,7 @@ class PythonGenerator(Generator):
|
|
65
67
|
|
66
68
|
def __post_init__(self) -> None:
|
67
69
|
self.sourcefile = self.schema
|
70
|
+
self.schemaview = SchemaView(self.schema)
|
68
71
|
super().__post_init__()
|
69
72
|
if self.format is None:
|
70
73
|
self.format = self.valid_formats[0]
|
@@ -307,15 +310,25 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
307
310
|
if ":/" in dflt_prefix
|
308
311
|
else dflt_prefix.upper()
|
309
312
|
)
|
310
|
-
|
311
|
-
|
312
|
-
f"{pfx.upper().replace('.', '_').replace('-', '_')}
|
313
|
-
|
314
|
-
|
315
|
-
|
313
|
+
curienamespace_defs = [
|
314
|
+
{
|
315
|
+
"variable": f"{pfx.upper().replace('.', '_').replace('-', '_')}",
|
316
|
+
"value": f"CurieNamespace('{pfx.replace('.', '_')}', '{self.namespaces[pfx]}')",
|
317
|
+
}
|
318
|
+
for pfx in sorted(self.emit_prefixes)
|
319
|
+
if pfx in self.namespaces
|
320
|
+
]
|
321
|
+
curienamespace_declarations = "\n".join(
|
322
|
+
[f"{ns['variable']} = {ns['value']}" for ns in curienamespace_defs]
|
316
323
|
+ [f"DEFAULT_ = {dflt}"]
|
317
324
|
)
|
318
325
|
|
326
|
+
",".join([x["variable"] for x in curienamespace_defs])
|
327
|
+
# catalog_declaration = f"\nnamespace_catalog = CurieNamespaceCatalog.create({curienamespace_vars})\n"
|
328
|
+
catalog_declaration = ""
|
329
|
+
|
330
|
+
return curienamespace_declarations + catalog_declaration
|
331
|
+
|
319
332
|
def gen_references(self) -> str:
|
320
333
|
"""Generate python type declarations for all identifiers (primary keys)"""
|
321
334
|
rval = []
|
@@ -396,6 +409,7 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
396
409
|
parentref = f'({self.formatted_element_name(cls.is_a, True) if cls.is_a else "YAMLRoot"})'
|
397
410
|
slotdefs = self.gen_class_variables(cls)
|
398
411
|
postinits = self.gen_postinits(cls)
|
412
|
+
constructor = self.gen_constructor(cls)
|
399
413
|
|
400
414
|
wrapped_description = (
|
401
415
|
f'\n\t"""\n\t{wrapped_annotation(be(cls.description))}\n\t"""'
|
@@ -406,15 +420,18 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
406
420
|
if self.is_class_unconstrained(cls):
|
407
421
|
return f"\n{self.class_or_type_name(cls.name)} = Any"
|
408
422
|
|
409
|
-
|
423
|
+
cd_str = (
|
410
424
|
("\n@dataclass" if slotdefs else "")
|
411
425
|
+ f"\nclass {self.class_or_type_name(cls.name)}{parentref}:{wrapped_description}"
|
412
426
|
+ f"{self.gen_inherited_slots(cls)}"
|
413
427
|
+ f"{self.gen_class_meta(cls)}"
|
414
428
|
+ (f"\n\t{slotdefs}" if slotdefs else "")
|
415
429
|
+ (f"\n{postinits}" if postinits else "")
|
430
|
+
+ (f"\n{constructor}" if constructor else "")
|
416
431
|
)
|
417
432
|
|
433
|
+
return cd_str
|
434
|
+
|
418
435
|
def gen_inherited_slots(self, cls: ClassDefinition) -> str:
|
419
436
|
if not self.gen_classvars:
|
420
437
|
return ""
|
@@ -648,7 +665,6 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
648
665
|
prox_type_name = rangelist[-1]
|
649
666
|
|
650
667
|
# Quote forward references - note that enums always gen at the end
|
651
|
-
logging.info(f"CHECK: {slot.name} => {slot.range} ")
|
652
668
|
if slot.range in self.schema.enums or (
|
653
669
|
cls
|
654
670
|
and slot.inlined
|
@@ -699,20 +715,30 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
699
715
|
# TODO: Remove the bypass whenever we get default_range fixed
|
700
716
|
if slot.name not in pkeys and (not slot.ifabsent or True):
|
701
717
|
post_inits.append(self.gen_postinit(cls, slot))
|
718
|
+
post_inits_designators = []
|
719
|
+
|
720
|
+
domain_slot_names = [s.name for s in self.domain_slots(cls)]
|
721
|
+
for slot in self.schemaview.class_induced_slots(cls.name):
|
722
|
+
# This is for all type designators that were defined at a parent class
|
723
|
+
# We need to treat them specially: the initialisation should come
|
724
|
+
# AFTER the call to super() because we want to override the super behaviour
|
725
|
+
if slot.name not in domain_slot_names and slot.designates_type:
|
726
|
+
post_inits_designators.append(self.gen_postinit(cls, slot))
|
702
727
|
|
703
728
|
post_inits_pre_super_line = "\n\t\t".join([p for p in post_inits_pre_super if p]) + (
|
704
729
|
"\n\t\t" if post_inits_pre_super else ""
|
705
730
|
)
|
731
|
+
post_inits_post_super_line = "\n\t\t".join(post_inits_designators)
|
706
732
|
post_inits_line = "\n\t\t".join([p for p in post_inits if p])
|
707
733
|
return (
|
708
734
|
(
|
709
735
|
f"""
|
710
736
|
def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
|
711
737
|
{post_inits_pre_super_line}{post_inits_line}
|
712
|
-
super().__post_init__(**kwargs)
|
713
|
-
|
738
|
+
super().__post_init__(**kwargs)
|
739
|
+
{post_inits_post_super_line}"""
|
714
740
|
)
|
715
|
-
if post_inits_line or post_inits_pre_super_line
|
741
|
+
if post_inits_line or post_inits_pre_super_line or post_inits_post_super_line
|
716
742
|
else ""
|
717
743
|
)
|
718
744
|
|
@@ -751,6 +777,67 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
751
777
|
return len(rng.slots) - len(pkeys) == 1
|
752
778
|
return False
|
753
779
|
|
780
|
+
def _roll_up_type(self, typ_name: str) -> str:
|
781
|
+
if typ_name in self.schemaview.all_types():
|
782
|
+
t = self.schemaview.get_type(typ_name)
|
783
|
+
if t.typeof:
|
784
|
+
return self._roll_up_type(t.typeof)
|
785
|
+
return typ_name
|
786
|
+
|
787
|
+
def gen_constructor(self, cls: ClassDefinition) -> Optional[str]:
|
788
|
+
rlines: List[str] = []
|
789
|
+
designators = [x for x in self.domain_slots(cls) if x.designates_type]
|
790
|
+
if len(designators) > 0:
|
791
|
+
descendants = self.schemaview.class_descendants(cls.name)
|
792
|
+
if len(descendants) > 1:
|
793
|
+
slot = designators[0]
|
794
|
+
aliased_slot_name = self.slot_name(slot.name)
|
795
|
+
slot_range = self._roll_up_type(slot.range)
|
796
|
+
|
797
|
+
rlines.append("def __new__(cls, *args, **kwargs):")
|
798
|
+
td_val_expression = "kwargs[type_designator]"
|
799
|
+
if slot_range == "string":
|
800
|
+
lookup_by_props = ["class_name"]
|
801
|
+
elif slot_range == "uri":
|
802
|
+
lookup_by_props = ["class_class_uri", "class_model_uri"]
|
803
|
+
td_val_expression = (
|
804
|
+
f"URIRef({td_val_expression}) if "
|
805
|
+
f"isinstance({td_val_expression}, str) else {td_val_expression}"
|
806
|
+
)
|
807
|
+
elif slot_range == "uriorcurie":
|
808
|
+
lookup_by_props = ["class_class_curie", "class_class_uri", "class_model_uri"]
|
809
|
+
else:
|
810
|
+
raise ValueError(f"Unsupported type designator range: {slot.range}")
|
811
|
+
rlines.append(
|
812
|
+
f"""
|
813
|
+
type_designator = "{aliased_slot_name}"
|
814
|
+
if not type_designator in kwargs:
|
815
|
+
return super().__new__(cls,*args,**kwargs)
|
816
|
+
else:
|
817
|
+
type_designator_value = {td_val_expression}
|
818
|
+
target_cls = cls._class_for("{lookup_by_props[0]}", type_designator_value)
|
819
|
+
"""
|
820
|
+
)
|
821
|
+
for prop in lookup_by_props[1:]:
|
822
|
+
rlines.append(
|
823
|
+
f"""
|
824
|
+
if target_cls is None:
|
825
|
+
target_cls = cls._class_for("{prop}", type_designator_value)
|
826
|
+
"""
|
827
|
+
)
|
828
|
+
rlines.append(
|
829
|
+
f"""
|
830
|
+
if target_cls is None:
|
831
|
+
raise ValueError(f"Wrong type designator value: class {{cls.__name__}} "
|
832
|
+
f"has no subclass with {lookup_by_props}='{{kwargs[type_designator]}}'")
|
833
|
+
return super().__new__(target_cls,*args,**kwargs)
|
834
|
+
"""
|
835
|
+
)
|
836
|
+
|
837
|
+
if rlines and copy(rlines[-1]).strip() != "":
|
838
|
+
rlines.append("")
|
839
|
+
return ("\n\t" if len(rlines) > 0 else "") + "\n\t".join(rlines)
|
840
|
+
|
754
841
|
def gen_postinit(self, cls: ClassDefinition, slot: SlotDefinition) -> Optional[str]:
|
755
842
|
"""Generate python post init rules for slot in class"""
|
756
843
|
rlines: List[str] = []
|
@@ -770,18 +857,34 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
770
857
|
rlines.append(f"if self._is_empty(self.{aliased_slot_name}):")
|
771
858
|
rlines.append(f'\tself.MissingRequiredField("{aliased_slot_name}")')
|
772
859
|
|
773
|
-
# Generate the type co-
|
860
|
+
# Generate the type co-ercion for the various types.
|
774
861
|
# NOTE: if you set this to true, we will cast all types. This may be what we really want
|
775
862
|
if not slot.multivalued:
|
776
|
-
if slot.
|
863
|
+
if slot.designates_type:
|
864
|
+
pass
|
865
|
+
elif slot.required:
|
777
866
|
rlines.append(f"if not isinstance(self.{aliased_slot_name}, {base_type_name}):")
|
778
867
|
else:
|
779
868
|
rlines.append(
|
780
869
|
f"if self.{aliased_slot_name} is not None and "
|
781
870
|
f"not isinstance(self.{aliased_slot_name}, {base_type_name}):"
|
782
871
|
)
|
783
|
-
|
784
|
-
|
872
|
+
if slot.designates_type:
|
873
|
+
slot_range = self._roll_up_type(slot.range)
|
874
|
+
if slot_range == "string":
|
875
|
+
td_value_classvar = "class_name"
|
876
|
+
elif slot_range == "uri":
|
877
|
+
td_value_classvar = "class_model_uri"
|
878
|
+
elif slot_range == "uriorcurie":
|
879
|
+
td_value_classvar = "class_class_curie"
|
880
|
+
else:
|
881
|
+
raise ValueError(f"Unsupported type designator range: {slot_range}")
|
882
|
+
rlines.append(f"self.{aliased_slot_name} = str(self.{td_value_classvar})")
|
883
|
+
elif (
|
884
|
+
# A really weird case -- a class that has no properties
|
885
|
+
slot.range in self.schema.classes
|
886
|
+
and not self.schema.classes[slot.range].slots
|
887
|
+
):
|
785
888
|
rlines.append(f"\tself.{aliased_slot_name} = {base_type_name}()")
|
786
889
|
else:
|
787
890
|
if (
|
@@ -847,8 +950,9 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
847
950
|
f"{sn} = [v if isinstance(v, {base_type_name}) "
|
848
951
|
f"else {base_type_name}(v) for v in {sn}]"
|
849
952
|
)
|
850
|
-
|
851
|
-
rlines.
|
953
|
+
while rlines and copy(rlines[-1]).strip() == "":
|
954
|
+
rlines.pop()
|
955
|
+
rlines.append("")
|
852
956
|
return "\n\t\t".join(rlines)
|
853
957
|
|
854
958
|
def _slot_iter(
|
linkml/utils/generator.py
CHANGED
@@ -210,7 +210,6 @@ class Generator(metaclass=abc.ABCMeta):
|
|
210
210
|
# See https://github.com/linkml/linkml/issues/923 for discussion on how
|
211
211
|
# to simplify the overall framework
|
212
212
|
if isinstance(schema, Generator):
|
213
|
-
logging.info("Instantiating generator with another generator is deprecated")
|
214
213
|
gen = schema
|
215
214
|
self.schema = gen.schema
|
216
215
|
self.synopsis = gen.synopsis
|
@@ -1,12 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: linkml
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6.0
|
4
4
|
Summary: Linked Open Data Modeling Language
|
5
5
|
Home-page: https://linkml.io/linkml/
|
6
6
|
Keywords: schema,linked data,data modeling,rdf,owl,biolink
|
7
7
|
Author: Chris Mungall
|
8
8
|
Author-email: cjmungall@lbl.gov
|
9
|
-
Requires-Python: >=3.
|
9
|
+
Requires-Python: >=3.8,<4.0
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
11
11
|
Classifier: Environment :: Console
|
12
12
|
Classifier: Intended Audience :: Developers
|
@@ -33,7 +33,7 @@ Requires-Dist: jinja2 (>=3.1.0)
|
|
33
33
|
Requires-Dist: jsonasobj2 (>=1.0.3,<2.0.0)
|
34
34
|
Requires-Dist: jsonschema[format] (>=4.0.0)
|
35
35
|
Requires-Dist: linkml-dataops
|
36
|
-
Requires-Dist: linkml-runtime (>=1.
|
36
|
+
Requires-Dist: linkml-runtime (>=1.6.0)
|
37
37
|
Requires-Dist: openpyxl
|
38
38
|
Requires-Dist: parse
|
39
39
|
Requires-Dist: prefixcommons (>=0.1.7)
|
@@ -28,18 +28,19 @@ linkml/generators/javagen/java_record_template.jinja2,sha256=yS7vKlgkHOQJfMjeziA
|
|
28
28
|
linkml/generators/javagen.py,sha256=Byf_923aAcWhZKeuTDPIB2o6PLuMHJV5WiD_AG0t_wg,5431
|
29
29
|
linkml/generators/jsonldcontextgen.py,sha256=3JnBns93ESW-sYb0AADJ-lcUpg6bQP8JzVDetOHLV3g,7932
|
30
30
|
linkml/generators/jsonldgen.py,sha256=OYxh7humrpcopw67P4fSiX4P0aO_iSZCE3xjgXrHNvk,7637
|
31
|
-
linkml/generators/jsonschemagen.py,sha256
|
31
|
+
linkml/generators/jsonschemagen.py,sha256=-qwTKrncSyVCGKikrBkfwI2jBBBw50CNQAeS21mfeLw,24194
|
32
|
+
linkml/generators/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
33
|
linkml/generators/linkmlgen.py,sha256=LaVTMPsGdQmC_zUPCjHg9fr6RsLuPLQK9nGyqqAUkPU,3556
|
33
34
|
linkml/generators/markdowngen.py,sha256=uDgSgPEaeeTExHCe4o9X0ul5YUKMwDKIpku5FzY-_4I,33468
|
34
35
|
linkml/generators/namespacegen.py,sha256=pPjUQweKRCtDfTTtK4kfuRohef3uKPrbhNUfkmYB8bA,6472
|
35
36
|
linkml/generators/oocodegen.py,sha256=l-5zck_NNAUxJiApJrnDPkqxCv3b6v5s4hC_smelszU,7620
|
36
|
-
linkml/generators/owlgen.py,sha256=
|
37
|
+
linkml/generators/owlgen.py,sha256=JQgs0MvTbcNoFROvzBY0KmtisrKdzd9J0j3Fu7M-iDM,39742
|
37
38
|
linkml/generators/plantumlgen.py,sha256=56AnrRE92pwxmPsYgB4Rbjx0AuxO-iwpIKl7DDApuhE,15360
|
38
39
|
linkml/generators/prefixmapgen.py,sha256=AWQTHPcuPlj-rDgSCbKcX_-4eLiDww9huZoOTVels6c,4694
|
39
40
|
linkml/generators/projectgen.py,sha256=_7jP7WFLoxX_kByj7pS5PA48VXDRJ_JDmY7HaWTnnr4,9674
|
40
41
|
linkml/generators/protogen.py,sha256=MzrrwD55YH5-GMUFhSRv8Z4DIt-5mcHAih4HO_oR6zM,2342
|
41
42
|
linkml/generators/pydanticgen.py,sha256=uAvq03QKkQBY1YJemcPbssnZvsxn-IX6tFzyi6j1VMY,22763
|
42
|
-
linkml/generators/pythongen.py,sha256=
|
43
|
+
linkml/generators/pythongen.py,sha256=N-rr63YYkUmHuB7i0t4o3m-8XZ9tD3TH8Y68df35sus,53536
|
43
44
|
linkml/generators/rdfgen.py,sha256=ZWn70B9e79eV91GiZsnHmN-QQ4-CoMBd8SvKSwUd63Q,2716
|
44
45
|
linkml/generators/shaclgen.py,sha256=AyabyHUju1rAfrjSYyoxxFwiRjUmhFgbgPIN4Qe56zE,7060
|
45
46
|
linkml/generators/shexgen.py,sha256=IotuSUVNboLSx7tF6uOqdT8Rb53iqoyFu2mNTnP6eNM,9191
|
@@ -85,7 +86,7 @@ linkml/utils/converter.py,sha256=lhhFVk_t4mZ2oxGum_9VLs0Uxb8qWbS8b3xed0LkmyY,630
|
|
85
86
|
linkml/utils/datautils.py,sha256=wTVIGHkqbG2kuHp8IPVPsrZ7we99ZH5RGrVdBMdzAQs,3740
|
86
87
|
linkml/utils/datavalidator.py,sha256=kxlBZRkctIoVnrdwOULvtE7NrJK9qRtqW1Ds4LSfnlU,486
|
87
88
|
linkml/utils/execute_tutorial.py,sha256=AdjHMUUVdeYAvJr_yWVPdBJEW_AWrCuPvnqh9fAHDfU,6950
|
88
|
-
linkml/utils/generator.py,sha256=
|
89
|
+
linkml/utils/generator.py,sha256=qrD1kfcLvhC4Uaf4bjUaKMoMy1Zyc9wshuGLxEUF6bU,38716
|
89
90
|
linkml/utils/helpers.py,sha256=yR8n4zFA5wPcYC7xzRuNF3wO16vG80v6j7DM3qTNmIc,447
|
90
91
|
linkml/utils/ifabsent_functions.py,sha256=VILoHk6VajhAVRb1bBukrxl1-imrrYzfrtAV0fr_-Rs,5833
|
91
92
|
linkml/utils/logictools.py,sha256=McrU80trvdpFs68L2xcbgCiiiCRdVXzDil5HdZwJ84w,21364
|
@@ -122,8 +123,8 @@ linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
122
123
|
linkml/workspaces/datamodel/workspaces.py,sha256=1M6yqcTnlpmKhUdI-QVxL40wNC1MSRAqrOwvYoLesh0,15073
|
123
124
|
linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
|
124
125
|
linkml/workspaces/example_runner.py,sha256=hkGHGVPsRp4VQjUU8CQibpnRCMhrULktZ7_A3asj_nw,11648
|
125
|
-
linkml-1.
|
126
|
-
linkml-1.
|
127
|
-
linkml-1.
|
128
|
-
linkml-1.
|
129
|
-
linkml-1.
|
126
|
+
linkml-1.6.0.dist-info/LICENSE,sha256=Nv_Z3AhdUpp-YOEnbXOuWgMLAgMT5sVAhZOmrirzlnM,6555
|
127
|
+
linkml-1.6.0.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
128
|
+
linkml-1.6.0.dist-info/METADATA,sha256=f1cWdCoGnqXPXmMwg-5GojfkYwppx2XYLlylK8XP8zY,3525
|
129
|
+
linkml-1.6.0.dist-info/entry_points.txt,sha256=Y_WcIenx01tAlAi192U1eDjpL7LZ4D9b72GqrCZSr9Q,2160
|
130
|
+
linkml-1.6.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|