linkml 1.8.0__py3-none-any.whl → 1.8.1__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 +13 -1
- linkml/generators/plantumlgen.py +23 -6
- linkml/generators/pydanticgen/__init__.py +2 -1
- linkml/generators/pydanticgen/includes.py +6 -0
- linkml/generators/pydanticgen/pydanticgen.py +24 -14
- linkml/generators/pydanticgen/template.py +6 -1
- linkml/generators/pydanticgen/templates/module.py.jinja +1 -1
- {linkml-1.8.0.dist-info → linkml-1.8.1.dist-info}/METADATA +1 -1
- {linkml-1.8.0.dist-info → linkml-1.8.1.dist-info}/RECORD +12 -12
- {linkml-1.8.0.dist-info → linkml-1.8.1.dist-info}/LICENSE +0 -0
- {linkml-1.8.0.dist-info → linkml-1.8.1.dist-info}/WHEEL +0 -0
- {linkml-1.8.0.dist-info → linkml-1.8.1.dist-info}/entry_points.txt +0 -0
@@ -435,8 +435,20 @@ class JsonSchemaGenerator(Generator):
|
|
435
435
|
constraints.add_keyword("const", slot.equals_number)
|
436
436
|
return constraints
|
437
437
|
|
438
|
-
def get_subschema_for_slot(
|
438
|
+
def get_subschema_for_slot(
|
439
|
+
self, slot: Union[SlotDefinition, AnonymousSlotExpression], omit_type: bool = False
|
440
|
+
) -> JsonSchema:
|
439
441
|
prop = JsonSchema()
|
442
|
+
if isinstance(slot, SlotDefinition) and slot.array:
|
443
|
+
# TODO: this is currently too lax, in that it will validate ANY array.
|
444
|
+
# see https://github.com/linkml/linkml/issues/2188
|
445
|
+
prop = JsonSchema(
|
446
|
+
{
|
447
|
+
"type": ["null", "boolean", "object", "number", "string", "array"],
|
448
|
+
"additionalProperties": True,
|
449
|
+
}
|
450
|
+
)
|
451
|
+
return JsonSchema.array_of(prop)
|
440
452
|
slot_is_multivalued = "multivalued" in slot and slot.multivalued
|
441
453
|
slot_is_inlined = self.schemaview.is_inlined(slot)
|
442
454
|
if not omit_type:
|
linkml/generators/plantumlgen.py
CHANGED
@@ -12,7 +12,11 @@ from typing import Callable, List, Optional, Set, cast
|
|
12
12
|
|
13
13
|
import click
|
14
14
|
import requests
|
15
|
-
from linkml_runtime.linkml_model.meta import
|
15
|
+
from linkml_runtime.linkml_model.meta import (
|
16
|
+
ClassDefinition,
|
17
|
+
ClassDefinitionName,
|
18
|
+
SlotDefinition,
|
19
|
+
)
|
16
20
|
from linkml_runtime.utils.formatutils import camelcase, underscore
|
17
21
|
|
18
22
|
from linkml import REQUESTS_TIMEOUT
|
@@ -46,6 +50,7 @@ class PlantumlGenerator(Generator):
|
|
46
50
|
directory: Optional[str] = None
|
47
51
|
kroki_server: Optional[str] = "https://kroki.io"
|
48
52
|
load_image: bool = True
|
53
|
+
tooltips_flag: bool = False
|
49
54
|
|
50
55
|
def visit_schema(
|
51
56
|
self,
|
@@ -132,18 +137,28 @@ class PlantumlGenerator(Generator):
|
|
132
137
|
" {field} "
|
133
138
|
+ underscore(self.aliased_slot_name(slot))
|
134
139
|
+ mod
|
135
|
-
+ ": "
|
140
|
+
+ " : "
|
136
141
|
+ underscore(slot.range)
|
142
|
+
+ " "
|
137
143
|
+ self.cardinality(slot)
|
138
144
|
)
|
139
145
|
self.class_generated.add(cn)
|
140
146
|
self.referenced.add(cn)
|
141
147
|
cls = self.schema.classes[cn]
|
148
|
+
|
149
|
+
tooltip_contents = str(cls.description)
|
150
|
+
first_newline_index = tooltip_contents.find("\n")
|
151
|
+
tooltip_contents = tooltip_contents if first_newline_index < 0 else tooltip_contents[0:first_newline_index]
|
152
|
+
|
153
|
+
if self.format == "svg" and len(tooltip_contents) > 200:
|
154
|
+
tooltip_contents = tooltip_contents[0:197] + " ... "
|
155
|
+
|
156
|
+
tooltip = " [[{" + tooltip_contents + "}]] "
|
142
157
|
if cls.abstract:
|
143
158
|
class_type = "abstract"
|
144
159
|
else:
|
145
160
|
class_type = "class"
|
146
|
-
return class_type + ' "' + cn +
|
161
|
+
return class_type + ' "' + cn + '"' + tooltip + ("{\n" + "\n".join(slot_defs) + "\n}")
|
147
162
|
|
148
163
|
def class_associations(self, cn: ClassDefinitionName, must_render: bool = False) -> str:
|
149
164
|
"""Emit all associations for a focus class. If none are specified, all classes are generated
|
@@ -217,7 +232,7 @@ class PlantumlGenerator(Generator):
|
|
217
232
|
classes.append(self.add_class(cn))
|
218
233
|
if mixin not in self.class_generated:
|
219
234
|
classes.append(self.add_class(mixin))
|
220
|
-
assocs.append(cn + plantuml_uses[0] + mixin + plantuml_uses[1])
|
235
|
+
assocs.append('"' + cn + '" ' + plantuml_uses[0] + ' "' + mixin + '" ' + plantuml_uses[1])
|
221
236
|
|
222
237
|
# Classes that use the class as a mixin
|
223
238
|
if cls.name in self.synopsis.mixinrefs:
|
@@ -226,7 +241,9 @@ class PlantumlGenerator(Generator):
|
|
226
241
|
classes.append(self.add_class(ClassDefinitionName(mixin)))
|
227
242
|
if cn not in self.class_generated:
|
228
243
|
classes.append(self.add_class(cn))
|
229
|
-
assocs.append(
|
244
|
+
assocs.append(
|
245
|
+
'"' + ClassDefinitionName(mixin) + '" ' + plantuml_uses[0] + ' "' + cn + '" ' + plantuml_uses[1]
|
246
|
+
)
|
230
247
|
|
231
248
|
# Classes that inject information
|
232
249
|
if cn in self.synopsis.applytos.classrefs:
|
@@ -265,7 +282,7 @@ class PlantumlGenerator(Generator):
|
|
265
282
|
if slot.multivalued:
|
266
283
|
return " [1..*]" if slot.required else " [0..*]"
|
267
284
|
else:
|
268
|
-
return "
|
285
|
+
return " "
|
269
286
|
else:
|
270
287
|
if slot.multivalued:
|
271
288
|
return '"1..*" ' if slot.required else '"0..*" '
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from linkml.generators.pydanticgen.pydanticgen import DEFAULT_IMPORTS, PydanticGenerator, cli
|
1
|
+
from linkml.generators.pydanticgen.pydanticgen import DEFAULT_IMPORTS, MetadataMode, PydanticGenerator, cli
|
2
2
|
from linkml.generators.pydanticgen.template import (
|
3
3
|
ConditionalImport,
|
4
4
|
Import,
|
@@ -18,6 +18,7 @@ __all__ = [
|
|
18
18
|
"DEFAULT_IMPORTS",
|
19
19
|
"Import",
|
20
20
|
"Imports",
|
21
|
+
"MetadataMode",
|
21
22
|
"PydanticAttribute",
|
22
23
|
"PydanticBaseModel",
|
23
24
|
"PydanticClass",
|
@@ -19,6 +19,9 @@ class LinkMLMeta(BaseModel):
|
|
19
19
|
|
20
20
|
def __setitem__(self, key:str, value):
|
21
21
|
self.__root__[key] = value
|
22
|
+
|
23
|
+
def __contains__(self, key:str) -> bool:
|
24
|
+
return key in self.__root__
|
22
25
|
|
23
26
|
class Config:
|
24
27
|
allow_mutation = False
|
@@ -37,6 +40,9 @@ class LinkMLMeta(RootModel):
|
|
37
40
|
|
38
41
|
def __setitem__(self, key:str, value):
|
39
42
|
self.root[key] = value
|
43
|
+
|
44
|
+
def __contains__(self, key:str) -> bool:
|
45
|
+
return key in self.root
|
40
46
|
|
41
47
|
"""
|
42
48
|
|
@@ -582,17 +582,22 @@ class PydanticGenerator(OOCodeGenerator):
|
|
582
582
|
elif self.metadata_mode in (MetadataMode.EXCEPT_CHILDREN, MetadataMode.EXCEPT_CHILDREN.value):
|
583
583
|
meta = {}
|
584
584
|
for k, v in remove_empty_items(source).items():
|
585
|
+
if k in ("slots", "classes") and isinstance(model, PydanticModule):
|
586
|
+
# FIXME: Special-case removal of slots until we generate class-level slots
|
587
|
+
continue
|
588
|
+
|
585
589
|
if not hasattr(model, k):
|
586
590
|
meta[k] = v
|
587
|
-
|
588
|
-
|
589
|
-
)
|
591
|
+
continue
|
592
|
+
|
593
|
+
model_attr = getattr(model, k)
|
594
|
+
if isinstance(model_attr, list) and not any([isinstance(item, TemplateModel) for item in model_attr]):
|
590
595
|
meta[k] = v
|
591
|
-
elif isinstance(
|
592
|
-
[isinstance(item, TemplateModel) for item in
|
596
|
+
elif isinstance(model_attr, dict) and not any(
|
597
|
+
[isinstance(item, TemplateModel) for item in model_attr.values()]
|
593
598
|
):
|
594
599
|
meta[k] = v
|
595
|
-
elif not isinstance(
|
600
|
+
elif not isinstance(model_attr, (list, dict, TemplateModel)):
|
596
601
|
meta[k] = v
|
597
602
|
|
598
603
|
elif self.metadata_mode in (MetadataMode.FULL, MetadataMode.FULL.value):
|
@@ -600,7 +605,7 @@ class PydanticGenerator(OOCodeGenerator):
|
|
600
605
|
else:
|
601
606
|
raise ValueError(
|
602
607
|
f"Unknown metadata mode '{self.metadata_mode}', needs to be one of "
|
603
|
-
f"{[mode
|
608
|
+
f"{[mode for mode in MetadataMode]}"
|
604
609
|
)
|
605
610
|
|
606
611
|
model.meta = meta
|
@@ -753,22 +758,17 @@ class PydanticGenerator(OOCodeGenerator):
|
|
753
758
|
new_class.bases = bases[k]
|
754
759
|
classes[k] = new_class
|
755
760
|
|
756
|
-
schema_meta = {
|
757
|
-
k: v for k, v in remove_empty_items(schema).items() if k not in PydanticModule.exclude_from_meta()
|
758
|
-
}
|
759
|
-
|
760
761
|
module = PydanticModule(
|
761
762
|
pydantic_ver=self.pydantic_version,
|
762
763
|
metamodel_version=self.schema.metamodel_version,
|
763
764
|
version=self.schema.version,
|
764
|
-
|
765
|
+
python_imports=imports.imports,
|
765
766
|
base_model=base_model,
|
766
767
|
injected_classes=injected_classes,
|
767
768
|
enums=enums,
|
768
769
|
classes=classes,
|
769
|
-
meta=schema_meta,
|
770
770
|
)
|
771
|
-
module = self.include_metadata(module,
|
771
|
+
module = self.include_metadata(module, schema)
|
772
772
|
return module
|
773
773
|
|
774
774
|
def serialize(self) -> str:
|
@@ -830,6 +830,14 @@ Available templates to override:
|
|
830
830
|
default=False,
|
831
831
|
help="Format generated models with black (must be present in the environment)",
|
832
832
|
)
|
833
|
+
@click.option(
|
834
|
+
"--meta",
|
835
|
+
type=click.Choice([k for k in MetadataMode]),
|
836
|
+
default="auto",
|
837
|
+
help="How to include linkml schema metadata in generated pydantic classes. "
|
838
|
+
"See docs for MetadataMode for full description of choices. "
|
839
|
+
"Default (auto) is to include all metadata that can't be otherwise represented",
|
840
|
+
)
|
833
841
|
@click.version_option(__version__, "-V", "--version")
|
834
842
|
@click.command()
|
835
843
|
def cli(
|
@@ -844,6 +852,7 @@ def cli(
|
|
844
852
|
pydantic_version=int(PYDANTIC_VERSION[0]),
|
845
853
|
extra_fields: Literal["allow", "forbid", "ignore"] = "forbid",
|
846
854
|
black: bool = False,
|
855
|
+
meta: MetadataMode = "auto",
|
847
856
|
**args,
|
848
857
|
):
|
849
858
|
"""Generate pydantic classes to represent a LinkML model"""
|
@@ -870,6 +879,7 @@ def cli(
|
|
870
879
|
gen_slots=slots,
|
871
880
|
template_dir=template_dir,
|
872
881
|
black=black,
|
882
|
+
metadata_mode=meta,
|
873
883
|
**args,
|
874
884
|
)
|
875
885
|
print(gen.serialize())
|
@@ -322,6 +322,11 @@ class PydanticClass(TemplateModel):
|
|
322
322
|
def validators(self) -> Optional[Dict[str, PydanticValidator]]:
|
323
323
|
return self._validators()
|
324
324
|
|
325
|
+
@computed_field
|
326
|
+
def slots(self) -> Optional[Dict[str, PydanticAttribute]]:
|
327
|
+
"""alias of attributes"""
|
328
|
+
return self.attributes
|
329
|
+
|
325
330
|
else:
|
326
331
|
validators: Optional[Dict[str, PydanticValidator]]
|
327
332
|
|
@@ -575,7 +580,7 @@ class PydanticModule(TemplateModel):
|
|
575
580
|
version: Optional[str] = None
|
576
581
|
base_model: PydanticBaseModel = PydanticBaseModel()
|
577
582
|
injected_classes: Optional[List[str]] = None
|
578
|
-
|
583
|
+
python_imports: List[Union[Import, ConditionalImport]] = Field(default_factory=list)
|
579
584
|
enums: Dict[str, PydanticEnum] = Field(default_factory=dict)
|
580
585
|
classes: Dict[str, PydanticClass] = Field(default_factory=dict)
|
581
586
|
meta: Optional[Dict[str, Any]] = None
|
@@ -28,24 +28,24 @@ linkml/generators/javagen/java_record_template.jinja2,sha256=OQZffLSy_xR3FIhQMlt
|
|
28
28
|
linkml/generators/javagen.py,sha256=KxwupMztyCRHcSsbtTnOovuj1WamsAny0mxbYWvTiDs,5324
|
29
29
|
linkml/generators/jsonldcontextgen.py,sha256=y_AE1JF0QS75VDfOAquToClrWGAWb_ltsGN5r-Q20F8,8638
|
30
30
|
linkml/generators/jsonldgen.py,sha256=FamA0pbbc9U3kEslsjvgJoJXjQ80VzoPbHmClVGPvKE,7757
|
31
|
-
linkml/generators/jsonschemagen.py,sha256=
|
31
|
+
linkml/generators/jsonschemagen.py,sha256=sQXlaT_UOiJfbRoxH-hFY4nM0ELdjRlCFnS8HqVzqb8,28263
|
32
32
|
linkml/generators/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
33
|
linkml/generators/linkmlgen.py,sha256=1_Kt_7rD42WvCTjq0yaq1Of7jEDZR_uusyzAT-qWMHk,3471
|
34
34
|
linkml/generators/markdowngen.py,sha256=mwydWkrF-WzsTiKwJqqe9NUya5VaTj7ywKqodP85A44,34449
|
35
35
|
linkml/generators/namespacegen.py,sha256=vVcIyM0zlKd7XRvtdzwTwHjG4Pg49801gy4FUmjJlqQ,6450
|
36
36
|
linkml/generators/oocodegen.py,sha256=r73QI08ajbTZTobc9OIG6BMWZft3zdu76vKVR33pyYg,7774
|
37
37
|
linkml/generators/owlgen.py,sha256=NHIcL1d79WoeqfiZRj6kRk5aTXcQ6JDNXV_VAtH6Vt0,57554
|
38
|
-
linkml/generators/plantumlgen.py,sha256=
|
38
|
+
linkml/generators/plantumlgen.py,sha256=JgAox2o_HQgXR4ZxdHwdRUzcHSbpsAdv15Qsq1vnEZs,15463
|
39
39
|
linkml/generators/prefixmapgen.py,sha256=w8gMCFOI0DmZsNvo9IkbhOqVWqqWYEN6SXnAP3BgFSk,4240
|
40
40
|
linkml/generators/projectgen.py,sha256=OuT_AneoZFNMCn50GllfZafadUHt50u61JcftM2eed4,9750
|
41
41
|
linkml/generators/protogen.py,sha256=i4sEhNdAiFFP12fwfRdype1MX8yU-E5fF7XzkcpBCd0,2512
|
42
|
-
linkml/generators/pydanticgen/__init__.py,sha256
|
42
|
+
linkml/generators/pydanticgen/__init__.py,sha256=-972x-uV0atgveW_n5qvG1WelKANvsk9ZseZOIH_tNI,663
|
43
43
|
linkml/generators/pydanticgen/array.py,sha256=EYqAkT2_wE82kZ-niUWAC5U3V8EvjjyfSH7tz5GYKWo,19461
|
44
44
|
linkml/generators/pydanticgen/black.py,sha256=BaJ7b-kMUbIN_cKRT3yCaMEbFwxzj1_U7w4fKQnkL44,723
|
45
45
|
linkml/generators/pydanticgen/build.py,sha256=Ia8qy4C16b-KqO_fw4tGQW_Eo4grCVyX7RsuJ3uRTtk,2681
|
46
|
-
linkml/generators/pydanticgen/includes.py,sha256=
|
47
|
-
linkml/generators/pydanticgen/pydanticgen.py,sha256=
|
48
|
-
linkml/generators/pydanticgen/template.py,sha256=
|
46
|
+
linkml/generators/pydanticgen/includes.py,sha256=0CZi8vs6Z2eVvMOWhbTphCYoI3X8E9-8LgSaCBeiuCY,1174
|
47
|
+
linkml/generators/pydanticgen/pydanticgen.py,sha256=kaUBENnVEGpFs3gGK8kQbR2ZoZ1eg9Jiz0yNtXajbEw,34900
|
48
|
+
linkml/generators/pydanticgen/template.py,sha256=gffWyzJNmjw2Kf1UszRp97qGrnkAGd4UnLimU2nEsEA,21154
|
49
49
|
linkml/generators/pydanticgen/templates/attribute.py.jinja,sha256=S_T-M7n_eeM3LW5gQUuTPH1-Oc1CEtL7Bve7qAFouYQ,688
|
50
50
|
linkml/generators/pydanticgen/templates/base_model.py.jinja,sha256=48y64MnC9rjNSV-nKLMeDuHN4gm15UsInhnKxh65zoM,834
|
51
51
|
linkml/generators/pydanticgen/templates/class.py.jinja,sha256=V_lyvFcZ9QhlKZi2bL5iff8RjHir2SQTTypOzQMOfmk,744
|
@@ -53,7 +53,7 @@ linkml/generators/pydanticgen/templates/conditional_import.py.jinja,sha256=Yhekn
|
|
53
53
|
linkml/generators/pydanticgen/templates/enum.py.jinja,sha256=572XFQyEMZfL-G_Cj68T-NI_mUnDoFOAVJOGIKu2Hb8,338
|
54
54
|
linkml/generators/pydanticgen/templates/footer.py.jinja,sha256=WuWGJjkWDQcEPL2bGk5fdGuhO0gQRUJzpo4CQHHxQNQ,385
|
55
55
|
linkml/generators/pydanticgen/templates/imports.py.jinja,sha256=d1XFna2eOpkH8cgJML3vXwqGcocczvOcrbg6jjd4kP0,945
|
56
|
-
linkml/generators/pydanticgen/templates/module.py.jinja,sha256=
|
56
|
+
linkml/generators/pydanticgen/templates/module.py.jinja,sha256=gYauXrq8ML3ieaN_DFGB9yj9VfZV2yHG5LRQUzWy4VA,622
|
57
57
|
linkml/generators/pydanticgen/templates/validator.py.jinja,sha256=Yo4dubQal-HwEoJKztQkLYM5qCz1I8na2oaDlXuEpwU,532
|
58
58
|
linkml/generators/pythongen.py,sha256=CiLmc964siGeJWZC_bOffsqrSnJ5qzn7Eu961C47xgo,52850
|
59
59
|
linkml/generators/rdfgen.py,sha256=eQi3XXjWk6xliTLncQ4G0VYzGCJwCU_FFG-O7tA8DSA,2959
|
@@ -143,8 +143,8 @@ linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
143
143
|
linkml/workspaces/datamodel/workspaces.py,sha256=4HdkqweGNfMPqnB1_Onc9DcTfkhoagTRcqruh08nRoI,14905
|
144
144
|
linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
|
145
145
|
linkml/workspaces/example_runner.py,sha256=hDk2RGxRE5-WYNriWknugtbm3Mhn8bFcAcXGMlkYxVk,11705
|
146
|
-
linkml-1.8.
|
147
|
-
linkml-1.8.
|
148
|
-
linkml-1.8.
|
149
|
-
linkml-1.8.
|
150
|
-
linkml-1.8.
|
146
|
+
linkml-1.8.1.dist-info/entry_points.txt,sha256=7haDkIbyC7ZLhm5z-e3BhrLJpY2xoW1yuD8Y7QPNtVg,2093
|
147
|
+
linkml-1.8.1.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
|
148
|
+
linkml-1.8.1.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
149
|
+
linkml-1.8.1.dist-info/METADATA,sha256=-Nk6qRvku2ysnCvxuObK_ILTulyQzPAKyvbbUbzSSfk,3724
|
150
|
+
linkml-1.8.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|