linkml 1.7.10__py3-none-any.whl → 1.8.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/docgen/class.md.jinja2 +0 -14
- linkml/generators/docgen/common_metadata.md.jinja2 +14 -1
- linkml/generators/erdiagramgen.py +37 -3
- linkml/generators/golanggen.py +1 -6
- linkml/generators/plantumlgen.py +1 -5
- linkml/generators/pydanticgen/array.py +1 -12
- linkml/generators/pydanticgen/black.py +1 -3
- linkml/generators/pydanticgen/includes.py +46 -0
- linkml/generators/pydanticgen/pydanticgen.py +109 -16
- linkml/generators/pydanticgen/template.py +26 -0
- linkml/generators/pydanticgen/templates/attribute.py.jinja +7 -1
- linkml/generators/pydanticgen/templates/class.py.jinja +4 -0
- linkml/generators/pydanticgen/templates/module.py.jinja +12 -5
- linkml/generators/pythongen.py +1 -8
- linkml/generators/shaclgen.py +95 -3
- linkml/generators/sqlalchemygen.py +2 -10
- linkml/linter/rules.py +1 -6
- linkml/transformers/logical_model_transformer.py +6 -2
- linkml/utils/schemaloader.py +27 -0
- linkml/utils/schemasynopsis.py +1 -9
- linkml/validator/__init__.py +1 -3
- linkml/validator/plugins/__init__.py +1 -3
- {linkml-1.7.10.dist-info → linkml-1.8.0.dist-info}/METADATA +2 -2
- {linkml-1.7.10.dist-info → linkml-1.8.0.dist-info}/RECORD +27 -26
- {linkml-1.7.10.dist-info → linkml-1.8.0.dist-info}/LICENSE +0 -0
- {linkml-1.7.10.dist-info → linkml-1.8.0.dist-info}/WHEEL +0 -0
- {linkml-1.7.10.dist-info → linkml-1.8.0.dist-info}/entry_points.txt +0 -0
@@ -99,20 +99,6 @@ URI: {{ gen.uri_link(element) }}
|
|
99
99
|
|
100
100
|
{% include "common_metadata.md.jinja2" %}
|
101
101
|
|
102
|
-
|
103
|
-
{% if schemaview.get_mappings(element.name).items() -%}
|
104
|
-
## Mappings
|
105
|
-
|
106
|
-
| Mapping Type | Mapped Value |
|
107
|
-
| --- | --- |
|
108
|
-
{% for m, mt in schemaview.get_mappings(element.name).items() -%}
|
109
|
-
{% if mt|length > 0 -%}
|
110
|
-
| {{ m }} | {{ mt|join(', ') }} |
|
111
|
-
{% endif -%}
|
112
|
-
{% endfor %}
|
113
|
-
|
114
|
-
{% endif -%}
|
115
|
-
|
116
102
|
{% if gen.example_object_blobs(element.name) -%}
|
117
103
|
## Examples
|
118
104
|
{% for name, blob in gen.example_object_blobs(element.name) -%}
|
@@ -75,4 +75,17 @@ Instances of this class *should* have identifiers with one of the following pref
|
|
75
75
|
{% if element.imported_from %}
|
76
76
|
* imported from: {{ element.imported_from }}
|
77
77
|
{% endif %}
|
78
|
-
{% endif %}
|
78
|
+
{% endif %}
|
79
|
+
|
80
|
+
{% if schemaview.get_mappings(element.name).items() -%}
|
81
|
+
## Mappings
|
82
|
+
|
83
|
+
| Mapping Type | Mapped Value |
|
84
|
+
| --- | --- |
|
85
|
+
{% for m, mt in schemaview.get_mappings(element.name).items() -%}
|
86
|
+
{% if mt|length > 0 -%}
|
87
|
+
| {{ m }} | {{ mt|join(', ') }} |
|
88
|
+
{% endif -%}
|
89
|
+
{% endfor %}
|
90
|
+
|
91
|
+
{% endif -%}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from enum import Enum
|
4
|
-
from typing import List, Optional, Union
|
4
|
+
from typing import List, Optional, Set, Union
|
5
5
|
|
6
6
|
import click
|
7
7
|
import pydantic
|
@@ -163,6 +163,7 @@ class ERDiagramGenerator(Generator):
|
|
163
163
|
class_names: List[Union[str, ClassDefinitionName]],
|
164
164
|
follow_references=False,
|
165
165
|
max_hops: int = None,
|
166
|
+
include_upstream: bool = False,
|
166
167
|
) -> MERMAID_SERIALIZATION:
|
167
168
|
"""
|
168
169
|
Serialize a list of classes as an ER Diagram.
|
@@ -195,6 +196,15 @@ class ERDiagramGenerator(Generator):
|
|
195
196
|
if follow_references or sv.is_inlined(slot):
|
196
197
|
if rng not in visited:
|
197
198
|
stack.append((rng, depth + 1))
|
199
|
+
|
200
|
+
# Now Add upstream classes if needed
|
201
|
+
if include_upstream:
|
202
|
+
for sn in sv.all_slots():
|
203
|
+
slot = sv.schema.slots.get(sn)
|
204
|
+
if slot and slot.range in set(class_names):
|
205
|
+
for cl in sv.all_classes():
|
206
|
+
if slot.name in sv.get_class(cl).slots and cl not in visited:
|
207
|
+
self.add_upstream_class(cl, set(class_names), diagram)
|
198
208
|
return self.serialize_diagram(diagram)
|
199
209
|
|
200
210
|
def serialize_diagram(self, diagram: ERDiagram) -> str:
|
@@ -210,6 +220,15 @@ class ERDiagramGenerator(Generator):
|
|
210
220
|
else:
|
211
221
|
return er
|
212
222
|
|
223
|
+
def add_upstream_class(self, class_name: ClassDefinitionName, targets: Set[str], diagram: ERDiagram) -> None:
|
224
|
+
sv = self.schemaview
|
225
|
+
cls = sv.get_class(class_name)
|
226
|
+
entity = Entity(name=camelcase(cls.name))
|
227
|
+
diagram.entities.append(entity)
|
228
|
+
for slot in sv.class_induced_slots(class_name):
|
229
|
+
if slot.range in targets:
|
230
|
+
self.add_relationship(entity, slot, diagram)
|
231
|
+
|
213
232
|
def add_class(self, class_name: ClassDefinitionName, diagram: ERDiagram) -> None:
|
214
233
|
"""
|
215
234
|
Add a class to the ER Diagram.
|
@@ -291,9 +310,17 @@ class ERDiagramGenerator(Generator):
|
|
291
310
|
)
|
292
311
|
@click.option("--max-hops", default=None, type=click.INT, help="Maximum number of hops")
|
293
312
|
@click.option("--classes", "-c", multiple=True, help="List of classes to serialize")
|
313
|
+
@click.option("--include-upstream", is_flag=True, help="Include upstream classes")
|
294
314
|
@click.version_option(__version__, "-V", "--version")
|
295
315
|
@click.command()
|
296
|
-
def cli(
|
316
|
+
def cli(
|
317
|
+
yamlfile,
|
318
|
+
classes: List[str],
|
319
|
+
max_hops: Optional[int],
|
320
|
+
follow_references: bool,
|
321
|
+
include_upstream: bool = False,
|
322
|
+
**args,
|
323
|
+
):
|
297
324
|
"""Generate a mermaid ER diagram from a schema.
|
298
325
|
|
299
326
|
By default, all entities traversable from the tree_root are included. If no tree_root is
|
@@ -306,7 +333,14 @@ def cli(yamlfile, classes: List[str], max_hops: Optional[int], follow_references
|
|
306
333
|
**args,
|
307
334
|
)
|
308
335
|
if classes:
|
309
|
-
print(
|
336
|
+
print(
|
337
|
+
gen.serialize_classes(
|
338
|
+
classes,
|
339
|
+
follow_references=follow_references,
|
340
|
+
max_hops=max_hops,
|
341
|
+
include_upstream=include_upstream,
|
342
|
+
)
|
343
|
+
)
|
310
344
|
else:
|
311
345
|
print(gen.serialize())
|
312
346
|
|
linkml/generators/golanggen.py
CHANGED
@@ -5,12 +5,7 @@ from typing import List, Optional
|
|
5
5
|
|
6
6
|
import click
|
7
7
|
from jinja2 import Template
|
8
|
-
from linkml_runtime.linkml_model.meta import
|
9
|
-
ClassDefinition,
|
10
|
-
ClassDefinitionName,
|
11
|
-
Element,
|
12
|
-
SlotDefinition,
|
13
|
-
)
|
8
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionName, Element, SlotDefinition
|
14
9
|
from linkml_runtime.utils.formatutils import camelcase, underscore
|
15
10
|
|
16
11
|
from linkml._version import __version__
|
linkml/generators/plantumlgen.py
CHANGED
@@ -12,11 +12,7 @@ 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
|
16
|
-
ClassDefinition,
|
17
|
-
ClassDefinitionName,
|
18
|
-
SlotDefinition,
|
19
|
-
)
|
15
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionName, SlotDefinition
|
20
16
|
from linkml_runtime.utils.formatutils import camelcase, underscore
|
21
17
|
|
22
18
|
from linkml import REQUESTS_TIMEOUT
|
@@ -1,18 +1,7 @@
|
|
1
1
|
import sys
|
2
2
|
from abc import ABC, abstractmethod
|
3
3
|
from enum import Enum
|
4
|
-
from typing import
|
5
|
-
Any,
|
6
|
-
ClassVar,
|
7
|
-
Generic,
|
8
|
-
Iterable,
|
9
|
-
List,
|
10
|
-
Optional,
|
11
|
-
Type,
|
12
|
-
TypeVar,
|
13
|
-
Union,
|
14
|
-
get_args,
|
15
|
-
)
|
4
|
+
from typing import Any, ClassVar, Generic, Iterable, List, Optional, Type, TypeVar, Union, get_args
|
16
5
|
|
17
6
|
from linkml_runtime.linkml_model import Element
|
18
7
|
from linkml_runtime.linkml_model.meta import ArrayExpression, DimensionExpression
|
@@ -16,9 +16,7 @@ except ImportError:
|
|
16
16
|
|
17
17
|
|
18
18
|
def _default_mode() -> "Mode":
|
19
|
-
return Mode(
|
20
|
-
target_versions={TargetVersion.PY311},
|
21
|
-
)
|
19
|
+
return Mode(target_versions={TargetVersion.PY311}, line_length=120)
|
22
20
|
|
23
21
|
|
24
22
|
def format_black(code: str, mode: Optional["Mode"] = None) -> str:
|
@@ -0,0 +1,46 @@
|
|
1
|
+
"""
|
2
|
+
Classes to inject in generated pydantic models
|
3
|
+
"""
|
4
|
+
|
5
|
+
from pydantic.version import VERSION
|
6
|
+
|
7
|
+
PYDANTIC_VERSION = int(VERSION[0])
|
8
|
+
|
9
|
+
|
10
|
+
LinkMLMeta_v1 = """
|
11
|
+
class LinkMLMeta(BaseModel):
|
12
|
+
__root__: Dict[str, Any] = {}
|
13
|
+
|
14
|
+
def __getattr__(self, key:str):
|
15
|
+
return getattr(self.__root__, key)
|
16
|
+
|
17
|
+
def __getitem__(self, key:str):
|
18
|
+
return self.__root__[key]
|
19
|
+
|
20
|
+
def __setitem__(self, key:str, value):
|
21
|
+
self.__root__[key] = value
|
22
|
+
|
23
|
+
class Config:
|
24
|
+
allow_mutation = False
|
25
|
+
"""
|
26
|
+
|
27
|
+
LinkMLMeta_v2 = """
|
28
|
+
class LinkMLMeta(RootModel):
|
29
|
+
root: Dict[str, Any] = {}
|
30
|
+
model_config = ConfigDict(frozen=True)
|
31
|
+
|
32
|
+
def __getattr__(self, key:str):
|
33
|
+
return getattr(self.root, key)
|
34
|
+
|
35
|
+
def __getitem__(self, key:str):
|
36
|
+
return self.root[key]
|
37
|
+
|
38
|
+
def __setitem__(self, key:str, value):
|
39
|
+
self.root[key] = value
|
40
|
+
|
41
|
+
"""
|
42
|
+
|
43
|
+
# if PYDANTIC_VERSION >= 2:
|
44
|
+
# LinkMLMeta = eval(LinkMLMeta_v2)
|
45
|
+
# else:
|
46
|
+
# LinkMLMeta = eval(LinkMLMeta_v1)
|
@@ -3,19 +3,12 @@ import logging
|
|
3
3
|
import os
|
4
4
|
import textwrap
|
5
5
|
from collections import defaultdict
|
6
|
-
from copy import deepcopy
|
6
|
+
from copy import copy, deepcopy
|
7
7
|
from dataclasses import dataclass, field
|
8
|
+
from enum import Enum
|
8
9
|
from pathlib import Path
|
9
10
|
from types import ModuleType
|
10
|
-
from typing import
|
11
|
-
Dict,
|
12
|
-
List,
|
13
|
-
Literal,
|
14
|
-
Optional,
|
15
|
-
Set,
|
16
|
-
Type,
|
17
|
-
Union,
|
18
|
-
)
|
11
|
+
from typing import Dict, List, Literal, Optional, Set, Type, TypeVar, Union, overload
|
19
12
|
|
20
13
|
import click
|
21
14
|
from jinja2 import ChoiceLoader, Environment, FileSystemLoader
|
@@ -27,16 +20,14 @@ from linkml_runtime.linkml_model.meta import (
|
|
27
20
|
TypeDefinition,
|
28
21
|
)
|
29
22
|
from linkml_runtime.utils.compile_python import compile_python
|
30
|
-
from linkml_runtime.utils.formatutils import camelcase, underscore
|
23
|
+
from linkml_runtime.utils.formatutils import camelcase, remove_empty_items, underscore
|
31
24
|
from linkml_runtime.utils.schemaview import SchemaView
|
32
25
|
from pydantic.version import VERSION as PYDANTIC_VERSION
|
33
26
|
|
34
27
|
from linkml._version import __version__
|
35
|
-
from linkml.generators.common.type_designators import
|
36
|
-
get_accepted_type_designator_values,
|
37
|
-
get_type_designator_value,
|
38
|
-
)
|
28
|
+
from linkml.generators.common.type_designators import get_accepted_type_designator_values, get_type_designator_value
|
39
29
|
from linkml.generators.oocodegen import OOCodeGenerator
|
30
|
+
from linkml.generators.pydanticgen import includes
|
40
31
|
from linkml.generators.pydanticgen.array import ArrayRangeGenerator, ArrayRepresentation
|
41
32
|
from linkml.generators.pydanticgen.build import SlotResult
|
42
33
|
from linkml.generators.pydanticgen.template import (
|
@@ -85,6 +76,7 @@ DEFAULT_IMPORTS = (
|
|
85
76
|
module="typing",
|
86
77
|
objects=[
|
87
78
|
ObjectImport(name="Any"),
|
79
|
+
ObjectImport(name="ClassVar"),
|
88
80
|
ObjectImport(name="List"),
|
89
81
|
ObjectImport(name="Literal"),
|
90
82
|
ObjectImport(name="Dict"),
|
@@ -100,6 +92,7 @@ DEFAULT_IMPORTS = (
|
|
100
92
|
ObjectImport(name="BaseModel"),
|
101
93
|
ObjectImport(name="ConfigDict"),
|
102
94
|
ObjectImport(name="Field"),
|
95
|
+
ObjectImport(name="RootModel"),
|
103
96
|
ObjectImport(name="field_validator"),
|
104
97
|
],
|
105
98
|
alternative=Import(
|
@@ -109,6 +102,33 @@ DEFAULT_IMPORTS = (
|
|
109
102
|
)
|
110
103
|
)
|
111
104
|
|
105
|
+
DEFAULT_INJECTS = {1: [includes.LinkMLMeta_v1], 2: [includes.LinkMLMeta_v2]}
|
106
|
+
|
107
|
+
|
108
|
+
class MetadataMode(str, Enum):
|
109
|
+
FULL = "full"
|
110
|
+
"""
|
111
|
+
all metadata from the source schema will be included, even if it is represented by the template classes,
|
112
|
+
and even if it is represented by some child class (eg. "classes" will be included with schema metadata
|
113
|
+
"""
|
114
|
+
EXCEPT_CHILDREN = "except_children"
|
115
|
+
"""
|
116
|
+
all metadata from the source schema will be included, even if it is represented by the template classes,
|
117
|
+
except if it is represented by some child template class (eg. "classes" will be excluded from schema metadata)
|
118
|
+
"""
|
119
|
+
AUTO = "auto"
|
120
|
+
"""
|
121
|
+
Only the metadata that isn't represented by the template classes or excluded with ``meta_exclude`` will be included
|
122
|
+
"""
|
123
|
+
NONE = None
|
124
|
+
"""
|
125
|
+
No metadata will be included.
|
126
|
+
"""
|
127
|
+
|
128
|
+
|
129
|
+
DefinitionType = TypeVar("DefinitionType", bound=Union[SchemaDefinition, ClassDefinition, SlotDefinition])
|
130
|
+
TemplateType = TypeVar("TemplateType", bound=Union[PydanticModule, PydanticClass, PydanticAttribute])
|
131
|
+
|
112
132
|
|
113
133
|
@dataclass
|
114
134
|
class PydanticGenerator(OOCodeGenerator):
|
@@ -212,6 +232,12 @@ class PydanticGenerator(OOCodeGenerator):
|
|
212
232
|
from typing_extensions import Literal
|
213
233
|
|
214
234
|
"""
|
235
|
+
metadata_mode: Union[MetadataMode, str, None] = MetadataMode.AUTO
|
236
|
+
"""
|
237
|
+
How to include schema metadata in generated pydantic models.
|
238
|
+
|
239
|
+
See :class:`.MetadataMode` for mode documentation
|
240
|
+
"""
|
215
241
|
|
216
242
|
# ObjectVars (identical to pythongen)
|
217
243
|
gen_classvars: bool = True
|
@@ -530,6 +556,56 @@ class PydanticGenerator(OOCodeGenerator):
|
|
530
556
|
|
531
557
|
return array_reps
|
532
558
|
|
559
|
+
@overload
|
560
|
+
def include_metadata(self, model: PydanticModule, source: SchemaDefinition) -> PydanticModule: ...
|
561
|
+
|
562
|
+
@overload
|
563
|
+
def include_metadata(self, model: PydanticClass, source: ClassDefinition) -> PydanticClass: ...
|
564
|
+
|
565
|
+
@overload
|
566
|
+
def include_metadata(self, model: PydanticAttribute, source: SlotDefinition) -> PydanticAttribute: ...
|
567
|
+
|
568
|
+
def include_metadata(self, model: TemplateType, source: DefinitionType) -> TemplateType:
|
569
|
+
"""
|
570
|
+
Include metadata from the source schema that is otherwise not represented in the pydantic template models.
|
571
|
+
|
572
|
+
Metadata inclusion mode is dependent on :attr:`.metadata_mode` - see:
|
573
|
+
|
574
|
+
- :class:`.MetadataMode`
|
575
|
+
- :meth:`.TemplateModel.exclude_from_meta`
|
576
|
+
|
577
|
+
"""
|
578
|
+
if self.metadata_mode is None or self.metadata_mode == MetadataMode.NONE:
|
579
|
+
return model
|
580
|
+
elif self.metadata_mode in (MetadataMode.AUTO, MetadataMode.AUTO.value):
|
581
|
+
meta = {k: v for k, v in remove_empty_items(source).items() if k not in model.exclude_from_meta()}
|
582
|
+
elif self.metadata_mode in (MetadataMode.EXCEPT_CHILDREN, MetadataMode.EXCEPT_CHILDREN.value):
|
583
|
+
meta = {}
|
584
|
+
for k, v in remove_empty_items(source).items():
|
585
|
+
if not hasattr(model, k):
|
586
|
+
meta[k] = v
|
587
|
+
elif isinstance(getattr(model, k), list) and not any(
|
588
|
+
[isinstance(item, TemplateModel) for item in getattr(model, k)]
|
589
|
+
):
|
590
|
+
meta[k] = v
|
591
|
+
elif isinstance(getattr(model, k), dict) and not any(
|
592
|
+
[isinstance(item, TemplateModel) for item in getattr(model, k).values()]
|
593
|
+
):
|
594
|
+
meta[k] = v
|
595
|
+
elif not isinstance(getattr(model, k), TemplateModel):
|
596
|
+
meta[k] = v
|
597
|
+
|
598
|
+
elif self.metadata_mode in (MetadataMode.FULL, MetadataMode.FULL.value):
|
599
|
+
meta = remove_empty_items(source)
|
600
|
+
else:
|
601
|
+
raise ValueError(
|
602
|
+
f"Unknown metadata mode '{self.metadata_mode}', needs to be one of "
|
603
|
+
f"{[mode.value for mode in MetadataMode]}"
|
604
|
+
)
|
605
|
+
|
606
|
+
model.meta = meta
|
607
|
+
return model
|
608
|
+
|
533
609
|
def render(self) -> PydanticModule:
|
534
610
|
sv: SchemaView
|
535
611
|
sv = self.schemaview
|
@@ -540,7 +616,7 @@ class PydanticGenerator(OOCodeGenerator):
|
|
540
616
|
description=schema.description.replace('"', '\\"') if schema.description else None,
|
541
617
|
)
|
542
618
|
enums = self.generate_enums(sv.all_enums())
|
543
|
-
injected_classes = []
|
619
|
+
injected_classes = copy(DEFAULT_INJECTS[self.pydantic_version])
|
544
620
|
if self.injected_classes is not None:
|
545
621
|
injected_classes += self.injected_classes
|
546
622
|
|
@@ -665,15 +741,22 @@ class PydanticGenerator(OOCodeGenerator):
|
|
665
741
|
predef_slot = str(predef_slot)
|
666
742
|
new_fields["predefined"] = predef_slot
|
667
743
|
new_fields["name"] = attr_name
|
744
|
+
|
668
745
|
attrs[attr_name] = PydanticAttribute(**new_fields, pydantic_ver=self.pydantic_version)
|
746
|
+
attrs[attr_name] = self.include_metadata(attrs[attr_name], src_attr)
|
669
747
|
|
670
748
|
new_class = PydanticClass(
|
671
749
|
name=k, attributes=attrs, description=c.description, pydantic_ver=self.pydantic_version
|
672
750
|
)
|
751
|
+
new_class = self.include_metadata(new_class, c)
|
673
752
|
if k in bases:
|
674
753
|
new_class.bases = bases[k]
|
675
754
|
classes[k] = new_class
|
676
755
|
|
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
|
+
|
677
760
|
module = PydanticModule(
|
678
761
|
pydantic_ver=self.pydantic_version,
|
679
762
|
metamodel_version=self.schema.metamodel_version,
|
@@ -683,7 +766,9 @@ class PydanticGenerator(OOCodeGenerator):
|
|
683
766
|
injected_classes=injected_classes,
|
684
767
|
enums=enums,
|
685
768
|
classes=classes,
|
769
|
+
meta=schema_meta,
|
686
770
|
)
|
771
|
+
module = self.include_metadata(module, pyschema)
|
687
772
|
return module
|
688
773
|
|
689
774
|
def serialize(self) -> str:
|
@@ -739,6 +824,12 @@ Available templates to override:
|
|
739
824
|
default="forbid",
|
740
825
|
help="How to handle extra fields in BaseModel.",
|
741
826
|
)
|
827
|
+
@click.option(
|
828
|
+
"--black",
|
829
|
+
is_flag=True,
|
830
|
+
default=False,
|
831
|
+
help="Format generated models with black (must be present in the environment)",
|
832
|
+
)
|
742
833
|
@click.version_option(__version__, "-V", "--version")
|
743
834
|
@click.command()
|
744
835
|
def cli(
|
@@ -752,6 +843,7 @@ def cli(
|
|
752
843
|
array_representations=list("list"),
|
753
844
|
pydantic_version=int(PYDANTIC_VERSION[0]),
|
754
845
|
extra_fields: Literal["allow", "forbid", "ignore"] = "forbid",
|
846
|
+
black: bool = False,
|
755
847
|
**args,
|
756
848
|
):
|
757
849
|
"""Generate pydantic classes to represent a LinkML model"""
|
@@ -777,6 +869,7 @@ def cli(
|
|
777
869
|
gen_classvars=classvars,
|
778
870
|
gen_slots=slots,
|
779
871
|
template_dir=template_dir,
|
872
|
+
black=black,
|
780
873
|
**args,
|
781
874
|
)
|
782
875
|
print(gen.serialize())
|
@@ -60,6 +60,7 @@ class TemplateModel(BaseModel):
|
|
60
60
|
)
|
61
61
|
|
62
62
|
pydantic_ver: int = int(PYDANTIC_VERSION[0])
|
63
|
+
meta_exclude: ClassVar[List[str]] = None
|
63
64
|
|
64
65
|
def render(self, environment: Optional[Environment] = None, black: bool = False) -> str:
|
65
66
|
"""
|
@@ -132,6 +133,16 @@ class TemplateModel(BaseModel):
|
|
132
133
|
return self.json(**kwargs)
|
133
134
|
return self.dict(**kwargs)
|
134
135
|
|
136
|
+
@classmethod
|
137
|
+
def exclude_from_meta(cls: "TemplateModel") -> List[str]:
|
138
|
+
"""
|
139
|
+
Attributes in the source definition to exclude from linkml_meta
|
140
|
+
"""
|
141
|
+
ret = [*cls.model_fields.keys()]
|
142
|
+
if cls.meta_exclude is not None:
|
143
|
+
ret = ret + cls.meta_exclude
|
144
|
+
return ret
|
145
|
+
|
135
146
|
|
136
147
|
def _render(
|
137
148
|
item: Union[TemplateModel, Any, List[Union[Any, TemplateModel]], Dict[str, Union[Any, TemplateModel]]],
|
@@ -213,6 +224,7 @@ class PydanticAttribute(TemplateModel):
|
|
213
224
|
"""
|
214
225
|
|
215
226
|
template: ClassVar[str] = "attribute.py.jinja"
|
227
|
+
meta_exclude: ClassVar[List[str]] = ["from_schema", "owner", "range", "multivalued", "inlined", "inlined_as_list"]
|
216
228
|
|
217
229
|
name: str
|
218
230
|
required: bool = False
|
@@ -237,6 +249,10 @@ class PydanticAttribute(TemplateModel):
|
|
237
249
|
minimum_value: Optional[Union[int, float]] = None
|
238
250
|
maximum_value: Optional[Union[int, float]] = None
|
239
251
|
pattern: Optional[str] = None
|
252
|
+
meta: Optional[Dict[str, Any]] = None
|
253
|
+
"""
|
254
|
+
Metadata for the slot to be included in a Field annotation
|
255
|
+
"""
|
240
256
|
|
241
257
|
if int(PYDANTIC_VERSION[0]) >= 2:
|
242
258
|
|
@@ -283,11 +299,16 @@ class PydanticClass(TemplateModel):
|
|
283
299
|
"""
|
284
300
|
|
285
301
|
template: ClassVar[str] = "class.py.jinja"
|
302
|
+
meta_exclude: ClassVar[List[str]] = ["slots", "is_a"]
|
286
303
|
|
287
304
|
name: str
|
288
305
|
bases: Union[List[str], str] = PydanticBaseModel.default_name
|
289
306
|
description: Optional[str] = None
|
290
307
|
attributes: Optional[Dict[str, PydanticAttribute]] = None
|
308
|
+
meta: Optional[Dict[str, Any]] = None
|
309
|
+
"""
|
310
|
+
Metadata for the class to be included in a linkml_meta class attribute
|
311
|
+
"""
|
291
312
|
|
292
313
|
def _validators(self) -> Optional[Dict[str, PydanticValidator]]:
|
293
314
|
if self.attributes is None:
|
@@ -548,6 +569,7 @@ class PydanticModule(TemplateModel):
|
|
548
569
|
"""
|
549
570
|
|
550
571
|
template: ClassVar[str] = "module.py.jinja"
|
572
|
+
meta_exclude: ClassVar[str] = ["slots"]
|
551
573
|
|
552
574
|
metamodel_version: Optional[str] = None
|
553
575
|
version: Optional[str] = None
|
@@ -556,6 +578,10 @@ class PydanticModule(TemplateModel):
|
|
556
578
|
imports: List[Union[Import, ConditionalImport]] = Field(default_factory=list)
|
557
579
|
enums: Dict[str, PydanticEnum] = Field(default_factory=dict)
|
558
580
|
classes: Dict[str, PydanticClass] = Field(default_factory=dict)
|
581
|
+
meta: Optional[Dict[str, Any]] = None
|
582
|
+
"""
|
583
|
+
Metadata for the schema to be included in a linkml_meta module-level instance of LinkMLMeta
|
584
|
+
"""
|
559
585
|
|
560
586
|
if int(PYDANTIC_VERSION[0]) >= 2:
|
561
587
|
|
@@ -7,4 +7,10 @@
|
|
7
7
|
{%- if minimum_value != None %}, ge={{minimum_value}}{% endif -%}
|
8
8
|
{%- if maximum_value != None %}, le={{maximum_value}}{% endif -%}
|
9
9
|
{%- endif -%}
|
10
|
-
|
10
|
+
{%- if meta != None -%}
|
11
|
+
{%- if pydantic_ver == 1 -%}
|
12
|
+
, linkml_meta = {{ meta | pprint | indent(width=8) }}
|
13
|
+
{% else -%}
|
14
|
+
, json_schema_extra = { "linkml_meta": {{ meta | pprint | indent(width=8) }} }
|
15
|
+
{%- endif -%}
|
16
|
+
{%- endif -%})
|
@@ -4,6 +4,10 @@ class {{ name }}({% if bases is string %}{{ bases }}{% else %}{{ bases | join(',
|
|
4
4
|
{{ description | indent(width=4) }}
|
5
5
|
"""
|
6
6
|
{% endif -%}
|
7
|
+
{% if meta != None %}
|
8
|
+
linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({% if pydantic_ver == 1 %}__root__={% endif %}{{ meta | pprint | indent(width=8) }})
|
9
|
+
|
10
|
+
{% endif %}
|
7
11
|
{% if attributes or validators %}
|
8
12
|
{% if attributes %}
|
9
13
|
{% for attr in attributes.values() %}
|
@@ -7,18 +7,25 @@ version = "{{version if version else None}}"
|
|
7
7
|
|
8
8
|
|
9
9
|
{{ base_model }}
|
10
|
-
{% if enums %}
|
11
|
-
{% for e in enums.values() %}
|
12
10
|
|
13
|
-
{{ e }}
|
14
|
-
{% endfor %}
|
15
|
-
{% endif %}
|
16
11
|
{% if injected_classes %}
|
17
12
|
{% for c in injected_classes%}
|
18
13
|
|
19
14
|
{{ c }}
|
20
15
|
{% endfor %}
|
21
16
|
{% endif %}
|
17
|
+
{% if meta != None %}
|
18
|
+
linkml_meta = LinkMLMeta({% if pydantic_ver == 1 %}__root__={% endif %}{{ meta | pprint | indent(width=4) }} )
|
19
|
+
{% else %}
|
20
|
+
linkml_meta = None
|
21
|
+
{% endif %}
|
22
|
+
{% if enums %}
|
23
|
+
{% for e in enums.values() %}
|
24
|
+
|
25
|
+
{{ e }}
|
26
|
+
{% endfor %}
|
27
|
+
{% endif %}
|
28
|
+
|
22
29
|
{% for c in classes.values() %}
|
23
30
|
|
24
31
|
{{ c }}
|
linkml/generators/pythongen.py
CHANGED
@@ -23,14 +23,7 @@ from linkml_runtime.linkml_model.meta import (
|
|
23
23
|
TypeDefinition,
|
24
24
|
)
|
25
25
|
from linkml_runtime.utils.compile_python import compile_python
|
26
|
-
from linkml_runtime.utils.formatutils import
|
27
|
-
be,
|
28
|
-
camelcase,
|
29
|
-
sfx,
|
30
|
-
split_col,
|
31
|
-
underscore,
|
32
|
-
wrapped_annotation,
|
33
|
-
)
|
26
|
+
from linkml_runtime.utils.formatutils import be, camelcase, sfx, split_col, underscore, wrapped_annotation
|
34
27
|
from linkml_runtime.utils.metamodelcore import builtinnames
|
35
28
|
from rdflib import URIRef
|
36
29
|
|
linkml/generators/shaclgen.py
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import Callable
|
4
|
+
from typing import Callable, List
|
5
5
|
|
6
6
|
import click
|
7
|
+
from jsonasobj2 import JsonObj, as_dict
|
7
8
|
from linkml_runtime.linkml_model.meta import ElementName
|
8
9
|
from linkml_runtime.utils.formatutils import underscore
|
9
10
|
from linkml_runtime.utils.schemaview import SchemaView
|
11
|
+
from linkml_runtime.utils.yamlutils import TypedNode, extended_float, extended_int, extended_str
|
10
12
|
from rdflib import BNode, Graph, Literal, URIRef
|
11
13
|
from rdflib.collection import Collection
|
12
|
-
from rdflib.namespace import RDF, SH
|
14
|
+
from rdflib.namespace import RDF, SH, XSD
|
13
15
|
|
14
16
|
from linkml._version import __version__
|
15
17
|
from linkml.generators.shacl.ifabsent_processor import IfAbsentProcessor
|
@@ -24,6 +26,8 @@ class ShaclGenerator(Generator):
|
|
24
26
|
"""True means add 'sh:closed=true' to all shapes, except of mixin shapes and shapes, that have parents"""
|
25
27
|
suffix: str = None
|
26
28
|
"""parameterized suffix to be appended. No suffix per default."""
|
29
|
+
include_annotations: bool = False
|
30
|
+
"""True means include all class / slot / type annotations in generated Node or Property shapes"""
|
27
31
|
generatorname = os.path.basename(__file__)
|
28
32
|
generatorversion = "0.0.1"
|
29
33
|
valid_formats = ["ttl"]
|
@@ -83,6 +87,8 @@ class ShaclGenerator(Generator):
|
|
83
87
|
list_node = BNode()
|
84
88
|
Collection(g, list_node, [RDF.type])
|
85
89
|
shape_pv(SH.ignoredProperties, list_node)
|
90
|
+
if c.annotations and self.include_annotations:
|
91
|
+
self._add_annotations(shape_pv, c)
|
86
92
|
order = 0
|
87
93
|
for s in sv.class_induced_slots(c.name):
|
88
94
|
# fixed in linkml-runtime 1.1.3
|
@@ -116,6 +122,12 @@ class ShaclGenerator(Generator):
|
|
116
122
|
|
117
123
|
all_classes = sv.all_classes()
|
118
124
|
if s.any_of:
|
125
|
+
# It is not allowed to use any of and equals_string or equals_string_in in one
|
126
|
+
# slot definition, as both are mapped to sh:in in SHACL
|
127
|
+
if s.equals_string or s.equals_string_in:
|
128
|
+
error = "'equals_string'/'equals_string_in' and 'any_of' are mutually exclusive"
|
129
|
+
raise ValueError(f'{TypedNode.yaml_loc(s, suffix="")} {error}')
|
130
|
+
|
119
131
|
or_node = BNode()
|
120
132
|
prop_pv(SH["or"], or_node)
|
121
133
|
range_list = []
|
@@ -158,10 +170,17 @@ class ShaclGenerator(Generator):
|
|
158
170
|
add_simple_data_type(st_node_pv, r)
|
159
171
|
range_list.append(st_node)
|
160
172
|
Collection(g, or_node, range_list)
|
161
|
-
|
162
173
|
else:
|
163
174
|
prop_pv_literal(SH.hasValue, s.equals_number)
|
164
175
|
r = s.range
|
176
|
+
if s.equals_string or s.equals_string_in:
|
177
|
+
# Check if range is "string" as this is mandatory for "equals_string" and "equals_string_in"
|
178
|
+
if r != "string":
|
179
|
+
raise ValueError(
|
180
|
+
f"slot: \"{slot_uri}\" - 'equals_string' and 'equals_string_in'"
|
181
|
+
f" require range 'string' and not '{r}'"
|
182
|
+
)
|
183
|
+
|
165
184
|
if r in all_classes:
|
166
185
|
self._add_class(prop_pv, r)
|
167
186
|
if sv.get_identifier_slot(r) is not None:
|
@@ -176,6 +195,14 @@ class ShaclGenerator(Generator):
|
|
176
195
|
add_simple_data_type(prop_pv, r)
|
177
196
|
if s.pattern:
|
178
197
|
prop_pv(SH.pattern, Literal(s.pattern))
|
198
|
+
if s.annotations and self.include_annotations:
|
199
|
+
self._add_annotations(prop_pv, s)
|
200
|
+
if s.equals_string:
|
201
|
+
# Map equal_string and equal_string_in to sh:in
|
202
|
+
self._and_equals_string(g, prop_pv, [s.equals_string])
|
203
|
+
if s.equals_string_in:
|
204
|
+
# Map equal_string and equal_string_in to sh:in
|
205
|
+
self._and_equals_string(g, prop_pv, s.equals_string_in)
|
179
206
|
|
180
207
|
ifabsent_processor.process_slot(prop_pv, s, class_uri)
|
181
208
|
|
@@ -206,9 +233,68 @@ class ShaclGenerator(Generator):
|
|
206
233
|
rt = sv.get_type(r)
|
207
234
|
if rt.uri:
|
208
235
|
func(SH.datatype, URIRef(sv.get_uri(rt, expand=True)))
|
236
|
+
if rt.pattern:
|
237
|
+
func(SH.pattern, Literal(rt.pattern))
|
238
|
+
if rt.annotations and self.include_annotations:
|
239
|
+
self._add_annotations(func, rt)
|
209
240
|
else:
|
210
241
|
logging.error(f"No URI for type {rt.name}")
|
211
242
|
|
243
|
+
def _and_equals_string(self, g: Graph, func: Callable, values: List) -> None:
|
244
|
+
pv_node = BNode()
|
245
|
+
Collection(
|
246
|
+
g,
|
247
|
+
pv_node,
|
248
|
+
[Literal(v) for v in values],
|
249
|
+
)
|
250
|
+
func(SH["in"], pv_node)
|
251
|
+
|
252
|
+
def _add_annotations(self, func: Callable, item) -> None:
|
253
|
+
# TODO: migrate some of this logic to SchemaView
|
254
|
+
sv = self.schemaview
|
255
|
+
annotations = item.annotations
|
256
|
+
# item could be a class, slot or type
|
257
|
+
# annotation type could be dict (on types) or JsonObj (on slots)
|
258
|
+
if type(annotations) == JsonObj:
|
259
|
+
annotations = as_dict(annotations)
|
260
|
+
for a in annotations.values():
|
261
|
+
# If ':' is in the tag, treat it as a CURIE, otherwise string Literal
|
262
|
+
if ":" in a["tag"]:
|
263
|
+
N_predicate = URIRef(sv.expand_curie(a["tag"]))
|
264
|
+
else:
|
265
|
+
N_predicate = Literal(a["tag"], datatype=XSD.string)
|
266
|
+
# If the value is a string and ':' is in the value, treat it as a CURIE,
|
267
|
+
# otherwise treat as Literal with derived XSD datatype
|
268
|
+
if type(a["value"]) == extended_str and ":" in a["value"]:
|
269
|
+
N_object = URIRef(sv.expand_curie(a["value"]))
|
270
|
+
else:
|
271
|
+
N_object = Literal(a["value"], datatype=self._getXSDtype(a["value"]))
|
272
|
+
|
273
|
+
func(N_predicate, N_object)
|
274
|
+
|
275
|
+
def _getXSDtype(self, value):
|
276
|
+
value_type = type(value)
|
277
|
+
if value_type == bool:
|
278
|
+
return XSD.boolean
|
279
|
+
elif value_type == extended_str:
|
280
|
+
return XSD.string
|
281
|
+
elif value_type == extended_int:
|
282
|
+
return XSD.integer
|
283
|
+
elif value_type == extended_float:
|
284
|
+
# TODO: distinguish between xsd:decimal and xsd:double?
|
285
|
+
return XSD.decimal
|
286
|
+
else:
|
287
|
+
return None
|
288
|
+
|
289
|
+
def _and_equals_string(self, g: Graph, func: Callable, values: List) -> None:
|
290
|
+
pv_node = BNode()
|
291
|
+
Collection(
|
292
|
+
g,
|
293
|
+
pv_node,
|
294
|
+
[Literal(v) for v in values],
|
295
|
+
)
|
296
|
+
func(SH["in"], pv_node)
|
297
|
+
|
212
298
|
|
213
299
|
def add_simple_data_type(func: Callable, r: ElementName) -> None:
|
214
300
|
for datatype in list(ShaclDataType):
|
@@ -231,6 +317,12 @@ def add_simple_data_type(func: Callable, r: ElementName) -> None:
|
|
231
317
|
show_default=True,
|
232
318
|
help="Use --suffix to append given string to SHACL class name (e. g. --suffix Shape: Person becomes PersonShape).",
|
233
319
|
)
|
320
|
+
@click.option(
|
321
|
+
"--include-annotations/--exclude-annotations",
|
322
|
+
default=False,
|
323
|
+
show_default=True,
|
324
|
+
help="Use --include-annotations to include annotations of slots, types, and classes in the generated SHACL shapes.",
|
325
|
+
)
|
234
326
|
@click.version_option(__version__, "-V", "--version")
|
235
327
|
def cli(yamlfile, **args):
|
236
328
|
"""Generate SHACL turtle from a LinkML model"""
|
@@ -7,12 +7,7 @@ from typing import List, Optional, Union
|
|
7
7
|
|
8
8
|
import click
|
9
9
|
from jinja2 import Template
|
10
|
-
from linkml_runtime.linkml_model import
|
11
|
-
Annotation,
|
12
|
-
ClassDefinition,
|
13
|
-
ClassDefinitionName,
|
14
|
-
SchemaDefinition,
|
15
|
-
)
|
10
|
+
from linkml_runtime.linkml_model import Annotation, ClassDefinition, ClassDefinitionName, SchemaDefinition
|
16
11
|
from linkml_runtime.utils.compile_python import compile_python
|
17
12
|
from linkml_runtime.utils.formatutils import camelcase, underscore
|
18
13
|
from linkml_runtime.utils.schemaview import SchemaView
|
@@ -21,10 +16,7 @@ from sqlalchemy import Enum
|
|
21
16
|
from linkml._version import __version__
|
22
17
|
from linkml.generators.pydanticgen import PydanticGenerator
|
23
18
|
from linkml.generators.pythongen import PythonGenerator
|
24
|
-
from linkml.generators.sqlalchemy import
|
25
|
-
sqlalchemy_declarative_template_str,
|
26
|
-
sqlalchemy_imperative_template_str,
|
27
|
-
)
|
19
|
+
from linkml.generators.sqlalchemy import sqlalchemy_declarative_template_str, sqlalchemy_imperative_template_str
|
28
20
|
from linkml.generators.sqltablegen import SQLTableGenerator
|
29
21
|
from linkml.transformers.relmodel_transformer import ForeignKeyPolicy, RelationalModelTransformer
|
30
22
|
from linkml.utils.generator import Generator, shared_arguments
|
linkml/linter/rules.py
CHANGED
@@ -3,12 +3,7 @@ from abc import ABC, abstractmethod
|
|
3
3
|
from functools import lru_cache
|
4
4
|
from typing import Callable, Iterable, List
|
5
5
|
|
6
|
-
from linkml_runtime.linkml_model import
|
7
|
-
ClassDefinition,
|
8
|
-
ClassDefinitionName,
|
9
|
-
Element,
|
10
|
-
SlotDefinition,
|
11
|
-
)
|
6
|
+
from linkml_runtime.linkml_model import ClassDefinition, ClassDefinitionName, Element, SlotDefinition
|
12
7
|
from linkml_runtime.utils.schemaview import SchemaView
|
13
8
|
from prefixmaps.io.parser import load_multi_context
|
14
9
|
|
@@ -32,6 +32,7 @@ from linkml.transformers.model_transformer import ModelTransformer
|
|
32
32
|
from linkml.utils import logictools
|
33
33
|
|
34
34
|
HERITABLE_METASLOT = [
|
35
|
+
# "multivalued",
|
35
36
|
"range",
|
36
37
|
"range_expression",
|
37
38
|
"minimum_value",
|
@@ -102,7 +103,7 @@ class LogicalModelTransformer(ModelTransformer):
|
|
102
103
|
>>> _ = sb.add_class("Person", slots={"age": {"range": "integer"}}, is_a="Thing")
|
103
104
|
>>> _ = sb.add_class("Organization", slots={"category": {"range": "OrganizationType"}}, is_a="Thing")
|
104
105
|
>>> _ = sb.add_enum("OrganizationType", ["commercial", "non-profit"])
|
105
|
-
>>> from linkml.transformers import LogicalModelTransformer
|
106
|
+
>>> from linkml.transformers.logical_model_transformer import LogicalModelTransformer
|
106
107
|
>>> tr = LogicalModelTransformer()
|
107
108
|
>>> tr.set_schema(sb.schema)
|
108
109
|
>>> flat_schema = tr.transform()
|
@@ -153,8 +154,8 @@ class LogicalModelTransformer(ModelTransformer):
|
|
153
154
|
attributes:
|
154
155
|
entities:
|
155
156
|
name: entities
|
156
|
-
multivalued: true
|
157
157
|
range: Thing
|
158
|
+
multivalued: true
|
158
159
|
|
159
160
|
...
|
160
161
|
|
@@ -443,6 +444,9 @@ class LogicalModelTransformer(ModelTransformer):
|
|
443
444
|
logger.debug(f"Simplified member of: {x}")
|
444
445
|
simplified_att = self._from_logical_expression(x)
|
445
446
|
for k, v in simplified_att.__dict__.items():
|
447
|
+
if v is None or v is False:
|
448
|
+
if k in ["multivalued"]:
|
449
|
+
continue
|
446
450
|
setattr(att, k, v)
|
447
451
|
|
448
452
|
def _simplify_member_ofs(self, expr: logictools.Expression):
|
linkml/utils/schemaloader.py
CHANGED
@@ -235,6 +235,9 @@ class SchemaLoader:
|
|
235
235
|
):
|
236
236
|
self.raise_value_error(f"slot: {slot.name} - unrecognized range ({slot.range})", slot.range)
|
237
237
|
|
238
|
+
# check constraints for usage of equals_string and equals_string_in
|
239
|
+
self._check_equals_string(slot)
|
240
|
+
|
238
241
|
# apply to --> mixins
|
239
242
|
for cls in self.schema.classes.values():
|
240
243
|
for apply_to_cls in cls.apply_to:
|
@@ -372,6 +375,9 @@ class SchemaLoader:
|
|
372
375
|
):
|
373
376
|
self.raise_value_error(f"slot: {slot.name} - unrecognized range ({slot.range})", slot.range)
|
374
377
|
|
378
|
+
# check constraints for usage of equals_string and equals_string_in
|
379
|
+
self._check_equals_string(slot)
|
380
|
+
|
375
381
|
# Massage classes, propagating class slots entries domain back to the target slots
|
376
382
|
for cls in self.schema.classes.values():
|
377
383
|
if not isinstance(cls, ClassDefinition):
|
@@ -964,3 +970,24 @@ class SchemaLoader:
|
|
964
970
|
return rval
|
965
971
|
else:
|
966
972
|
return None
|
973
|
+
|
974
|
+
def _check_equals_string(self, slot: SlotDefinition):
|
975
|
+
if slot.equals_string or slot.equals_string_in:
|
976
|
+
# Range "string" mandatory for "equals_string" and "equals_string_in"
|
977
|
+
range = slot.range
|
978
|
+
if not range:
|
979
|
+
# range is not defined --> check default range
|
980
|
+
range = self.schema.default_range
|
981
|
+
if range != "string":
|
982
|
+
self.raise_value_error(
|
983
|
+
f"slot: {slot.name} - 'equals_string' and 'equals_string_in' requires range "
|
984
|
+
f"'string' and not range '{range}'",
|
985
|
+
slot.range,
|
986
|
+
)
|
987
|
+
if slot.any_of:
|
988
|
+
# It is not allowed to use any of and equals_string or equals_string_in in one slot definition,
|
989
|
+
# as both are mapped to sh:in in SHACL
|
990
|
+
self.raise_value_error(
|
991
|
+
f"slot: {slot.name} - 'equals_string'/'equals_string_in' and 'any_of' are mutually exclusive",
|
992
|
+
slot.name,
|
993
|
+
)
|
linkml/utils/schemasynopsis.py
CHANGED
@@ -21,15 +21,7 @@ from linkml_runtime.utils.metamodelcore import empty_dict
|
|
21
21
|
from linkml_runtime.utils.yamlutils import TypedNode
|
22
22
|
from rdflib import URIRef
|
23
23
|
|
24
|
-
from linkml.utils.typereferences import
|
25
|
-
ClassType,
|
26
|
-
EnumType,
|
27
|
-
References,
|
28
|
-
RefType,
|
29
|
-
SlotType,
|
30
|
-
SubsetType,
|
31
|
-
TypeType,
|
32
|
-
)
|
24
|
+
from linkml.utils.typereferences import ClassType, EnumType, References, RefType, SlotType, SubsetType, TypeType
|
33
25
|
|
34
26
|
|
35
27
|
def empty_references() -> field:
|
linkml/validator/__init__.py
CHANGED
@@ -11,9 +11,7 @@ from typing import Any, Optional, Union
|
|
11
11
|
from linkml_runtime.linkml_model import SchemaDefinition
|
12
12
|
from linkml_runtime.loaders import yaml_loader
|
13
13
|
|
14
|
-
from linkml.validator.loaders import
|
15
|
-
default_loader_for_file,
|
16
|
-
)
|
14
|
+
from linkml.validator.loaders import default_loader_for_file
|
17
15
|
from linkml.validator.plugins import JsonschemaValidationPlugin
|
18
16
|
from linkml.validator.report import ValidationReport
|
19
17
|
from linkml.validator.validator import Validator
|
@@ -4,9 +4,7 @@ on data instances. Instances of these classes should be provided when constructi
|
|
4
4
|
:class:`linkml.validator.Validator` instance.
|
5
5
|
"""
|
6
6
|
|
7
|
-
from linkml.validator.plugins.jsonschema_validation_plugin import
|
8
|
-
JsonschemaValidationPlugin,
|
9
|
-
)
|
7
|
+
from linkml.validator.plugins.jsonschema_validation_plugin import JsonschemaValidationPlugin
|
10
8
|
from linkml.validator.plugins.pydantic_validation_plugin import PydanticValidationPlugin
|
11
9
|
from linkml.validator.plugins.recommended_slots_plugin import RecommendedSlotsPlugin
|
12
10
|
from linkml.validator.plugins.validation_plugin import ValidationPlugin
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: linkml
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.8.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
|
@@ -36,7 +36,7 @@ Requires-Dist: jinja2 (>=3.1.0)
|
|
36
36
|
Requires-Dist: jsonasobj2 (>=1.0.3,<2.0.0)
|
37
37
|
Requires-Dist: jsonschema[format] (>=4.0.0)
|
38
38
|
Requires-Dist: linkml-dataops
|
39
|
-
Requires-Dist: linkml-runtime (
|
39
|
+
Requires-Dist: linkml-runtime (==1.8.0)
|
40
40
|
Requires-Dist: openpyxl
|
41
41
|
Requires-Dist: parse
|
42
42
|
Requires-Dist: prefixcommons (>=0.1.7)
|
@@ -6,9 +6,9 @@ linkml/generators/__init__.py,sha256=dQ2EUKy_MctEVEzbC3XzEJL5YmYwjYfsa44mG2zKn7g
|
|
6
6
|
linkml/generators/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
7
|
linkml/generators/common/type_designators.py,sha256=lgVcIRJJ-yCvVGeP9U_gQZpm77UmJBQo9Bh3lGJITno,1956
|
8
8
|
linkml/generators/csvgen.py,sha256=R8VQdWXj43LNf5isJElo3MStsiNBSSF4ywIRS1c3_v0,3243
|
9
|
-
linkml/generators/docgen/class.md.jinja2,sha256
|
9
|
+
linkml/generators/docgen/class.md.jinja2,sha256=-JmjYHgYOaaBYd5r-Tr5dkk0CLM_lX0kHdocPQtRsjU,3504
|
10
10
|
linkml/generators/docgen/class_diagram.md.jinja2,sha256=gzskx4hOpU_s6BqOXdYZ9DwKxuClnsEgDzPurm30PeY,3469
|
11
|
-
linkml/generators/docgen/common_metadata.md.jinja2,sha256=
|
11
|
+
linkml/generators/docgen/common_metadata.md.jinja2,sha256=gy9J8rghBfKDKimwtHj_XuHY4PJRRYHLXVlBHqWrUzU,1604
|
12
12
|
linkml/generators/docgen/enum.md.jinja2,sha256=mXnUrRkleY2bOTEyAZ5c4pcUnqhs6BNa8a-4LVve-eo,1014
|
13
13
|
linkml/generators/docgen/index.md.jinja2,sha256=wXUYTmayPLFltC0vbGE_Mf6m3GkkWav7FOEjCvEpHp4,1466
|
14
14
|
linkml/generators/docgen/index.tex.jinja2,sha256=Go_EA-_N4JUpbOYbk3OY11mz5yV70VF2l2sMtgIPWw4,501
|
@@ -18,9 +18,9 @@ linkml/generators/docgen/subset.md.jinja2,sha256=EPln_fjlhlkmwEGEp2iPX-9Xm2vVodP
|
|
18
18
|
linkml/generators/docgen/type.md.jinja2,sha256=QmCMJZrFwP33eHkggBVtypbyrxTb-XZn9vHOYojVaYk,635
|
19
19
|
linkml/generators/docgen.py,sha256=QECBmOAiVr-DsUYOLmqapESSB_CiNoiHt_3vjiZCrUs,36396
|
20
20
|
linkml/generators/dotgen.py,sha256=kzp1EYtF8bBqOuycJokDmsvHVDVkkW-J-6-MiUhwJH0,5013
|
21
|
-
linkml/generators/erdiagramgen.py,sha256=
|
21
|
+
linkml/generators/erdiagramgen.py,sha256=7W010ngoHrk-BjhCEmpHyySPImLXIOTEBGO70hOUOH8,11341
|
22
22
|
linkml/generators/excelgen.py,sha256=3ILAeIHeYngNpPf3Ad7CXoHOLQ9KSiYcX5HdwHhQeQE,7696
|
23
|
-
linkml/generators/golanggen.py,sha256=
|
23
|
+
linkml/generators/golanggen.py,sha256=rDiDFyZBZ6_JygCEdpbKrohQCScvBlWi17AcoR6Qi3g,5790
|
24
24
|
linkml/generators/golrgen.py,sha256=OUBYRWicP7G7lrPu1VrxumbVpx3CBJal-o2imyeP05M,3437
|
25
25
|
linkml/generators/graphqlgen.py,sha256=ClJdD6fVjBI8rsIJ3DIuwdQScAJG0gYYKwS8SrFqVZk,2149
|
26
26
|
linkml/generators/javagen/example_template.java.jinja2,sha256=ec4CVTv_0zS7V5Y-1E6H4lRraya10gfX7BEMBlu38X4,444
|
@@ -35,37 +35,38 @@ linkml/generators/markdowngen.py,sha256=mwydWkrF-WzsTiKwJqqe9NUya5VaTj7ywKqodP85
|
|
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=2e4ejw0B72Sl_-mipgpKz743LVMs0kRZc8E0MK7gxFY,14919
|
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
42
|
linkml/generators/pydanticgen/__init__.py,sha256=uKGaaQSaeKqinHImXGFE448i-t8Oi0No8suIO76sep8,629
|
43
|
-
linkml/generators/pydanticgen/array.py,sha256=
|
44
|
-
linkml/generators/pydanticgen/black.py,sha256=
|
43
|
+
linkml/generators/pydanticgen/array.py,sha256=EYqAkT2_wE82kZ-niUWAC5U3V8EvjjyfSH7tz5GYKWo,19461
|
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/
|
47
|
-
linkml/generators/pydanticgen/
|
48
|
-
linkml/generators/pydanticgen/
|
46
|
+
linkml/generators/pydanticgen/includes.py,sha256=PIVbACrtqQS6LFrXqQsJC6dQUcGBM3uY4E4qLQWJrnk,998
|
47
|
+
linkml/generators/pydanticgen/pydanticgen.py,sha256=WZxFfLvXhHXVtDQpLjMf63eoBMUxcW0oEMS14jbDOWo,34458
|
48
|
+
linkml/generators/pydanticgen/template.py,sha256=HESLY1Rd7N_e92dqrh_fif_yp3oDl0n1UAghklMyphA,20982
|
49
|
+
linkml/generators/pydanticgen/templates/attribute.py.jinja,sha256=S_T-M7n_eeM3LW5gQUuTPH1-Oc1CEtL7Bve7qAFouYQ,688
|
49
50
|
linkml/generators/pydanticgen/templates/base_model.py.jinja,sha256=48y64MnC9rjNSV-nKLMeDuHN4gm15UsInhnKxh65zoM,834
|
50
|
-
linkml/generators/pydanticgen/templates/class.py.jinja,sha256=
|
51
|
+
linkml/generators/pydanticgen/templates/class.py.jinja,sha256=V_lyvFcZ9QhlKZi2bL5iff8RjHir2SQTTypOzQMOfmk,744
|
51
52
|
linkml/generators/pydanticgen/templates/conditional_import.py.jinja,sha256=YheknDrxvepiJUzeItSL5aSbAkCdR1k0a6m6aTA4qNM,240
|
52
53
|
linkml/generators/pydanticgen/templates/enum.py.jinja,sha256=572XFQyEMZfL-G_Cj68T-NI_mUnDoFOAVJOGIKu2Hb8,338
|
53
54
|
linkml/generators/pydanticgen/templates/footer.py.jinja,sha256=WuWGJjkWDQcEPL2bGk5fdGuhO0gQRUJzpo4CQHHxQNQ,385
|
54
55
|
linkml/generators/pydanticgen/templates/imports.py.jinja,sha256=d1XFna2eOpkH8cgJML3vXwqGcocczvOcrbg6jjd4kP0,945
|
55
|
-
linkml/generators/pydanticgen/templates/module.py.jinja,sha256=
|
56
|
+
linkml/generators/pydanticgen/templates/module.py.jinja,sha256=nymjtSX4jqV9deSsXrsh1HWR90ygECHE4CV9MCyNrTY,615
|
56
57
|
linkml/generators/pydanticgen/templates/validator.py.jinja,sha256=Yo4dubQal-HwEoJKztQkLYM5qCz1I8na2oaDlXuEpwU,532
|
57
|
-
linkml/generators/pythongen.py,sha256=
|
58
|
+
linkml/generators/pythongen.py,sha256=CiLmc964siGeJWZC_bOffsqrSnJ5qzn7Eu961C47xgo,52850
|
58
59
|
linkml/generators/rdfgen.py,sha256=eQi3XXjWk6xliTLncQ4G0VYzGCJwCU_FFG-O7tA8DSA,2959
|
59
60
|
linkml/generators/shacl/__init__.py,sha256=O-M-wndKw8rMW-U8X3QCNHal-ErXP6uXZqxiQSa77l4,108
|
60
61
|
linkml/generators/shacl/ifabsent_processor.py,sha256=kV9BGA2ZPXLRfaFuW0o4jpkATvGggvrqpAo9c1UqWNE,2193
|
61
62
|
linkml/generators/shacl/shacl_data_type.py,sha256=BT3C9tdFyBQnuucPN7YQiFAKEa9yuzy-Q26X6dmOXgo,1827
|
62
|
-
linkml/generators/shaclgen.py,sha256=
|
63
|
+
linkml/generators/shaclgen.py,sha256=kgJ3VaVM0_7XBr5cvqgob6wjEarNINZzpC4FK61sC9M,13157
|
63
64
|
linkml/generators/shexgen.py,sha256=MhB1HidCREMCJcDGBqutFQ0gWKKz7aSVw-0s-IHUMm4,9930
|
64
65
|
linkml/generators/sparqlgen.py,sha256=c7x8GFChKWprBx4rToSnu9qN8OleWTCenVUdZ8XSTWM,6138
|
65
66
|
linkml/generators/sqlalchemy/__init__.py,sha256=mb9AC1rIFkSiNZhhG0TAk45ol9PjS1XvsrvCjgfVUpQ,249
|
66
67
|
linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py,sha256=X_Ws1NUBikMI5HuNgEhl_PIeWM-B-c2B0W9KUBH4QTg,2542
|
67
68
|
linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py,sha256=u4ZpponG1h6XROrOHGOf_0H2e6xL1_s8twAOA-gx94A,1622
|
68
|
-
linkml/generators/sqlalchemygen.py,sha256=
|
69
|
+
linkml/generators/sqlalchemygen.py,sha256=boXn_tlkbZ_a5TJYoXvdlKzABNwD-Jn5ld9IAbtzWm4,9286
|
69
70
|
linkml/generators/sqltablegen.py,sha256=87057FJi9EUVPXOjRfHuSqY0lKmepXRNQsose2fGts4,12343
|
70
71
|
linkml/generators/sssomgen.py,sha256=yur3q7so9uwIELWZaZRzkJwNbz_ppBL7IQki9XLIM3k,6879
|
71
72
|
linkml/generators/string_template.md,sha256=kRcfic6entgIaJdpSg6GF3jcjC9wbKsCVM6wVT2qipc,1788
|
@@ -89,11 +90,11 @@ linkml/linter/formatters/markdown_formatter.py,sha256=sumF2MNJYL5oipLwCftCr3AiaC
|
|
89
90
|
linkml/linter/formatters/terminal_formatter.py,sha256=xmNwlRieVCssRt3fpnNP5WWw_YXGmaBsbxFoMWufy5M,2085
|
90
91
|
linkml/linter/formatters/tsv_formatter.py,sha256=1VW-1Tv16mwhIDpHdExYpJJR3z42K5_XK2C-4mmYYdE,871
|
91
92
|
linkml/linter/linter.py,sha256=qfVV-vFT7bUJ2BmmDQteD7Jz8HZ-CNDSvnkyhJ-54H0,5113
|
92
|
-
linkml/linter/rules.py,sha256=
|
93
|
+
linkml/linter/rules.py,sha256=Eg_-lIX1KPsCp3PHdPcBiHmSS5qAVZkHbw5LURfkfXk,11481
|
93
94
|
linkml/reporting/__init__.py,sha256=Jo0V_nyEcnWhMukMW-bqW9dlbgCfaRlWm3CO-XzgU84,92
|
94
95
|
linkml/reporting/model.py,sha256=-10yNfk8wuRC48ZI-akrWvtlJ9a6RYWET2TzlZV3XXo,8622
|
95
96
|
linkml/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
96
|
-
linkml/transformers/logical_model_transformer.py,sha256=
|
97
|
+
linkml/transformers/logical_model_transformer.py,sha256=z-1nyD0d8LYJeAPWRn29p-S4Hgmvjocfcj0VrHTAs2c,26703
|
97
98
|
linkml/transformers/model_transformer.py,sha256=tK_MpRDI-q2qfe8KHT6qJHP8ZruKjYx1FcM-Fnjse-E,678
|
98
99
|
linkml/transformers/relmodel_transformer.py,sha256=aiSI2xaqRz4f0Z_0WFaBP5bknzX0pTnvxsR5mESFysg,18857
|
99
100
|
linkml/transformers/schema_renamer.py,sha256=DYRbgL9j41M9FdbHYLY3u4YIdDM98laD3cv_lHcgWHQ,5275
|
@@ -112,12 +113,12 @@ linkml/utils/mergeutils.py,sha256=QVm2iQB4v_L2rSvPBsPe9C865R03BgV3TzlPoTTTwWQ,90
|
|
112
113
|
linkml/utils/rawloader.py,sha256=nUB8Gfn8yEVwyo6bx0TtB2mBGkilC-fybi0xvQ73Gks,4417
|
113
114
|
linkml/utils/schema_builder.py,sha256=4qhrur8O0xRZnPm7H1h2BZmTkut5R4q-IE_1KKiHy_c,9937
|
114
115
|
linkml/utils/schema_fixer.py,sha256=Uz8M3AOQ_BputJr1f6lbfk1iyvmANUNG80-0B3BQKJ8,16761
|
115
|
-
linkml/utils/schemaloader.py,sha256=
|
116
|
-
linkml/utils/schemasynopsis.py,sha256=
|
116
|
+
linkml/utils/schemaloader.py,sha256=dWZO044p_UcUWnrd8HZ-NsbLXQ9cA6c8HKfNI9-qH2A,47388
|
117
|
+
linkml/utils/schemasynopsis.py,sha256=j7sNt6j-E3rmf-1qEo351Kth2kltt6crQV-dxJAGCUE,18414
|
117
118
|
linkml/utils/sqlutils.py,sha256=Cwoaz44MLcvAGUEBshT4jtn0Z3w7jVOp85zGkd6FTHY,17071
|
118
119
|
linkml/utils/typereferences.py,sha256=8Yfuz9-HAwOPoJLbIcO_sY9zf32hvPRzGeSOzECfMWA,2232
|
119
120
|
linkml/utils/validation.py,sha256=eLw1-d8x3N1V14bSc6H_mJJXo59ryKvvUIBcOJ1dVMw,1438
|
120
|
-
linkml/validator/__init__.py,sha256=
|
121
|
+
linkml/validator/__init__.py,sha256=u0CeorIw50Qqwa60-lIFsJXg-sOdfo90hqvLpyvvwo4,4993
|
121
122
|
linkml/validator/cli.py,sha256=uVe_tbBzsK-4BNboE5zRyohS_dEs5Nl1gbhklrzOEpw,7605
|
122
123
|
linkml/validator/loaders/__init__.py,sha256=FjUqEfBHeT5PEMBEZ9XwpclyQOysr4OCI1M0w_MYPVc,1165
|
123
124
|
linkml/validator/loaders/delimited_file_loader.py,sha256=fdh61ZMPTfH29_DM93f5dY0jLP7KQPNh_QAHZppsdNw,2616
|
@@ -125,7 +126,7 @@ linkml/validator/loaders/json_loader.py,sha256=Qy42naS2clb0fNXbUushckRu5AIX32b3U
|
|
125
126
|
linkml/validator/loaders/loader.py,sha256=YKQXmSZhCymvvb2Dbr4lVCKVDt-lOIayzRD7CWrdsJI,559
|
126
127
|
linkml/validator/loaders/passthrough_loader.py,sha256=fQvBZqzGnpdwpZio4Mbehmsb6ePpzcacHPuR1QWuhFM,525
|
127
128
|
linkml/validator/loaders/yaml_loader.py,sha256=ZsMz-oGDkX9oPEOVcKnFRGhU9q0fKoHcL6BLOkCeB4c,914
|
128
|
-
linkml/validator/plugins/__init__.py,sha256=
|
129
|
+
linkml/validator/plugins/__init__.py,sha256=0ifiDqpcXVy4X7OJFm7FMYi1-6E06avNIIk9R0c6nD8,693
|
129
130
|
linkml/validator/plugins/jsonschema_validation_plugin.py,sha256=c3OjvLR5m83vppsDfkrS9nMXma_ogUxXpZuM_JIUVM4,2634
|
130
131
|
linkml/validator/plugins/pydantic_validation_plugin.py,sha256=C-Vp74bz5oqp5V-iuhXW8p0PPDoFY8NCU5x36Ur5Og4,1985
|
131
132
|
linkml/validator/plugins/recommended_slots_plugin.py,sha256=kOdoYQyye47nLA7BjorVmydS84nGpiVy3MoCbPq1Ymo,2308
|
@@ -142,8 +143,8 @@ linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
142
143
|
linkml/workspaces/datamodel/workspaces.py,sha256=4HdkqweGNfMPqnB1_Onc9DcTfkhoagTRcqruh08nRoI,14905
|
143
144
|
linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
|
144
145
|
linkml/workspaces/example_runner.py,sha256=hDk2RGxRE5-WYNriWknugtbm3Mhn8bFcAcXGMlkYxVk,11705
|
145
|
-
linkml-1.
|
146
|
-
linkml-1.
|
147
|
-
linkml-1.
|
148
|
-
linkml-1.
|
149
|
-
linkml-1.
|
146
|
+
linkml-1.8.0.dist-info/entry_points.txt,sha256=7haDkIbyC7ZLhm5z-e3BhrLJpY2xoW1yuD8Y7QPNtVg,2093
|
147
|
+
linkml-1.8.0.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
|
148
|
+
linkml-1.8.0.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
149
|
+
linkml-1.8.0.dist-info/METADATA,sha256=ImZiqQezJfM8leU0WgCimYjcJXydh1XO8T22tlC9zpw,3724
|
150
|
+
linkml-1.8.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|