linkml 1.5.5__py3-none-any.whl → 1.5.7__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/__init__.py +2 -6
- linkml/_version.py +1 -1
- linkml/generators/PythonGenNotes.md +4 -4
- linkml/generators/__init__.py +26 -5
- linkml/generators/common/type_designators.py +27 -22
- linkml/generators/csvgen.py +4 -10
- linkml/generators/docgen/class.md.jinja2 +7 -0
- linkml/generators/docgen/class_diagram.md.jinja2 +0 -6
- linkml/generators/docgen/subset.md.jinja2 +54 -13
- linkml/generators/docgen.py +94 -92
- linkml/generators/dotgen.py +5 -9
- linkml/generators/erdiagramgen.py +58 -53
- linkml/generators/excelgen.py +10 -16
- linkml/generators/golanggen.py +11 -21
- linkml/generators/golrgen.py +4 -13
- linkml/generators/graphqlgen.py +3 -11
- linkml/generators/javagen.py +8 -15
- linkml/generators/jsonldcontextgen.py +7 -36
- linkml/generators/jsonldgen.py +14 -12
- linkml/generators/jsonschemagen.py +183 -136
- linkml/generators/linkmlgen.py +1 -1
- linkml/generators/markdowngen.py +40 -89
- linkml/generators/namespacegen.py +1 -2
- linkml/generators/oocodegen.py +22 -25
- linkml/generators/owlgen.py +48 -49
- linkml/generators/prefixmapgen.py +6 -14
- linkml/generators/projectgen.py +7 -14
- linkml/generators/protogen.py +3 -5
- linkml/generators/pydanticgen.py +85 -73
- linkml/generators/pythongen.py +89 -157
- linkml/generators/rdfgen.py +5 -11
- linkml/generators/shaclgen.py +32 -18
- linkml/generators/shexgen.py +19 -24
- linkml/generators/sparqlgen.py +5 -13
- linkml/generators/sqlalchemy/__init__.py +3 -2
- linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +7 -7
- linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +3 -3
- linkml/generators/sqlalchemygen.py +29 -27
- linkml/generators/sqlddlgen.py +34 -26
- linkml/generators/sqltablegen.py +21 -21
- linkml/generators/sssomgen.py +11 -13
- linkml/generators/summarygen.py +2 -4
- linkml/generators/terminusdbgen.py +7 -19
- linkml/generators/typescriptgen.py +10 -18
- linkml/generators/yamlgen.py +0 -2
- linkml/generators/yumlgen.py +23 -71
- linkml/linter/cli.py +4 -11
- linkml/linter/config/datamodel/config.py +17 -47
- linkml/linter/linter.py +2 -4
- linkml/linter/rules.py +34 -48
- linkml/reporting/__init__.py +2 -0
- linkml/reporting/model.py +9 -24
- linkml/transformers/relmodel_transformer.py +20 -33
- linkml/transformers/schema_renamer.py +14 -10
- linkml/utils/converter.py +15 -15
- linkml/utils/datautils.py +9 -24
- linkml/utils/datavalidator.py +2 -2
- linkml/utils/execute_tutorial.py +10 -12
- linkml/utils/generator.py +74 -92
- linkml/utils/helpers.py +4 -2
- linkml/utils/ifabsent_functions.py +23 -15
- linkml/utils/mergeutils.py +19 -35
- linkml/utils/rawloader.py +2 -6
- linkml/utils/schema_builder.py +31 -19
- linkml/utils/schema_fixer.py +28 -18
- linkml/utils/schemaloader.py +44 -89
- linkml/utils/schemasynopsis.py +50 -73
- linkml/utils/sqlutils.py +40 -30
- linkml/utils/typereferences.py +9 -6
- linkml/utils/validation.py +4 -5
- linkml/validators/__init__.py +2 -0
- linkml/validators/jsonschemavalidator.py +104 -53
- linkml/validators/sparqlvalidator.py +5 -15
- linkml/workspaces/datamodel/workspaces.py +13 -30
- linkml/workspaces/example_runner.py +75 -68
- {linkml-1.5.5.dist-info → linkml-1.5.7.dist-info}/METADATA +2 -2
- linkml-1.5.7.dist-info/RECORD +109 -0
- linkml-1.5.5.dist-info/RECORD +0 -109
- {linkml-1.5.5.dist-info → linkml-1.5.7.dist-info}/LICENSE +0 -0
- {linkml-1.5.5.dist-info → linkml-1.5.7.dist-info}/WHEEL +0 -0
- {linkml-1.5.5.dist-info → linkml-1.5.7.dist-info}/entry_points.txt +0 -0
linkml/__init__.py
CHANGED
@@ -20,9 +20,7 @@ MODULE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
|
20
20
|
LOCAL_METAMODEL_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.META, Format.YAML)
|
21
21
|
LOCAL_TYPES_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.TYPES, Format.YAML)
|
22
22
|
LOCAL_MAPPINGS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.MAPPINGS, Format.YAML)
|
23
|
-
LOCAL_ANNOTATIONS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(
|
24
|
-
Source.ANNOTATIONS, Format.YAML
|
25
|
-
)
|
23
|
+
LOCAL_ANNOTATIONS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.ANNOTATIONS, Format.YAML)
|
26
24
|
LOCAL_EXTENSIONS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.EXTENSIONS, Format.YAML)
|
27
25
|
|
28
26
|
# Local location of jsonld and context.jsonld files
|
@@ -30,9 +28,7 @@ LOCAL_METAMODEL_LDCONTEXT_FILE = linkml_files.LOCAL_PATH_FOR(Source.META, Format
|
|
30
28
|
LOCAL_METAMODEL_JSONLD_FILE = linkml_files.LOCAL_PATH_FOR(Source.META, Format.JSON)
|
31
29
|
LOCAL_TYPES_LDCONTEXT_FILE = linkml_files.LOCAL_PATH_FOR(Source.TYPES, Format.JSONLD)
|
32
30
|
LOCAL_TYPES_JSONLD_FILE = linkml_files.LOCAL_PATH_FOR(Source.TYPES, Format.JSON)
|
33
|
-
LOCAL_MAPPINGS_LDCONTEXT_FILE = linkml_files.LOCAL_PATH_FOR(
|
34
|
-
Source.MAPPINGS, Format.JSONLD
|
35
|
-
)
|
31
|
+
LOCAL_MAPPINGS_LDCONTEXT_FILE = linkml_files.LOCAL_PATH_FOR(Source.MAPPINGS, Format.JSONLD)
|
36
32
|
LOCAL_MAPPINGS_JSONLD_FILE = linkml_files.LOCAL_PATH_FOR(Source.MAPPINGS, Format.JSON)
|
37
33
|
|
38
34
|
# Local location of metamodel shex file
|
linkml/_version.py
CHANGED
@@ -122,7 +122,7 @@ the builtin type `int`. Four class variables are included in the generation:
|
|
122
122
|
* `type_name` - the non-mangled name assigned to the type in the original definition
|
123
123
|
* `type_model_uri` - the URIRef of the type definition in the default LinkML namespace
|
124
124
|
|
125
|
-
The python then emits a class definition for the `Integers`
|
125
|
+
The python then emits a class definition for the `Integers` class, where we have defined four slot type permutations:
|
126
126
|
|
127
127
|
1) `mand_integer` - a single valued required type:
|
128
128
|
|
@@ -189,7 +189,7 @@ The python then emits a class definition for the `Integers` classe, where we hav
|
|
189
189
|
|
190
190
|
`opt_multi_integer: Optional[Union[int, List[int]]] = empty_list()`
|
191
191
|
|
192
|
-
* The absence of a list property is always represented as an
|
192
|
+
* The absence of a list property is always represented as an empty list:
|
193
193
|
```
|
194
194
|
if self.opt_multi_integer is None:
|
195
195
|
self.opt_multi_integer = []
|
@@ -1232,7 +1232,7 @@ dictionary. You can construct a list of integers with a single value:
|
|
1232
1232
|
```python
|
1233
1233
|
my_entries = ListOfIntegers(17)
|
1234
1234
|
```
|
1235
|
-
Which would, if the class `ListOfIntegers`'s first variable was a multivalued slot with a range of
|
1235
|
+
Which would, if the class `ListOfIntegers`'s first variable was a multivalued slot with a range of integers, result in
|
1236
1236
|
`my_entries.v == [17]`. When dealing with classes, however, the following:
|
1237
1237
|
```python
|
1238
1238
|
my_entries = ListOfClasses(dict(name='element1', value=17))
|
@@ -1243,7 +1243,7 @@ The final line in the `__post_init__` section:
|
|
1243
1243
|
```python
|
1244
1244
|
self._normalize_inlined_slot(slot_name="v1", slot_type=IdentifiedThreeElementClass, key_name="name", inlined_as_list=True, keyed=True)
|
1245
1245
|
```
|
1246
|
-
passes the remainder of the post
|
1246
|
+
passes the remainder of the post initialization normalization to a function defined in `YAMLRoot`.
|
1247
1247
|
|
1248
1248
|
|
1249
1249
|
The final case, Case 2.4 (Inlined as dictionary) is essentially the same, with the exception that the target type is
|
linkml/generators/__init__.py
CHANGED
@@ -2,7 +2,17 @@
|
|
2
2
|
Generators translate between a SchemaDefinition and an alternative
|
3
3
|
representation such as JsonSchema
|
4
4
|
"""
|
5
|
-
|
5
|
+
|
6
|
+
from linkml.generators.javagen import JavaGenerator
|
7
|
+
from linkml.generators.jsonschemagen import JsonSchemaGenerator
|
8
|
+
from linkml.generators.owlgen import OwlSchemaGenerator
|
9
|
+
from linkml.generators.pydanticgen import PydanticGenerator
|
10
|
+
from linkml.generators.pythongen import PythonGenerator
|
11
|
+
from linkml.generators.shaclgen import ShaclGenerator
|
12
|
+
from linkml.generators.shexgen import ShExGenerator
|
13
|
+
from linkml.generators.sqlalchemygen import SQLAlchemyGenerator
|
14
|
+
from linkml.generators.sqltablegen import SQLTableGenerator
|
15
|
+
|
6
16
|
__all__ = [
|
7
17
|
"csvgen",
|
8
18
|
"dotgen",
|
@@ -18,15 +28,26 @@ __all__ = [
|
|
18
28
|
"owlgen",
|
19
29
|
"protogen",
|
20
30
|
"pythongen",
|
31
|
+
"pydanticgen",
|
21
32
|
"rdfgen",
|
22
33
|
"shexgen",
|
34
|
+
"shaclgen",
|
23
35
|
"sssomgen",
|
24
36
|
"summarygen",
|
25
37
|
"yamlgen",
|
26
38
|
"yumlgen",
|
27
|
-
"
|
39
|
+
"OwlSchemaGenerator",
|
40
|
+
"PydanticGenerator",
|
41
|
+
"PythonGenerator",
|
42
|
+
"JavaGenerator",
|
43
|
+
"JsonSchemaGenerator",
|
44
|
+
"ShaclGenerator",
|
45
|
+
"ShExGenerator",
|
46
|
+
"SQLAlchemyGenerator",
|
47
|
+
"SQLTableGenerator",
|
28
48
|
]
|
29
|
-
GENERATOR_BASE = "0.9"
|
30
49
|
|
31
|
-
|
32
|
-
|
50
|
+
# TODO: deprecate usage of these
|
51
|
+
# GENERATOR_BASE = "0.9"
|
52
|
+
|
53
|
+
# PYTHON_GEN_VERSION = GENERATOR_BASE + ".0"
|
@@ -1,44 +1,49 @@
|
|
1
|
-
from
|
1
|
+
from typing import List
|
2
|
+
|
3
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
|
2
4
|
from linkml_runtime.utils.schemaview import SchemaView
|
3
|
-
from linkml_runtime.utils.formatutils import camelcase
|
4
|
-
from typing import List, Tuple
|
5
5
|
|
6
|
-
|
6
|
+
|
7
|
+
def get_type_designator_value(
|
8
|
+
sv: SchemaView, type_designator_slot: SlotDefinition, class_def: ClassDefinition
|
9
|
+
) -> str:
|
7
10
|
"""
|
8
|
-
|
9
|
-
|
11
|
+
returns the correct value for a type designator field for a given class, depending on its range
|
12
|
+
this implements the logic described in https://github.com/linkml/linkml/issues/945:
|
10
13
|
"""
|
11
14
|
slot_types = set(sv.type_ancestors(type_designator_slot.range))
|
12
|
-
if
|
13
|
-
return sv.get_uri(class_def,expand=True,native=False)
|
14
|
-
elif
|
15
|
-
return sv.get_uri(class_def,expand=False, native=False)
|
16
|
-
elif
|
15
|
+
if "uri" in slot_types:
|
16
|
+
return sv.get_uri(class_def, expand=True, native=False)
|
17
|
+
elif "uriorcurie" in slot_types:
|
18
|
+
return sv.get_uri(class_def, expand=False, native=False)
|
19
|
+
elif "string" in slot_types:
|
17
20
|
return class_def.name
|
18
21
|
else:
|
19
|
-
return sv.get_uri(class_def,expand=False, native=False)
|
22
|
+
return sv.get_uri(class_def, expand=False, native=False)
|
20
23
|
|
21
24
|
|
22
|
-
def get_accepted_type_designator_values(
|
25
|
+
def get_accepted_type_designator_values(
|
26
|
+
sv: SchemaView, type_designator_slot: SlotDefinition, class_def: ClassDefinition
|
27
|
+
) -> List[str]:
|
23
28
|
"""
|
24
|
-
|
25
|
-
|
29
|
+
returns the accepted values for a type designator field for a given class, depending on its range
|
30
|
+
this implements the logic described in https://github.com/linkml/linkml/issues/945:
|
26
31
|
"""
|
27
32
|
accepted_uri_values = [
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
sv.get_uri(class_def, expand=True, native=True),
|
34
|
+
sv.get_uri(class_def, expand=True, native=False),
|
35
|
+
sv.get_uri(class_def, expand=False, native=True),
|
36
|
+
sv.get_uri(class_def, expand=False, native=False),
|
37
|
+
]
|
33
38
|
# unique, but with order preserved (https://stackoverflow.com/a/17016257)
|
34
39
|
accepted_uri_values = list(dict.fromkeys(accepted_uri_values))
|
35
40
|
|
36
41
|
slot_types = set(sv.type_ancestors(type_designator_slot.range))
|
37
|
-
uri_types = [
|
42
|
+
uri_types = ["uri", "uriorcurie"]
|
38
43
|
|
39
44
|
if slot_types.intersection(uri_types):
|
40
45
|
return accepted_uri_values
|
41
|
-
elif type_designator_slot.range ==
|
46
|
+
elif type_designator_slot.range == "string":
|
42
47
|
return [class_def.name]
|
43
48
|
else:
|
44
49
|
return accepted_uri_values
|
linkml/generators/csvgen.py
CHANGED
@@ -5,12 +5,10 @@ import os
|
|
5
5
|
import sys
|
6
6
|
from csv import DictWriter
|
7
7
|
from dataclasses import dataclass
|
8
|
-
from typing import List, Optional, Set
|
8
|
+
from typing import List, Optional, Set
|
9
9
|
|
10
10
|
import click
|
11
|
-
from linkml_runtime.linkml_model.meta import
|
12
|
-
ClassDefinitionName,
|
13
|
-
SchemaDefinition)
|
11
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionName
|
14
12
|
from linkml_runtime.utils.formatutils import be, underscore
|
15
13
|
|
16
14
|
from linkml._version import __version__
|
@@ -37,9 +35,7 @@ class CsvGenerator(Generator):
|
|
37
35
|
sep: Optional[str] = None
|
38
36
|
"""Separator for columns"""
|
39
37
|
|
40
|
-
closure: Optional[
|
41
|
-
Set[ClassDefinitionName]
|
42
|
-
] = None
|
38
|
+
closure: Optional[Set[ClassDefinitionName]] = None
|
43
39
|
"""List of classes to include in output"""
|
44
40
|
|
45
41
|
writer: Optional[DictWriter] = None
|
@@ -69,9 +65,7 @@ class CsvGenerator(Generator):
|
|
69
65
|
self.closure.update(self.ancestors(self.schema.classes[clsname]))
|
70
66
|
|
71
67
|
dialect: str = "excel" if self.format == "csv" else "excel-tab"
|
72
|
-
self.writer = DictWriter(
|
73
|
-
sys.stdout, ["id", "mappings", "description"], dialect=dialect
|
74
|
-
)
|
68
|
+
self.writer = DictWriter(sys.stdout, ["id", "mappings", "description"], dialect=dialect)
|
75
69
|
self.writer.writeheader()
|
76
70
|
|
77
71
|
def visit_class(self, cls: ClassDefinition) -> bool:
|
@@ -18,7 +18,14 @@ _{{ element_description_line }}_
|
|
18
18
|
|
19
19
|
URI: {{ gen.uri_link(element) }}
|
20
20
|
|
21
|
+
|
22
|
+
{% if diagram_type == "er_diagram" %}
|
23
|
+
```{{ gen.mermaid_directive() }}
|
24
|
+
{{ gen.mermaid_diagram([element.name]) }}
|
25
|
+
```
|
26
|
+
{% else %}
|
21
27
|
{% include "class_diagram.md.jinja2" %}
|
28
|
+
{% endif %}
|
22
29
|
|
23
30
|
{% if schemaview.class_parents(element.name) or schemaview.class_children(element.name, mixins=False) %}
|
24
31
|
|
@@ -1,8 +1,3 @@
|
|
1
|
-
{% if diagram_type == "er_diagram" %}
|
2
|
-
```{{ gen.mermaid_directive() }}
|
3
|
-
{{ gen.mermaid_diagram([element.name]) }}
|
4
|
-
```
|
5
|
-
{% else %}
|
6
1
|
{% if schemaview.class_parents(element.name) and schemaview.class_children(element.name) %}
|
7
2
|
```{{ gen.mermaid_directive() }}
|
8
3
|
classDiagram
|
@@ -61,5 +56,4 @@
|
|
61
56
|
{% endif %}
|
62
57
|
{% endfor %}
|
63
58
|
```
|
64
|
-
{% endif %}
|
65
59
|
{% endif %}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Subset: {{ gen.name(element) }}
|
2
2
|
|
3
3
|
{%- if header -%}
|
4
|
-
{{header}}
|
4
|
+
{{ header }}
|
5
5
|
{%- endif -%}
|
6
6
|
|
7
7
|
{% if element.description %}
|
@@ -13,9 +13,32 @@ _{{ element_description_line }}_
|
|
13
13
|
|
14
14
|
URI: {{ gen.uri_link(element) }}
|
15
15
|
|
16
|
-
|
17
16
|
{% include "common_metadata.md.jinja2" %}
|
18
17
|
|
18
|
+
{% set classes_in_subset = [] %}
|
19
|
+
{% set slots_in_subset = [] %}
|
20
|
+
{% set enums_in_subset = [] %}
|
21
|
+
|
22
|
+
{# Collect classes, slots, and enumerations in subset #}
|
23
|
+
{% for c in gen.all_class_objects()|sort(attribute=sort_by) %}
|
24
|
+
{%- if element.name in c.in_subset %}
|
25
|
+
{% set _ = classes_in_subset.append(c) %}
|
26
|
+
{%- endif %}
|
27
|
+
{% endfor %}
|
28
|
+
|
29
|
+
{% for s in gen.all_slot_objects()|sort(attribute=sort_by) %}
|
30
|
+
{%- if element.name in s.in_subset %}
|
31
|
+
{% set _ = slots_in_subset.append(s) %}
|
32
|
+
{%- endif %}
|
33
|
+
{% endfor %}
|
34
|
+
|
35
|
+
{% for e in schemaview.all_enums().values() %}
|
36
|
+
{%- if element.name in e.in_subset %}
|
37
|
+
{% set _ = enums_in_subset.append(e) %}
|
38
|
+
{%- endif %}
|
39
|
+
{% endfor %}
|
40
|
+
|
41
|
+
{% if classes_in_subset %}
|
19
42
|
## Classes in subset
|
20
43
|
|
21
44
|
| Class | Description |
|
@@ -32,34 +55,52 @@ URI: {{ gen.uri_link(element) }}
|
|
32
55
|
|
33
56
|
{{c.description}}
|
34
57
|
|
58
|
+
{%- set filtered_slots = [] -%}
|
59
|
+
|
60
|
+
{%- for s in induced_slots|sort(attribute=sort_by) -%}
|
61
|
+
{%- if element.name in s.in_subset or element.name in schemaview.get_slot(s.name).in_subset -%}
|
62
|
+
{% set _ = filtered_slots.append(s) %}
|
63
|
+
{%- endif -%}
|
64
|
+
{%- endfor %}
|
65
|
+
|
66
|
+
{%- if filtered_slots|length > 0 -%}
|
35
67
|
| Name | Cardinality and Range | Description |
|
36
68
|
| --- | --- | --- |
|
37
|
-
{% for s in
|
38
|
-
{% if element.name in s.in_subset or element.name in schemaview.get_slot(s.name).in_subset -%}
|
69
|
+
{% for s in filtered_slots -%}
|
39
70
|
| {{gen.link(s)}} | {{ gen.cardinality(s) }} <br/> {{gen.link(s.range)}} | {{s.description|enshorten}} {% if s.identifier %}**identifier**{% endif %} |
|
40
|
-
{% endif -%}
|
41
71
|
{% endfor %}
|
72
|
+
{%- endif %}
|
42
73
|
|
43
|
-
|
74
|
+
|
75
|
+
{%- endif %}
|
44
76
|
{% endfor %}
|
45
77
|
|
78
|
+
{%- endif %}
|
79
|
+
|
80
|
+
|
81
|
+
{% if slots_in_subset %}
|
46
82
|
## Slots in subset
|
47
83
|
|
48
84
|
| Slot | Description |
|
49
85
|
| --- | --- |
|
50
|
-
{% for s in
|
86
|
+
{% for s in slots_in_subset|sort(attribute=sort_by) -%}
|
51
87
|
{%- if element.name in s.in_subset -%}
|
52
|
-
| {{gen.link(s)}} | {{s.description|enshorten}} |
|
53
|
-
{
|
88
|
+
| {{ gen.link(s) }} | {{ s.description|enshorten }} |
|
89
|
+
{%- endif %}
|
54
90
|
{% endfor %}
|
55
91
|
|
92
|
+
{%- endif %}
|
93
|
+
|
94
|
+
|
95
|
+
{% if enums_in_subset %}
|
56
96
|
## Enumerations in subset
|
57
97
|
|
58
98
|
| Enumeration | Description |
|
59
99
|
| --- | --- |
|
60
|
-
{% for e in
|
61
|
-
{%- if element.name in e.in_subset
|
62
|
-
| {{gen.link(e)}} | {{e.description|enshorten}} |
|
63
|
-
{
|
100
|
+
{% for e in enums_in_subset|sort(attribute='name') -%}
|
101
|
+
{%- if element.name in e.in_subset %}
|
102
|
+
| {{ gen.link(e) }} | {{ e.description|enshorten }} |
|
103
|
+
{%- endif %}
|
64
104
|
{% endfor %}
|
65
105
|
|
106
|
+
{%- endif %}
|