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/generators/summarygen.py
CHANGED
@@ -5,11 +5,10 @@ import os
|
|
5
5
|
import sys
|
6
6
|
from csv import DictWriter
|
7
7
|
from dataclasses import dataclass, field
|
8
|
-
from typing import Optional
|
8
|
+
from typing import Optional
|
9
9
|
|
10
10
|
import click
|
11
|
-
from linkml_runtime.linkml_model.meta import
|
12
|
-
SchemaDefinition, SlotDefinition)
|
11
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
|
13
12
|
from linkml_runtime.utils.formatutils import camelcase
|
14
13
|
|
15
14
|
from linkml._version import __version__
|
@@ -18,7 +17,6 @@ from linkml.utils.generator import Generator, shared_arguments
|
|
18
17
|
|
19
18
|
@dataclass
|
20
19
|
class SummaryGenerator(Generator):
|
21
|
-
|
22
20
|
# ClassVars
|
23
21
|
generatorname = os.path.basename(__file__)
|
24
22
|
generatorversion = "0.1.1"
|
@@ -1,11 +1,10 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
3
|
from dataclasses import dataclass
|
4
|
-
from typing import
|
4
|
+
from typing import List
|
5
5
|
|
6
6
|
import click
|
7
|
-
from linkml_runtime.linkml_model.meta import
|
8
|
-
SchemaDefinition, SlotDefinition)
|
7
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
|
9
8
|
from linkml_runtime.utils.formatutils import be, camelcase, underscore
|
10
9
|
from terminusdb_client.woqlquery import WOQLQuery as WQ
|
11
10
|
|
@@ -35,6 +34,7 @@ XSD_Ok = {
|
|
35
34
|
]
|
36
35
|
}
|
37
36
|
|
37
|
+
|
38
38
|
@dataclass
|
39
39
|
class TerminusdbGenerator(Generator):
|
40
40
|
"""
|
@@ -61,17 +61,12 @@ class TerminusdbGenerator(Generator):
|
|
61
61
|
raw_additions: List = None
|
62
62
|
clswq: str = None
|
63
63
|
|
64
|
-
|
65
64
|
def visit_schema(self, inline: bool = False, **kwargs) -> None:
|
66
65
|
self.classes = []
|
67
66
|
self.raw_additions = []
|
68
67
|
|
69
68
|
def end_schema(self, **_) -> None:
|
70
|
-
print(
|
71
|
-
json.dumps(
|
72
|
-
WQ().woql_and(*self.classes, *self.raw_additions).to_dict(), indent=2
|
73
|
-
)
|
74
|
-
)
|
69
|
+
print(json.dumps(WQ().woql_and(*self.classes, *self.raw_additions).to_dict(), indent=2))
|
75
70
|
|
76
71
|
def visit_class(self, cls: ClassDefinition) -> bool:
|
77
72
|
self.clswq = (
|
@@ -86,8 +81,7 @@ class TerminusdbGenerator(Generator):
|
|
86
81
|
self.clswq.abstract()
|
87
82
|
if cls.broad_mappings:
|
88
83
|
if any(
|
89
|
-
str(self.namespaces.uri_for(m))
|
90
|
-
== "http://terminusdb.com/schema/system#Document"
|
84
|
+
str(self.namespaces.uri_for(m)) == "http://terminusdb.com/schema/system#Document"
|
91
85
|
for m in cls.broad_mappings
|
92
86
|
):
|
93
87
|
self.clswq.parent("Document")
|
@@ -107,11 +101,7 @@ class TerminusdbGenerator(Generator):
|
|
107
101
|
else:
|
108
102
|
rng = "xsd:string"
|
109
103
|
|
110
|
-
name =
|
111
|
-
f"{cls.name} {aliased_slot_name}"
|
112
|
-
if slot.is_usage_slot
|
113
|
-
else aliased_slot_name
|
114
|
-
)
|
104
|
+
name = f"{cls.name} {aliased_slot_name}" if slot.is_usage_slot else aliased_slot_name
|
115
105
|
|
116
106
|
# translate to terminusdb xsd builtins:
|
117
107
|
if rng == "xsd:int":
|
@@ -127,9 +117,7 @@ class TerminusdbGenerator(Generator):
|
|
127
117
|
f"Range {rng} is of type {type(rng)}."
|
128
118
|
)
|
129
119
|
|
130
|
-
self.clswq.property(
|
131
|
-
underscore(name), rng, label=name, description=slot.description
|
132
|
-
)
|
120
|
+
self.clswq.property(underscore(name), rng, label=name, description=slot.description)
|
133
121
|
if not slot.multivalued:
|
134
122
|
self.clswq.max(1)
|
135
123
|
if slot.required:
|
@@ -1,22 +1,15 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
|
-
from copy import deepcopy
|
4
3
|
from dataclasses import dataclass
|
5
|
-
from
|
6
|
-
from typing import (Callable, Dict, Iterator, List, Optional, Set, TextIO,
|
7
|
-
Tuple, Union)
|
4
|
+
from typing import List, Optional
|
8
5
|
|
9
6
|
import click
|
10
|
-
from jinja2 import
|
11
|
-
from linkml_runtime.dumpers import yaml_dumper
|
7
|
+
from jinja2 import Template
|
12
8
|
from linkml_runtime.linkml_model.meta import (
|
13
|
-
|
14
|
-
ClassDefinitionName,
|
15
|
-
|
16
|
-
EnumDefinition, SchemaDefinition,
|
9
|
+
ClassDefinition,
|
10
|
+
ClassDefinitionName,
|
11
|
+
Element,
|
17
12
|
SlotDefinition,
|
18
|
-
SlotDefinitionName,
|
19
|
-
TypeDefinition
|
20
13
|
)
|
21
14
|
from linkml_runtime.utils.formatutils import camelcase, underscore
|
22
15
|
from linkml_runtime.utils.schemaview import SchemaView
|
@@ -55,7 +48,7 @@ export enum {{e.name}} {
|
|
55
48
|
{% if pv.description -%}
|
56
49
|
/** {{pv.description}} */
|
57
50
|
{% endif -%}
|
58
|
-
{{pv.label}} = "{{pv.value}}",
|
51
|
+
{{pv.label}} = "{{pv.value}}",
|
59
52
|
{%- endfor %}
|
60
53
|
};
|
61
54
|
{% endfor %}
|
@@ -65,7 +58,7 @@ export enum {{e.name}} {
|
|
65
58
|
/**
|
66
59
|
* {{c.description}}
|
67
60
|
*/
|
68
|
-
{%- endif -%}
|
61
|
+
{%- endif -%}
|
69
62
|
{% set parents = gen.parents(c) %}
|
70
63
|
export interface {{gen.name(c)}} {%- if parents %} extends {{parents|join(', ')}} {%- endif %} {
|
71
64
|
{%- for sn in view.class_slots(c.name, direct=False) %}
|
@@ -137,9 +130,7 @@ class TypescriptGenerator(OOCodeGenerator):
|
|
137
130
|
else:
|
138
131
|
return None
|
139
132
|
|
140
|
-
def get_identifier_or_key_slot(
|
141
|
-
self, cn: ClassDefinitionName
|
142
|
-
) -> Optional[SlotDefinition]:
|
133
|
+
def get_identifier_or_key_slot(self, cn: ClassDefinitionName) -> Optional[SlotDefinition]:
|
143
134
|
sv = self.schemaview
|
144
135
|
id_slot = sv.get_identifier_slot(cn)
|
145
136
|
if id_slot:
|
@@ -194,13 +185,14 @@ class TypescriptGenerator(OOCodeGenerator):
|
|
194
185
|
def default_value_for_type(self, typ: str) -> str:
|
195
186
|
pass
|
196
187
|
|
188
|
+
|
197
189
|
@shared_arguments(TypescriptGenerator)
|
198
190
|
@click.version_option(__version__, "-V", "--version")
|
199
191
|
@click.command()
|
200
192
|
def cli(yamlfile, **args):
|
201
193
|
"""Generate typescript interfaces and types
|
202
194
|
|
203
|
-
See https://
|
195
|
+
See https://github.com/linkml/linkml-runtime.js
|
204
196
|
"""
|
205
197
|
gen = TypescriptGenerator(yamlfile, **args)
|
206
198
|
print(gen.serialize())
|
linkml/generators/yamlgen.py
CHANGED
@@ -3,10 +3,8 @@
|
|
3
3
|
"""
|
4
4
|
import os
|
5
5
|
from dataclasses import dataclass, field
|
6
|
-
from typing import TextIO, Union
|
7
6
|
|
8
7
|
import click
|
9
|
-
from linkml_runtime.linkml_model.meta import SchemaDefinition
|
10
8
|
from linkml_runtime.utils.yamlutils import as_yaml
|
11
9
|
|
12
10
|
from linkml._version import __version__
|
linkml/generators/yumlgen.py
CHANGED
@@ -3,20 +3,16 @@
|
|
3
3
|
https://yuml.me/diagram/scruffy/class/samples
|
4
4
|
|
5
5
|
"""
|
6
|
-
import logging
|
7
6
|
import os
|
8
7
|
from dataclasses import dataclass, field
|
9
|
-
from typing import Callable, List, Optional, Set,
|
8
|
+
from typing import Callable, List, Optional, Set, cast
|
10
9
|
|
11
10
|
import click
|
12
11
|
import requests
|
13
|
-
from linkml_runtime.linkml_model.meta import
|
14
|
-
ClassDefinitionName,
|
15
|
-
SchemaDefinition, SlotDefinition)
|
12
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionName, SlotDefinition
|
16
13
|
from linkml_runtime.utils.formatutils import camelcase, underscore
|
17
14
|
from rdflib import Namespace
|
18
15
|
|
19
|
-
from linkml._version import __version__
|
20
16
|
from linkml.utils.generator import Generator, shared_arguments
|
21
17
|
|
22
18
|
yuml_is_a = "^-"
|
@@ -41,34 +37,21 @@ class YumlGenerator(Generator):
|
|
41
37
|
valid_formats = ["yuml", "png", "pdf", "jpg", "json", "svg"]
|
42
38
|
visit_all_class_slots = False
|
43
39
|
|
44
|
-
referenced: Optional[
|
45
|
-
|
46
|
-
] = None #
|
47
|
-
generated: Optional[
|
48
|
-
Set[ClassDefinitionName]
|
49
|
-
] = None # List of classes that have been emitted
|
50
|
-
box_generated: Optional[
|
51
|
-
Set[ClassDefinitionName]
|
52
|
-
] = None # Class boxes that have been emitted
|
40
|
+
referenced: Optional[Set[ClassDefinitionName]] = None # List of classes that have to be emitted
|
41
|
+
generated: Optional[Set[ClassDefinitionName]] = None # List of classes that have been emitted
|
42
|
+
box_generated: Optional[Set[ClassDefinitionName]] = None # Class boxes that have been emitted
|
53
43
|
associations_generated: Optional[
|
54
44
|
Set[ClassDefinitionName]
|
55
45
|
] = None # Classes with associations generated
|
56
|
-
focus_classes: Optional[
|
57
|
-
|
58
|
-
] = None #
|
59
|
-
gen_classes: Optional[
|
60
|
-
Set[ClassDefinitionName]
|
61
|
-
] = None # Classes to be generated
|
62
|
-
output_file_name: Optional[
|
63
|
-
str
|
64
|
-
] = None # Location of output file if directory used
|
46
|
+
focus_classes: Optional[Set[ClassDefinitionName]] = None # Classes to be completely filled
|
47
|
+
gen_classes: Optional[Set[ClassDefinitionName]] = None # Classes to be generated
|
48
|
+
output_file_name: Optional[str] = None # Location of output file if directory used
|
65
49
|
|
66
50
|
classes: Set[ClassDefinitionName] = None
|
67
51
|
directory: Optional[str] = None
|
68
52
|
diagram_name: Optional[str] = None
|
69
53
|
load_image: bool = field(default_factory=lambda: True)
|
70
54
|
|
71
|
-
|
72
55
|
def visit_schema(
|
73
56
|
self,
|
74
57
|
classes: Set[ClassDefinitionName] = None,
|
@@ -94,22 +77,16 @@ class YumlGenerator(Generator):
|
|
94
77
|
self.generated = set()
|
95
78
|
yumlclassdef: List[str] = []
|
96
79
|
while self.referenced.difference(self.generated):
|
97
|
-
cn = sorted(list(self.referenced.difference(self.generated)), reverse=True)[
|
98
|
-
0
|
99
|
-
]
|
80
|
+
cn = sorted(list(self.referenced.difference(self.generated)), reverse=True)[0]
|
100
81
|
self.generated.add(cn)
|
101
|
-
assocs = self.class_associations(
|
102
|
-
ClassDefinitionName(cn), cn in self.referenced
|
103
|
-
)
|
82
|
+
assocs = self.class_associations(ClassDefinitionName(cn), cn in self.referenced)
|
104
83
|
if assocs:
|
105
84
|
yumlclassdef.append(assocs)
|
106
85
|
else:
|
107
86
|
yumlclassdef.append(self.class_box(ClassDefinitionName(cn)))
|
108
87
|
|
109
88
|
file_suffix = ".svg" if self.format == "yuml" else "." + self.format
|
110
|
-
file_name = diagram_name or camelcase(
|
111
|
-
sorted(classes)[0] if classes else self.schema.name
|
112
|
-
)
|
89
|
+
file_name = diagram_name or camelcase(sorted(classes)[0] if classes else self.schema.name)
|
113
90
|
if directory:
|
114
91
|
self.output_file_name = os.path.join(
|
115
92
|
directory,
|
@@ -118,7 +95,7 @@ class YumlGenerator(Generator):
|
|
118
95
|
if load_image:
|
119
96
|
payload = "dsl_text=" + (",".join(yumlclassdef))
|
120
97
|
payload = payload.replace("%3F", "?").replace("%2B", "+")
|
121
|
-
url =
|
98
|
+
url = "https://yuml.me/diagram/plain/class/"
|
122
99
|
resp = requests.post(url, data=payload)
|
123
100
|
if resp.ok:
|
124
101
|
filename = resp.text.strip().replace(".svg", file_suffix)
|
@@ -139,9 +116,7 @@ class YumlGenerator(Generator):
|
|
139
116
|
@return:
|
140
117
|
"""
|
141
118
|
slot_defs: List[str] = []
|
142
|
-
if cn not in self.box_generated and (
|
143
|
-
not self.focus_classes or cn in self.focus_classes
|
144
|
-
):
|
119
|
+
if cn not in self.box_generated and (not self.focus_classes or cn in self.focus_classes):
|
145
120
|
cls = self.schema.classes[cn]
|
146
121
|
for slot in self.filtered_cls_slots(
|
147
122
|
cn, all_slots=True, filtr=lambda s: s.range not in self.schema.classes
|
@@ -157,13 +132,9 @@ class YumlGenerator(Generator):
|
|
157
132
|
)
|
158
133
|
self.box_generated.add(cn)
|
159
134
|
self.referenced.add(cn)
|
160
|
-
return (
|
161
|
-
"[" + camelcase(cn) + ("|" + ";".join(slot_defs) if slot_defs else "") + "]"
|
162
|
-
)
|
135
|
+
return "[" + camelcase(cn) + ("|" + ";".join(slot_defs) if slot_defs else "") + "]"
|
163
136
|
|
164
|
-
def class_associations(
|
165
|
-
self, cn: ClassDefinitionName, must_render: bool = False
|
166
|
-
) -> str:
|
137
|
+
def class_associations(self, cn: ClassDefinitionName, must_render: bool = False) -> str:
|
167
138
|
"""Emit all associations for a focus class. If none are specified, all classes are generated
|
168
139
|
|
169
140
|
@param cn: Name of class to be emitted
|
@@ -184,10 +155,7 @@ class YumlGenerator(Generator):
|
|
184
155
|
cn, False, lambda s: s.range in self.schema.classes
|
185
156
|
)[::-1]:
|
186
157
|
# Swap the two boxes because, in the case of self reference, the last definition wins
|
187
|
-
if
|
188
|
-
not slot.range in self.associations_generated
|
189
|
-
and cn in slot.domain_of
|
190
|
-
):
|
158
|
+
if slot.range not in self.associations_generated and cn in slot.domain_of:
|
191
159
|
rhs = self.class_box(cn)
|
192
160
|
lhs = self.class_box(cast(ClassDefinitionName, slot.range))
|
193
161
|
assocs.append(
|
@@ -205,10 +173,7 @@ class YumlGenerator(Generator):
|
|
205
173
|
slot = self.schema.slots[slotname]
|
206
174
|
# Don't do self references twice
|
207
175
|
# Also, slot must be owned by the class
|
208
|
-
if
|
209
|
-
cls.name not in slot.domain_of
|
210
|
-
and cls.name not in self.associations_generated
|
211
|
-
):
|
176
|
+
if cls.name not in slot.domain_of and cls.name not in self.associations_generated:
|
212
177
|
for dom in [self.schema.classes[dof] for dof in slot.domain_of]:
|
213
178
|
assocs.append(
|
214
179
|
self.class_box(dom.name)
|
@@ -226,20 +191,14 @@ class YumlGenerator(Generator):
|
|
226
191
|
|
227
192
|
# Classes that use the class as a mixin
|
228
193
|
if cls.name in self.synopsis.mixinrefs:
|
229
|
-
for mixin in sorted(
|
230
|
-
self.synopsis.mixinrefs[cls.name].classrefs, reverse=True
|
231
|
-
):
|
194
|
+
for mixin in sorted(self.synopsis.mixinrefs[cls.name].classrefs, reverse=True):
|
232
195
|
assocs.append(
|
233
|
-
self.class_box(ClassDefinitionName(mixin))
|
234
|
-
+ yuml_uses
|
235
|
-
+ self.class_box(cn)
|
196
|
+
self.class_box(ClassDefinitionName(mixin)) + yuml_uses + self.class_box(cn)
|
236
197
|
)
|
237
198
|
|
238
199
|
# Classes that inject information
|
239
200
|
if cn in self.synopsis.applytos.classrefs:
|
240
|
-
for injector in sorted(
|
241
|
-
self.synopsis.applytorefs[cn].classrefs, reverse=True
|
242
|
-
):
|
201
|
+
for injector in sorted(self.synopsis.applytorefs[cn].classrefs, reverse=True):
|
243
202
|
assocs.append(
|
244
203
|
self.class_box(cn)
|
245
204
|
+ yuml_injected
|
@@ -249,9 +208,7 @@ class YumlGenerator(Generator):
|
|
249
208
|
|
250
209
|
# Children
|
251
210
|
if cn in self.synopsis.isarefs:
|
252
|
-
for is_a_cls in sorted(
|
253
|
-
self.synopsis.isarefs[cn].classrefs, reverse=True
|
254
|
-
):
|
211
|
+
for is_a_cls in sorted(self.synopsis.isarefs[cn].classrefs, reverse=True):
|
255
212
|
assocs.append(
|
256
213
|
self.class_box(cn)
|
257
214
|
+ yuml_is_a
|
@@ -280,7 +237,7 @@ class YumlGenerator(Generator):
|
|
280
237
|
self,
|
281
238
|
cn: ClassDefinitionName,
|
282
239
|
all_slots: bool = True,
|
283
|
-
filtr: Callable[[SlotDefinition], bool] =
|
240
|
+
filtr: Callable[[SlotDefinition], bool] = lambda: True,
|
284
241
|
) -> List[SlotDefinition]:
|
285
242
|
"""Return the set of slots associated with the class that meet the filter criteria. Slots will be returned
|
286
243
|
in defining order, with class slots returned last
|
@@ -290,9 +247,6 @@ class YumlGenerator(Generator):
|
|
290
247
|
@param filtr: Slot filter predicate
|
291
248
|
@return: List of slot definitions
|
292
249
|
"""
|
293
|
-
if filtr is None:
|
294
|
-
filtr = lambda x: True
|
295
|
-
|
296
250
|
rval = []
|
297
251
|
cls = self.schema.classes[cn]
|
298
252
|
cls_slots = self.all_slots(cls, cls_slots_first=True)
|
@@ -325,9 +279,7 @@ class YumlGenerator(Generator):
|
|
325
279
|
for a in sorted(self.synopsis.applytorefs[cls.name].classrefs)
|
326
280
|
]
|
327
281
|
]
|
328
|
-
return pk + (
|
329
|
-
"(a)" if injected else "(m)" if mixin else "(i)" if inherited else ""
|
330
|
-
)
|
282
|
+
return pk + ("(a)" if injected else "(m)" if mixin else "(i)" if inherited else "")
|
331
283
|
|
332
284
|
|
333
285
|
@shared_arguments(YumlGenerator)
|
linkml/linter/cli.py
CHANGED
@@ -9,8 +9,7 @@ import yaml
|
|
9
9
|
from linkml._version import __version__
|
10
10
|
|
11
11
|
from .config.datamodel.config import RuleLevel
|
12
|
-
from .formatters import
|
13
|
-
TsvFormatter)
|
12
|
+
from .formatters import JsonFormatter, MarkdownFormatter, TerminalFormatter, TsvFormatter
|
14
13
|
from .linter import Linter
|
15
14
|
|
16
15
|
YAML_SUFFIXES = [".yml", ".yaml"]
|
@@ -35,9 +34,7 @@ def get_yaml_files(root: Path) -> Iterable[str]:
|
|
35
34
|
@click.command()
|
36
35
|
@click.argument(
|
37
36
|
"schema",
|
38
|
-
type=click.Path(
|
39
|
-
exists=True, dir_okay=True, file_okay=True, resolve_path=True, path_type=Path
|
40
|
-
),
|
37
|
+
type=click.Path(exists=True, dir_okay=True, file_okay=True, resolve_path=True, path_type=Path),
|
41
38
|
)
|
42
39
|
@click.option(
|
43
40
|
"-c",
|
@@ -66,9 +63,7 @@ def get_yaml_files(root: Path) -> Iterable[str]:
|
|
66
63
|
help="Validate the schema against the LinkML Metamodel and then exit without checking linter rules.",
|
67
64
|
)
|
68
65
|
@click.option("-v", "--verbose", is_flag=True)
|
69
|
-
@click.option(
|
70
|
-
"-o", "--output", type=click.File("w"), default="-", help="Report file name."
|
71
|
-
)
|
66
|
+
@click.option("-o", "--output", type=click.File("w"), default="-", help="Report file name.")
|
72
67
|
@click.option(
|
73
68
|
"--ignore-warnings",
|
74
69
|
is_flag=True,
|
@@ -131,9 +126,7 @@ def main(
|
|
131
126
|
formatter.start_report()
|
132
127
|
for path in get_yaml_files(schema):
|
133
128
|
formatter.start_schema(path)
|
134
|
-
report = linter.lint(
|
135
|
-
path, fix=fix, validate_schema=validate, validate_only=validate_only
|
136
|
-
)
|
129
|
+
report = linter.lint(path, fix=fix, validate_schema=validate, validate_only=validate_only)
|
137
130
|
for problem in report:
|
138
131
|
if str(problem.level) is RuleLevel.error.text:
|
139
132
|
error_count += 1
|
@@ -7,26 +7,18 @@
|
|
7
7
|
# license: https://creativecommons.org/publicdomain/zero/1.0/
|
8
8
|
|
9
9
|
import dataclasses
|
10
|
-
import re
|
11
|
-
import sys
|
12
10
|
from dataclasses import dataclass
|
13
11
|
from typing import Any, ClassVar, Dict, List, Optional, Union
|
14
12
|
|
15
|
-
from jsonasobj2 import
|
16
|
-
from linkml_runtime.linkml_model.meta import
|
17
|
-
PvFormulaOptions)
|
18
|
-
from linkml_runtime.linkml_model.types import Boolean, String
|
13
|
+
from jsonasobj2 import as_dict
|
14
|
+
from linkml_runtime.linkml_model.meta import EnumDefinition, PermissibleValue
|
19
15
|
from linkml_runtime.utils.curienamespace import CurieNamespace
|
20
|
-
from linkml_runtime.utils.dataclass_extensions_376 import
|
21
|
-
dataclasses_init_fn_with_kwargs
|
16
|
+
from linkml_runtime.utils.dataclass_extensions_376 import dataclasses_init_fn_with_kwargs
|
22
17
|
from linkml_runtime.utils.enumerations import EnumDefinitionImpl
|
23
|
-
from linkml_runtime.utils.
|
24
|
-
from linkml_runtime.utils.metamodelcore import (Bool, bnode, empty_dict,
|
25
|
-
empty_list)
|
18
|
+
from linkml_runtime.utils.metamodelcore import Bool, empty_list
|
26
19
|
from linkml_runtime.utils.slot import Slot
|
27
|
-
from linkml_runtime.utils.yamlutils import
|
28
|
-
|
29
|
-
from rdflib import Namespace, URIRef
|
20
|
+
from linkml_runtime.utils.yamlutils import YAMLRoot
|
21
|
+
from rdflib import URIRef
|
30
22
|
|
31
23
|
metamodel_version = "1.7.0"
|
32
24
|
version = None
|
@@ -82,9 +74,7 @@ class Rules(YAMLRoot):
|
|
82
74
|
class_model_uri: ClassVar[URIRef] = LINTCFG.Rules
|
83
75
|
|
84
76
|
no_empty_title: Optional[Union[dict, "RuleConfig"]] = None
|
85
|
-
permissible_values_format: Optional[
|
86
|
-
Union[dict, "PermissibleValuesFormatRuleConfig"]
|
87
|
-
] = None
|
77
|
+
permissible_values_format: Optional[Union[dict, "PermissibleValuesFormatRuleConfig"]] = None
|
88
78
|
tree_root_class: Optional[Union[dict, "TreeRootClassRuleConfig"]] = None
|
89
79
|
recommended: Optional[Union[dict, "RecommendedRuleConfig"]] = None
|
90
80
|
no_xsd_int_type: Optional[Union[dict, "RuleConfig"]] = None
|
@@ -93,9 +83,7 @@ class Rules(YAMLRoot):
|
|
93
83
|
canonical_prefixes: Optional[Union[dict, "CanonicalPrefixesConfig"]] = None
|
94
84
|
|
95
85
|
def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
|
96
|
-
if self.no_empty_title is not None and not isinstance(
|
97
|
-
self.no_empty_title, RuleConfig
|
98
|
-
):
|
86
|
+
if self.no_empty_title is not None and not isinstance(self.no_empty_title, RuleConfig):
|
99
87
|
self.no_empty_title = RuleConfig(**as_dict(self.no_empty_title))
|
100
88
|
|
101
89
|
if self.permissible_values_format is not None and not isinstance(
|
@@ -108,26 +96,18 @@ class Rules(YAMLRoot):
|
|
108
96
|
if self.tree_root_class is not None and not isinstance(
|
109
97
|
self.tree_root_class, TreeRootClassRuleConfig
|
110
98
|
):
|
111
|
-
self.tree_root_class = TreeRootClassRuleConfig(
|
112
|
-
**as_dict(self.tree_root_class)
|
113
|
-
)
|
99
|
+
self.tree_root_class = TreeRootClassRuleConfig(**as_dict(self.tree_root_class))
|
114
100
|
|
115
|
-
if self.recommended is not None and not isinstance(
|
116
|
-
self.recommended, RecommendedRuleConfig
|
117
|
-
):
|
101
|
+
if self.recommended is not None and not isinstance(self.recommended, RecommendedRuleConfig):
|
118
102
|
self.recommended = RecommendedRuleConfig(**as_dict(self.recommended))
|
119
103
|
|
120
|
-
if self.no_xsd_int_type is not None and not isinstance(
|
121
|
-
self.no_xsd_int_type, RuleConfig
|
122
|
-
):
|
104
|
+
if self.no_xsd_int_type is not None and not isinstance(self.no_xsd_int_type, RuleConfig):
|
123
105
|
self.no_xsd_int_type = RuleConfig(**as_dict(self.no_xsd_int_type))
|
124
106
|
|
125
107
|
if self.no_invalid_slot_usage is not None and not isinstance(
|
126
108
|
self.no_invalid_slot_usage, RuleConfig
|
127
109
|
):
|
128
|
-
self.no_invalid_slot_usage = RuleConfig(
|
129
|
-
**as_dict(self.no_invalid_slot_usage)
|
130
|
-
)
|
110
|
+
self.no_invalid_slot_usage = RuleConfig(**as_dict(self.no_invalid_slot_usage))
|
131
111
|
|
132
112
|
if self.standard_naming is not None and not isinstance(
|
133
113
|
self.standard_naming, StandardNamingConfig
|
@@ -137,9 +117,7 @@ class Rules(YAMLRoot):
|
|
137
117
|
if self.canonical_prefixes is not None and not isinstance(
|
138
118
|
self.canonical_prefixes, CanonicalPrefixesConfig
|
139
119
|
):
|
140
|
-
self.canonical_prefixes = CanonicalPrefixesConfig(
|
141
|
-
**as_dict(self.canonical_prefixes)
|
142
|
-
)
|
120
|
+
self.canonical_prefixes = CanonicalPrefixesConfig(**as_dict(self.canonical_prefixes))
|
143
121
|
|
144
122
|
super().__post_init__(**kwargs)
|
145
123
|
|
@@ -209,9 +187,7 @@ class TreeRootClassRuleConfig(RuleConfig):
|
|
209
187
|
validate_existing_class_name: Optional[Union[bool, Bool]] = None
|
210
188
|
|
211
189
|
def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
|
212
|
-
if self.root_class_name is not None and not isinstance(
|
213
|
-
self.root_class_name, str
|
214
|
-
):
|
190
|
+
if self.root_class_name is not None and not isinstance(self.root_class_name, str):
|
215
191
|
self.root_class_name = str(self.root_class_name)
|
216
192
|
|
217
193
|
if self.validate_existing_class_name is not None and not isinstance(
|
@@ -271,9 +247,7 @@ class StandardNamingConfig(RuleConfig):
|
|
271
247
|
if self.permissible_values_upper_case is not None and not isinstance(
|
272
248
|
self.permissible_values_upper_case, Bool
|
273
249
|
):
|
274
|
-
self.permissible_values_upper_case = Bool(
|
275
|
-
self.permissible_values_upper_case
|
276
|
-
)
|
250
|
+
self.permissible_values_upper_case = Bool(self.permissible_values_upper_case)
|
277
251
|
|
278
252
|
super().__post_init__(**kwargs)
|
279
253
|
|
@@ -297,9 +271,7 @@ class CanonicalPrefixesConfig(RuleConfig):
|
|
297
271
|
def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
|
298
272
|
if not isinstance(self.prefixmaps_contexts, list):
|
299
273
|
self.prefixmaps_contexts = (
|
300
|
-
[self.prefixmaps_contexts]
|
301
|
-
if self.prefixmaps_contexts is not None
|
302
|
-
else []
|
274
|
+
[self.prefixmaps_contexts] if self.prefixmaps_contexts is not None else []
|
303
275
|
)
|
304
276
|
self.prefixmaps_contexts = [
|
305
277
|
v if isinstance(v, str) else str(v) for v in self.prefixmaps_contexts
|
@@ -329,9 +301,7 @@ class RuleLevel(EnumDefinitionImpl):
|
|
329
301
|
The permissible values for the `level` option of all rules
|
330
302
|
"""
|
331
303
|
|
332
|
-
disabled = PermissibleValue(
|
333
|
-
text="disabled", description="The rule will not be checked"
|
334
|
-
)
|
304
|
+
disabled = PermissibleValue(text="disabled", description="The rule will not be checked")
|
335
305
|
warning = PermissibleValue(
|
336
306
|
text="warning",
|
337
307
|
description="A violation of a rule at this level is a minor issue that should be fixed",
|
linkml/linter/linter.py
CHANGED
@@ -70,9 +70,7 @@ class Linter:
|
|
70
70
|
default_config = deepcopy(get_named_config("default"))
|
71
71
|
merged_config = config
|
72
72
|
if config.get("extends") == ExtendableConfigs.recommended.text:
|
73
|
-
recommended_config = deepcopy(
|
74
|
-
get_named_config(ExtendableConfigs.recommended.text)
|
75
|
-
)
|
73
|
+
recommended_config = deepcopy(get_named_config(ExtendableConfigs.recommended.text))
|
76
74
|
merged_config = merge_configs(recommended_config, merged_config)
|
77
75
|
merged_config = merge_configs(default_config, merged_config)
|
78
76
|
self.config = Config(**merged_config)
|
@@ -119,7 +117,7 @@ class Linter:
|
|
119
117
|
|
120
118
|
try:
|
121
119
|
schema_view = SchemaView(schema)
|
122
|
-
except:
|
120
|
+
except Exception:
|
123
121
|
if not validate_schema:
|
124
122
|
yield LinterProblem(
|
125
123
|
message="File is not a valid LinkML schema. Use --validate for more details.",
|