linkml 1.6.7__py3-none-any.whl → 1.6.9__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 +4 -0
- linkml/generators/docgen/class_diagram.md.jinja2 +4 -4
- linkml/generators/docgen.py +9 -2
- linkml/generators/jsonschemagen.py +80 -53
- linkml/generators/pydanticgen.py +19 -3
- linkml/generators/shexgen.py +19 -1
- linkml/generators/typescriptgen.py +2 -2
- linkml/linter/cli.py +6 -2
- linkml/linter/linter.py +3 -3
- linkml/utils/datautils.py +4 -4
- linkml/validator/plugins/jsonschema_validation_plugin.py +1 -3
- linkml/validator/validation_context.py +16 -12
- linkml/validators/jsonschemavalidator.py +2 -1
- {linkml-1.6.7.dist-info → linkml-1.6.9.dist-info}/METADATA +1 -2
- {linkml-1.6.7.dist-info → linkml-1.6.9.dist-info}/RECORD +18 -18
- {linkml-1.6.7.dist-info → linkml-1.6.9.dist-info}/LICENSE +0 -0
- {linkml-1.6.7.dist-info → linkml-1.6.9.dist-info}/WHEEL +0 -0
- {linkml-1.6.7.dist-info → linkml-1.6.9.dist-info}/entry_points.txt +0 -0
@@ -33,6 +33,10 @@ URI: {{ gen.uri_link(element) }}
|
|
33
33
|
```{{ gen.mermaid_directive() }}
|
34
34
|
{{ gen.mermaid_diagram([element.name]) }}
|
35
35
|
```
|
36
|
+
{% elif diagram_type == "plantuml_class_diagram" %}
|
37
|
+
```puml
|
38
|
+
{{ gen.mermaid_diagram([element.name]) }}
|
39
|
+
```
|
36
40
|
{% else %}
|
37
41
|
{% include "class_diagram.md.jinja2" %}
|
38
42
|
{% endif %}
|
@@ -13,7 +13,7 @@
|
|
13
13
|
{% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
|
14
14
|
{{ gen.name(element) }} : {{gen.name(s)}}
|
15
15
|
{% if s.range not in gen.all_type_object_names() %}
|
16
|
-
{{ gen.name(element) }}
|
16
|
+
{{ gen.name(element) }} --> {{ s.range }} : {{ gen.name(s) }}
|
17
17
|
{% endif %}
|
18
18
|
{% endfor %}
|
19
19
|
```
|
@@ -27,7 +27,7 @@
|
|
27
27
|
{% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
|
28
28
|
{{ gen.name(element) }} : {{gen.name(s)}}
|
29
29
|
{% if s.range not in gen.all_type_object_names() %}
|
30
|
-
{{ gen.name(element) }}
|
30
|
+
{{ gen.name(element) }} --> {{ s.range }} : {{ gen.name(s) }}
|
31
31
|
{% endif %}
|
32
32
|
{% endfor %}
|
33
33
|
```
|
@@ -41,7 +41,7 @@
|
|
41
41
|
{% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
|
42
42
|
{{ gen.name(element) }} : {{gen.name(s)}}
|
43
43
|
{% if s.range not in gen.all_type_object_names() %}
|
44
|
-
{{ gen.name(element) }}
|
44
|
+
{{ gen.name(element) }} --> {{ s.range }} : {{ gen.name(s) }}
|
45
45
|
{% endif %}
|
46
46
|
{% endfor %}
|
47
47
|
```
|
@@ -52,7 +52,7 @@
|
|
52
52
|
{% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
|
53
53
|
{{ gen.name(element) }} : {{gen.name(s)}}
|
54
54
|
{% if s.range not in gen.all_type_object_names() %}
|
55
|
-
{{ gen.name(element) }}
|
55
|
+
{{ gen.name(element) }} --> {{ s.range }} : {{ gen.name(s) }}
|
56
56
|
{% endif %}
|
57
57
|
{% endfor %}
|
58
58
|
```
|
linkml/generators/docgen.py
CHANGED
@@ -28,6 +28,7 @@ from linkml_runtime.utils.schemaview import SchemaView
|
|
28
28
|
|
29
29
|
from linkml._version import __version__
|
30
30
|
from linkml.generators.erdiagramgen import ERDiagramGenerator
|
31
|
+
from linkml.generators.plantumlgen import PlantumlGenerator
|
31
32
|
from linkml.utils.generator import Generator, shared_arguments
|
32
33
|
from linkml.workspaces.example_runner import ExampleRunner
|
33
34
|
|
@@ -38,7 +39,8 @@ class MarkdownDialect(Enum):
|
|
38
39
|
|
39
40
|
|
40
41
|
class DiagramType(Enum):
|
41
|
-
|
42
|
+
mermaid_class_diagram = "mermaid_class_diagram"
|
43
|
+
plantuml_class_diagram = "plantuml_class_diagram"
|
42
44
|
er_diagram = "er_diagram"
|
43
45
|
|
44
46
|
|
@@ -593,8 +595,13 @@ class DocGenerator(Generator):
|
|
593
595
|
return erdgen.serialize_classes(class_names, follow_references=True, max_hops=2)
|
594
596
|
else:
|
595
597
|
return erdgen.serialize()
|
596
|
-
elif self.diagram_type.value == DiagramType.
|
598
|
+
elif self.diagram_type.value == DiagramType.mermaid_class_diagram.value:
|
597
599
|
self.logger.info("This is currently handled in the jinja templates")
|
600
|
+
elif self.diagram_type.value == DiagramType.plantuml_class_diagram.value:
|
601
|
+
plantumlgen = PlantumlGenerator(self.schema)
|
602
|
+
plantuml_diagram = plantumlgen.serialize(classes=class_names)
|
603
|
+
self.logger.debug(f"Created PlantUML diagram for class: {class_names}")
|
604
|
+
return plantuml_diagram
|
598
605
|
else:
|
599
606
|
raise NotImplementedError(f"Diagram type {self.diagram_type} not implemented")
|
600
607
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
3
|
import os
|
4
|
-
from collections import UserDict
|
5
4
|
from copy import deepcopy
|
6
5
|
from dataclasses import dataclass, field
|
7
6
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
@@ -43,7 +42,7 @@ json_schema_types: Dict[str, Tuple[str, Optional[str]]] = {
|
|
43
42
|
}
|
44
43
|
|
45
44
|
|
46
|
-
class JsonSchema(
|
45
|
+
class JsonSchema(dict):
|
47
46
|
OPTIONAL_IDENTIFIER_SUFFIX = "__identifier_optional"
|
48
47
|
|
49
48
|
def __init__(self, *args, **kwargs):
|
@@ -83,7 +82,9 @@ class JsonSchema(UserDict):
|
|
83
82
|
lax_cls["required"].remove(identifier_name)
|
84
83
|
self["$defs"][canonical_name + self.OPTIONAL_IDENTIFIER_SUFFIX] = lax_cls
|
85
84
|
|
86
|
-
def add_property(
|
85
|
+
def add_property(
|
86
|
+
self, name: str, subschema: "JsonSchema", *, value_required: bool = False, value_disallowed: bool = False
|
87
|
+
) -> None:
|
87
88
|
canonical_name = underscore(name)
|
88
89
|
|
89
90
|
if "properties" not in self:
|
@@ -91,12 +92,32 @@ class JsonSchema(UserDict):
|
|
91
92
|
|
92
93
|
self["properties"][canonical_name] = subschema
|
93
94
|
|
94
|
-
if
|
95
|
+
if value_required:
|
95
96
|
if "required" not in self:
|
96
97
|
self["required"] = []
|
97
98
|
|
98
99
|
self["required"].append(canonical_name)
|
99
100
|
|
101
|
+
# JSON Schema does not have a very natural way to express that a property cannot be present.
|
102
|
+
# The apparent best way to do it is to use:
|
103
|
+
# {
|
104
|
+
# properties: {
|
105
|
+
# foo: ...
|
106
|
+
# },
|
107
|
+
# not: {
|
108
|
+
# required: ['foo']
|
109
|
+
# }
|
110
|
+
# }
|
111
|
+
# The {required: [foo]} subschema evaluates to true if the foo property is present with any
|
112
|
+
# value. Wrapping that in a `not` keyword inverts that condition.
|
113
|
+
if value_disallowed:
|
114
|
+
if "not" not in self:
|
115
|
+
self["not"] = {}
|
116
|
+
if "required" not in self["not"]:
|
117
|
+
self["not"]["required"] = []
|
118
|
+
|
119
|
+
self["not"]["required"].append(canonical_name)
|
120
|
+
|
100
121
|
def add_keyword(self, keyword: str, value: Any):
|
101
122
|
if value is None:
|
102
123
|
return
|
@@ -112,7 +133,7 @@ class JsonSchema(UserDict):
|
|
112
133
|
return self.get("type") == "object"
|
113
134
|
|
114
135
|
def to_json(self, **kwargs) -> str:
|
115
|
-
return json.dumps(self
|
136
|
+
return json.dumps(self, **kwargs)
|
116
137
|
|
117
138
|
@classmethod
|
118
139
|
def ref_for(cls, class_name: Union[str, List[str]], identifier_optional: bool = False):
|
@@ -190,7 +211,7 @@ class JsonSchemaGenerator(Generator):
|
|
190
211
|
|
191
212
|
self.top_level_schema = JsonSchema(
|
192
213
|
{
|
193
|
-
"$schema": "
|
214
|
+
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
194
215
|
"$id": self.schema.id,
|
195
216
|
"metamodel_version": metamodel_version,
|
196
217
|
"version": self.schema.version if self.schema.version else None,
|
@@ -204,13 +225,15 @@ class JsonSchemaGenerator(Generator):
|
|
204
225
|
if cls.mixin or cls.abstract:
|
205
226
|
return
|
206
227
|
|
228
|
+
subschema_type = "object"
|
207
229
|
additional_properties = False
|
208
230
|
if self.is_class_unconstrained(cls):
|
231
|
+
subschema_type = ["null", "boolean", "object", "number", "string"]
|
209
232
|
additional_properties = True
|
210
233
|
|
211
234
|
class_subschema = JsonSchema(
|
212
235
|
{
|
213
|
-
"type":
|
236
|
+
"type": subschema_type,
|
214
237
|
"additionalProperties": additional_properties,
|
215
238
|
"description": be(cls.description),
|
216
239
|
}
|
@@ -220,42 +243,44 @@ class JsonSchemaGenerator(Generator):
|
|
220
243
|
self.handle_class_slot(subschema=class_subschema, cls=cls, slot=slot_definition)
|
221
244
|
|
222
245
|
rule_subschemas = []
|
223
|
-
for
|
224
|
-
|
246
|
+
for ancestor_class_name in self.schemaview.class_ancestors(cls.name):
|
247
|
+
ancestor_class = self.schemaview.get_class(ancestor_class_name)
|
248
|
+
for rule in ancestor_class.rules:
|
249
|
+
subschema = JsonSchema()
|
225
250
|
|
226
|
-
|
227
|
-
|
228
|
-
|
251
|
+
open_world = rule.open_world
|
252
|
+
if open_world is None:
|
253
|
+
open_world = False
|
229
254
|
|
230
|
-
|
231
|
-
|
232
|
-
|
255
|
+
if_subschema = self.get_subschema_for_anonymous_class(rule.preconditions, properties_required=True)
|
256
|
+
if if_subschema:
|
257
|
+
subschema["if"] = if_subschema
|
233
258
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
259
|
+
then_subschema = self.get_subschema_for_anonymous_class(
|
260
|
+
rule.postconditions, properties_required=not open_world
|
261
|
+
)
|
262
|
+
if then_subschema:
|
263
|
+
subschema["then"] = then_subschema
|
239
264
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
265
|
+
# same as required requirements as postconditions?
|
266
|
+
else_subschema = self.get_subschema_for_anonymous_class(
|
267
|
+
rule.elseconditions, properties_required=not open_world
|
268
|
+
)
|
269
|
+
if else_subschema:
|
270
|
+
subschema["else"] = else_subschema
|
246
271
|
|
247
|
-
|
272
|
+
rule_subschemas.append(subschema)
|
248
273
|
|
249
|
-
|
250
|
-
|
274
|
+
if rule.bidirectional:
|
275
|
+
inverse_subschema = JsonSchema()
|
251
276
|
|
252
|
-
|
253
|
-
|
277
|
+
if then_subschema:
|
278
|
+
inverse_subschema["if"] = then_subschema
|
254
279
|
|
255
|
-
|
256
|
-
|
280
|
+
if if_subschema:
|
281
|
+
inverse_subschema["then"] = if_subschema
|
257
282
|
|
258
|
-
|
283
|
+
rule_subschemas.append(inverse_subschema)
|
259
284
|
|
260
285
|
if len(rule_subschemas) == 1:
|
261
286
|
class_subschema.update(rule_subschemas[0])
|
@@ -285,20 +310,20 @@ class JsonSchemaGenerator(Generator):
|
|
285
310
|
subschema = JsonSchema()
|
286
311
|
for slot in cls.slot_conditions.values():
|
287
312
|
prop = self.get_subschema_for_slot(slot, omit_type=True)
|
313
|
+
value_required = False
|
314
|
+
value_disallowed = False
|
288
315
|
if slot.value_presence:
|
289
316
|
if slot.value_presence == PresenceEnum(PresenceEnum.PRESENT):
|
290
|
-
|
317
|
+
value_required = True
|
291
318
|
elif slot.value_presence == PresenceEnum(PresenceEnum.ABSENT):
|
292
|
-
|
293
|
-
# make the slot unsatisfiable
|
294
|
-
prop["enum"] = []
|
295
|
-
else:
|
296
|
-
this_properties_required = False
|
319
|
+
value_disallowed = True
|
297
320
|
elif slot.required is not None:
|
298
|
-
|
321
|
+
value_required = slot.required
|
299
322
|
else:
|
300
|
-
|
301
|
-
subschema.add_property(
|
323
|
+
value_required = properties_required
|
324
|
+
subschema.add_property(
|
325
|
+
self.aliased_slot_name(slot), prop, value_required=value_required, value_disallowed=value_disallowed
|
326
|
+
)
|
302
327
|
|
303
328
|
if cls.any_of is not None and len(cls.any_of) > 0:
|
304
329
|
subschema["anyOf"] = [self.get_subschema_for_anonymous_class(c, properties_required) for c in cls.any_of]
|
@@ -343,7 +368,9 @@ class JsonSchemaGenerator(Generator):
|
|
343
368
|
enum_schema["enum"] = permissible_values_texts
|
344
369
|
self.top_level_schema.add_def(enum.name, enum_schema)
|
345
370
|
|
346
|
-
def get_type_info_for_slot_subschema(
|
371
|
+
def get_type_info_for_slot_subschema(
|
372
|
+
self, slot: Union[SlotDefinition, AnonymousSlotExpression]
|
373
|
+
) -> Tuple[str, str, Union[str, List[str]]]:
|
347
374
|
# JSON Schema type (https://json-schema.org/understanding-json-schema/reference/type.html)
|
348
375
|
typ = None
|
349
376
|
# Reference to a JSON schema entity (https://json-schema.org/understanding-json-schema/structuring.html#ref)
|
@@ -379,7 +406,7 @@ class JsonSchemaGenerator(Generator):
|
|
379
406
|
|
380
407
|
return (typ, fmt, reference)
|
381
408
|
|
382
|
-
def get_value_constraints_for_slot(self, slot: Union[AnonymousSlotExpression, None]) -> JsonSchema:
|
409
|
+
def get_value_constraints_for_slot(self, slot: Union[SlotDefinition, AnonymousSlotExpression, None]) -> JsonSchema:
|
383
410
|
if slot is None:
|
384
411
|
return JsonSchema()
|
385
412
|
|
@@ -397,11 +424,6 @@ class JsonSchemaGenerator(Generator):
|
|
397
424
|
constraints.add_keyword("maximum", slot.maximum_value)
|
398
425
|
constraints.add_keyword("const", slot.equals_string)
|
399
426
|
constraints.add_keyword("const", slot.equals_number)
|
400
|
-
if slot.value_presence:
|
401
|
-
if slot.value_presence == PresenceEnum(PresenceEnum.PRESENT):
|
402
|
-
constraints.add_keyword("required", True)
|
403
|
-
elif slot.value_presence == PresenceEnum(PresenceEnum.ABSENT):
|
404
|
-
constraints.add_keyword("enum", [])
|
405
427
|
return constraints
|
406
428
|
|
407
429
|
def get_subschema_for_slot(self, slot: SlotDefinition, omit_type: bool = False) -> JsonSchema:
|
@@ -503,17 +525,22 @@ class JsonSchemaGenerator(Generator):
|
|
503
525
|
|
504
526
|
def handle_class_slot(self, subschema: JsonSchema, cls: ClassDefinition, slot: SlotDefinition) -> None:
|
505
527
|
class_id_slot = self.schemaview.get_identifier_slot(cls.name, use_key=True)
|
506
|
-
|
528
|
+
value_required = (
|
529
|
+
slot.required or slot == class_id_slot or slot.value_presence == PresenceEnum(PresenceEnum.PRESENT)
|
530
|
+
)
|
531
|
+
value_disallowed = slot.value_presence == PresenceEnum(PresenceEnum.ABSENT)
|
507
532
|
|
508
533
|
aliased_slot_name = self.aliased_slot_name(slot)
|
509
534
|
prop = self.get_subschema_for_slot(slot)
|
510
|
-
subschema.add_property(
|
535
|
+
subschema.add_property(
|
536
|
+
aliased_slot_name, prop, value_required=value_required, value_disallowed=value_disallowed
|
537
|
+
)
|
511
538
|
|
512
539
|
if slot.designates_type:
|
513
540
|
type_value = get_type_designator_value(self.schemaview, slot, cls)
|
514
541
|
prop["enum"] = [type_value]
|
515
542
|
|
516
|
-
def generate(self) ->
|
543
|
+
def generate(self) -> JsonSchema:
|
517
544
|
self.start_schema()
|
518
545
|
for enum_definition in self.schemaview.all_enums().values():
|
519
546
|
self.handle_enum(enum_definition)
|
linkml/generators/pydanticgen.py
CHANGED
@@ -43,6 +43,9 @@ def default_template(pydantic_ver: str = "1", extra_fields: str = "forbid") -> s
|
|
43
43
|
from __future__ import annotations
|
44
44
|
from datetime import datetime, date
|
45
45
|
from enum import Enum
|
46
|
+
{% if uses_numpy -%}
|
47
|
+
import numpy as np
|
48
|
+
{%- endif %}
|
46
49
|
from typing import List, Dict, Optional, Any, Union"""
|
47
50
|
if pydantic_ver == "1":
|
48
51
|
template += """
|
@@ -86,7 +89,9 @@ class ConfiguredBaseModel(BaseModel):
|
|
86
89
|
extra = '{extra_fields}',
|
87
90
|
arbitrary_types_allowed=True,
|
88
91
|
use_enum_values = True)
|
92
|
+
pass
|
89
93
|
"""
|
94
|
+
|
90
95
|
### ENUMS ###
|
91
96
|
template += """
|
92
97
|
{% for e in enums.values() %}
|
@@ -157,7 +162,7 @@ class {{ c.name }}
|
|
157
162
|
raise ValueError(f"Invalid {{attr.name}} format: {v}")
|
158
163
|
return v
|
159
164
|
{% endif -%}
|
160
|
-
{% endfor %}
|
165
|
+
{% endfor %}
|
161
166
|
{% endfor %}
|
162
167
|
"""
|
163
168
|
elif pydantic_ver == "2":
|
@@ -209,7 +214,7 @@ class {{ c.name }}
|
|
209
214
|
raise ValueError(f"Invalid {{attr.name}} format: {v}")
|
210
215
|
return v
|
211
216
|
{% endif -%}
|
212
|
-
{% endfor %}
|
217
|
+
{% endfor %}
|
213
218
|
{% endfor %}
|
214
219
|
"""
|
215
220
|
|
@@ -344,6 +349,8 @@ class PydanticGenerator(OOCodeGenerator):
|
|
344
349
|
# Multivalued slots that are either not inlined (just an identifier) or are
|
345
350
|
# inlined as lists should get default_factory list, if they're inlined but
|
346
351
|
# not as a list, that means a dictionary
|
352
|
+
elif "linkml:elements" in slot.implements:
|
353
|
+
slot_values[camelcase(class_def.name)][slot.name] = None
|
347
354
|
elif slot.multivalued:
|
348
355
|
has_identifier_slot = self.range_class_has_identifier_slot(slot)
|
349
356
|
|
@@ -535,6 +542,8 @@ class PydanticGenerator(OOCodeGenerator):
|
|
535
542
|
)
|
536
543
|
enums = self.generate_enums(sv.all_enums())
|
537
544
|
|
545
|
+
uses_numpy = False
|
546
|
+
|
538
547
|
sorted_classes = self.sort_classes(list(sv.all_classes().values()))
|
539
548
|
self.sorted_class_names = [camelcase(c.name) for c in sorted_classes]
|
540
549
|
|
@@ -587,7 +596,13 @@ class PydanticGenerator(OOCodeGenerator):
|
|
587
596
|
else:
|
588
597
|
raise Exception(f"Could not generate python range for {class_name}.{s.name}")
|
589
598
|
|
590
|
-
if s.
|
599
|
+
if "linkml:elements" in s.implements:
|
600
|
+
# TODO add support for xarray
|
601
|
+
pyrange = "np.ndarray"
|
602
|
+
if "linkml:ColumnOrderedArray" in class_def.implements:
|
603
|
+
raise NotImplementedError("Cannot generate Pydantic code for ColumnOrderedArrays.")
|
604
|
+
uses_numpy = True
|
605
|
+
elif s.multivalued:
|
591
606
|
if s.inlined or s.inlined_as_list:
|
592
607
|
collection_key = self.generate_collection_key(slot_ranges, s, class_def)
|
593
608
|
else:
|
@@ -609,6 +624,7 @@ class PydanticGenerator(OOCodeGenerator):
|
|
609
624
|
metamodel_version=self.schema.metamodel_version,
|
610
625
|
version=self.schema.version,
|
611
626
|
class_isa_plus_mixins=self.get_class_isa_plus_mixins(),
|
627
|
+
uses_numpy=uses_numpy,
|
612
628
|
)
|
613
629
|
return code
|
614
630
|
|
linkml/generators/shexgen.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
"""
|
4
4
|
import os
|
5
|
+
import urllib.parse as urlparse
|
5
6
|
from dataclasses import dataclass, field
|
6
7
|
from typing import List, Optional, Union
|
7
8
|
|
@@ -139,7 +140,24 @@ class ShExGenerator(Generator):
|
|
139
140
|
constraint.predicate = self.namespaces.uri_for(slot.slot_uri)
|
140
141
|
constraint.min = int(bool(slot.required))
|
141
142
|
constraint.max = 1 if not slot.multivalued else -1
|
142
|
-
|
143
|
+
if slot.range in self.schema.enums:
|
144
|
+
# Handle permissible values from enums
|
145
|
+
enum = self.schema.enums[slot.range]
|
146
|
+
values = []
|
147
|
+
for value in enum.permissible_values.values():
|
148
|
+
if value.meaning:
|
149
|
+
values.append(self.namespaces.uri_for(value.meaning))
|
150
|
+
else:
|
151
|
+
value_uri = f"{self._class_or_type_uri(enum.name)}#{urlparse.quote(value.text)}"
|
152
|
+
values.append(value_uri)
|
153
|
+
if values:
|
154
|
+
node_constraint = NodeConstraint(
|
155
|
+
# id=self._class_or_type_uri(slot.range),
|
156
|
+
values=values,
|
157
|
+
)
|
158
|
+
constraint.valueExpr = node_constraint
|
159
|
+
else:
|
160
|
+
constraint.valueExpr = self._class_or_type_uri(slot.range)
|
143
161
|
|
144
162
|
def end_schema(self, output: Optional[str] = None, **_) -> None:
|
145
163
|
self.shex.shapes = self.shapes if self.shapes else [Shape()]
|
@@ -84,11 +84,11 @@ export function is{{gen.name(c)}}(o: object): o is {{gen.name(c)}} {
|
|
84
84
|
{%- set rcs = gen.required_slots(c) %}
|
85
85
|
{%- set comp = "&&" if rcs else "||" %}
|
86
86
|
{%- set cs = rcs if rcs else view.class_slots(c.name, direct=False) %}
|
87
|
-
return
|
87
|
+
return (
|
88
88
|
{%- for sn in cs %}
|
89
89
|
'{{sn}}' in o {%- if not loop.last %} {{comp}}{% endif -%}
|
90
90
|
{%- endfor %}
|
91
|
-
|
91
|
+
)
|
92
92
|
}
|
93
93
|
|
94
94
|
export function to{{gen.name(c)}}(o: {{gen.name(c)}}): {{gen.name(c)}} {
|
linkml/linter/cli.py
CHANGED
@@ -16,7 +16,7 @@ YAML_SUFFIXES = [".yml", ".yaml"]
|
|
16
16
|
DEFAULT_CONFIG_FILES = [".linkmllint.yaml", ".linkmllint.yml"]
|
17
17
|
|
18
18
|
|
19
|
-
def get_yaml_files(root: Path) -> Iterable[str]:
|
19
|
+
def get_yaml_files(root: Path, accept_dot_files: bool) -> Iterable[str]:
|
20
20
|
if root.is_file():
|
21
21
|
if root.suffix not in YAML_SUFFIXES:
|
22
22
|
raise click.UsageError("SCHEMA must be a YAML file")
|
@@ -26,6 +26,8 @@ def get_yaml_files(root: Path) -> Iterable[str]:
|
|
26
26
|
for file in files:
|
27
27
|
if file in DEFAULT_CONFIG_FILES:
|
28
28
|
continue
|
29
|
+
if file.startswith(".") and not accept_dot_files:
|
30
|
+
continue
|
29
31
|
path = Path(dir, file)
|
30
32
|
if path.suffix in YAML_SUFFIXES:
|
31
33
|
yield str(path)
|
@@ -36,6 +38,7 @@ def get_yaml_files(root: Path) -> Iterable[str]:
|
|
36
38
|
"schema",
|
37
39
|
type=click.Path(exists=True, dir_okay=True, file_okay=True, resolve_path=True, path_type=Path),
|
38
40
|
)
|
41
|
+
@click.option("-a", "--all", is_flag=True, default=False, help="Process files that start with '.'.")
|
39
42
|
@click.option(
|
40
43
|
"-c",
|
41
44
|
"--config",
|
@@ -82,6 +85,7 @@ def get_yaml_files(root: Path) -> Iterable[str]:
|
|
82
85
|
def main(
|
83
86
|
schema: Path,
|
84
87
|
fix: bool,
|
88
|
+
all: bool,
|
85
89
|
config: str,
|
86
90
|
format: str,
|
87
91
|
validate: bool,
|
@@ -124,7 +128,7 @@ def main(
|
|
124
128
|
error_count = 0
|
125
129
|
warning_count = 0
|
126
130
|
formatter.start_report()
|
127
|
-
for path in get_yaml_files(schema):
|
131
|
+
for path in get_yaml_files(schema, all):
|
128
132
|
formatter.start_schema(path)
|
129
133
|
report = linter.lint(path, fix=fix, validate_schema=validate, validate_only=validate_only)
|
130
134
|
for problem in report:
|
linkml/linter/linter.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import inspect
|
2
|
-
import json
|
3
2
|
from copy import deepcopy
|
4
3
|
from dataclasses import dataclass
|
5
4
|
from functools import lru_cache
|
@@ -38,8 +37,9 @@ def get_named_config(name: str) -> Dict[str, Any]:
|
|
38
37
|
@lru_cache
|
39
38
|
def get_metamodel_validator() -> jsonschema.Validator:
|
40
39
|
meta_json_gen = JsonSchemaGenerator(LOCAL_METAMODEL_YAML_FILE, not_closed=False)
|
41
|
-
meta_json_schema =
|
42
|
-
|
40
|
+
meta_json_schema = meta_json_gen.generate()
|
41
|
+
validator_cls = jsonschema.validators.validator_for(meta_json_schema, default=jsonschema.Draft7Validator)
|
42
|
+
validator = validator_cls(meta_json_schema, format_checker=validator_cls.FORMAT_CHECKER)
|
43
43
|
return validator
|
44
44
|
|
45
45
|
|
linkml/utils/datautils.py
CHANGED
@@ -79,14 +79,14 @@ def infer_root_class(sv: SchemaView) -> Optional[ClassDefinitionName]:
|
|
79
79
|
if c.tree_root:
|
80
80
|
return c.name
|
81
81
|
refs = defaultdict(int)
|
82
|
-
for cn in sv.
|
82
|
+
for cn in sv.all_classes().keys():
|
83
83
|
for sn in sv.class_slots(cn):
|
84
84
|
slot = sv.induced_slot(sn, cn)
|
85
85
|
r = slot.range
|
86
|
-
if r in sv.
|
86
|
+
if r in sv.all_classes():
|
87
87
|
for a in sv.class_ancestors(r):
|
88
88
|
refs[a] += 1
|
89
|
-
candidates = [cn for cn in sv.
|
89
|
+
candidates = [cn for cn in sv.all_classes().keys() if cn not in refs]
|
90
90
|
|
91
91
|
# throw Exception if unambiguous root cannot be inferred
|
92
92
|
if len(candidates) > 1:
|
@@ -106,7 +106,7 @@ def infer_index_slot(sv: SchemaView, root_class: ClassDefinitionName) -> Optiona
|
|
106
106
|
index_slots = []
|
107
107
|
for sn in sv.class_slots(root_class):
|
108
108
|
slot = sv.induced_slot(sn, root_class)
|
109
|
-
if slot.multivalued and slot.range in sv.
|
109
|
+
if slot.multivalued and slot.range in sv.all_classes():
|
110
110
|
index_slots.append(sn)
|
111
111
|
if len(index_slots) == 1:
|
112
112
|
return index_slots[0]
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
from typing import Any, Iterator, Optional
|
3
3
|
|
4
|
-
import jsonschema
|
5
4
|
from jsonschema.exceptions import best_match
|
6
5
|
|
7
6
|
from linkml.validator.plugins.validation_plugin import ValidationPlugin
|
@@ -41,12 +40,11 @@ class JsonschemaValidationPlugin(ValidationPlugin):
|
|
41
40
|
:return: Iterator over validation results
|
42
41
|
:rtype: Iterator[ValidationResult]
|
43
42
|
"""
|
44
|
-
|
43
|
+
validator = context.json_schema_validator(
|
45
44
|
closed=self.closed,
|
46
45
|
include_range_class_descendants=self.include_range_class_descendants,
|
47
46
|
path_override=self.json_schema_path,
|
48
47
|
)
|
49
|
-
validator = jsonschema.Draft7Validator(json_schema, format_checker=jsonschema.Draft7Validator.FORMAT_CHECKER)
|
50
48
|
for error in validator.iter_errors(instance):
|
51
49
|
best_error = best_match([error])
|
52
50
|
yield ValidationResult(
|
@@ -3,6 +3,7 @@ import os
|
|
3
3
|
from functools import lru_cache
|
4
4
|
from typing import Optional
|
5
5
|
|
6
|
+
import jsonschema
|
6
7
|
from linkml_runtime import SchemaView
|
7
8
|
from linkml_runtime.linkml_model import SchemaDefinition
|
8
9
|
|
@@ -29,26 +30,29 @@ class ValidationContext:
|
|
29
30
|
return self._target_class
|
30
31
|
|
31
32
|
@lru_cache
|
32
|
-
def
|
33
|
+
def json_schema_validator(
|
33
34
|
self,
|
34
35
|
*,
|
35
36
|
closed: bool,
|
36
37
|
include_range_class_descendants: bool,
|
37
38
|
path_override: Optional[os.PathLike] = None,
|
38
|
-
):
|
39
|
+
) -> jsonschema.Validator:
|
39
40
|
if path_override:
|
40
41
|
with open(path_override) as json_schema_file:
|
41
|
-
|
42
|
+
json_schema = json.load(json_schema_file)
|
43
|
+
else:
|
44
|
+
not_closed = not closed
|
45
|
+
jsonschema_gen = JsonSchemaGenerator(
|
46
|
+
schema=self._schema,
|
47
|
+
mergeimports=True,
|
48
|
+
top_class=self._target_class,
|
49
|
+
not_closed=not_closed,
|
50
|
+
include_range_class_descendants=include_range_class_descendants,
|
51
|
+
)
|
52
|
+
json_schema = jsonschema_gen.generate()
|
42
53
|
|
43
|
-
|
44
|
-
|
45
|
-
schema=self._schema,
|
46
|
-
mergeimports=True,
|
47
|
-
top_class=self._target_class,
|
48
|
-
not_closed=not_closed,
|
49
|
-
include_range_class_descendants=include_range_class_descendants,
|
50
|
-
)
|
51
|
-
return jsonschema_gen.generate()
|
54
|
+
validator_cls = jsonschema.validators.validator_for(json_schema, default=jsonschema.Draft7Validator)
|
55
|
+
return validator_cls(json_schema, format_checker=validator_cls.FORMAT_CHECKER)
|
52
56
|
|
53
57
|
def pydantic_model(self, *, closed: bool):
|
54
58
|
module = self._pydantic_module(closed=closed)
|
@@ -105,7 +105,8 @@ class JsonSchemaDataValidator(DataValidator):
|
|
105
105
|
jsonschema_obj = _generate_jsonschema(
|
106
106
|
self._hashable_schema, target_class_name, closed, self.include_range_class_descendants
|
107
107
|
)
|
108
|
-
|
108
|
+
validator_cls = jsonschema.validators.validator_for(jsonschema_obj, default=jsonschema.Draft7Validator)
|
109
|
+
validator = validator_cls(jsonschema_obj, format_checker=validator_cls.FORMAT_CHECKER)
|
109
110
|
for error in validator.iter_errors(data):
|
110
111
|
best_error = best_match([error])
|
111
112
|
# TODO: This should return some kind of standard validation result
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: linkml
|
3
|
-
Version: 1.6.
|
3
|
+
Version: 1.6.9
|
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
|
@@ -18,7 +18,6 @@ Classifier: Programming Language :: Python :: 3.9
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.10
|
19
19
|
Classifier: Programming Language :: Python :: 3.11
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
21
|
-
Classifier: Programming Language :: Python :: 3.7
|
22
21
|
Classifier: Programming Language :: Python :: 3.8
|
23
22
|
Classifier: Programming Language :: Python :: 3.9
|
24
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
@@ -6,8 +6,8 @@ linkml/generators/__init__.py,sha256=qa22iTeBrcds6ndst_iTPVWLQtBF6NGyhVngBhbhIpc
|
|
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=h-Mj-uNrzuETx_G3dW6eFbk1jj0NHSwqbehqR5tA6PM,2955
|
9
|
-
linkml/generators/docgen/class.md.jinja2,sha256=
|
10
|
-
linkml/generators/docgen/class_diagram.md.jinja2,sha256=
|
9
|
+
linkml/generators/docgen/class.md.jinja2,sha256=_nQr8ge57ZkX3Hrh-cqPUm8Z7HCnJuuRCgYm0g21mS8,3381
|
10
|
+
linkml/generators/docgen/class_diagram.md.jinja2,sha256=lLU_0sQZBttOX5Wiup2oZwrxHuiQtbU9ZgLi66aJvOo,2538
|
11
11
|
linkml/generators/docgen/common_metadata.md.jinja2,sha256=zy8Ua3gDtAAq8VA3e3O3ft9W7eJopVZaq5efP8LU_hU,1321
|
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
|
@@ -16,7 +16,7 @@ linkml/generators/docgen/schema.md.jinja2,sha256=xlENfnzNRYgPT_0tdqNFxgklVM4Qf5B
|
|
16
16
|
linkml/generators/docgen/slot.md.jinja2,sha256=XVd0M4gKx9Q2fONcsUGBRj_bJivyN4P9jhj9IO496jQ,2817
|
17
17
|
linkml/generators/docgen/subset.md.jinja2,sha256=fTNIpAkml5RKFbbtLore3IAzFN1cISVsyL1ru2-Z4oA,2665
|
18
18
|
linkml/generators/docgen/type.md.jinja2,sha256=QmCMJZrFwP33eHkggBVtypbyrxTb-XZn9vHOYojVaYk,635
|
19
|
-
linkml/generators/docgen.py,sha256=
|
19
|
+
linkml/generators/docgen.py,sha256=Kwg4ZIXL2e9G-q-_CUoj8Bgnpyyvvh5fKPnseDcTK04,33755
|
20
20
|
linkml/generators/dotgen.py,sha256=CnbVY6CO1OMuiYXYnvxgNN2IW1mtOQW-J-QnwZlXkUI,5012
|
21
21
|
linkml/generators/erdiagramgen.py,sha256=Gu-_nhLuEPTsYYaoV6tNS1V6cZ2dNJdm6YwxC0VGl7g,10315
|
22
22
|
linkml/generators/excelgen.py,sha256=OhVzuQaDESYpAGR8Zv13hiWlDDJA8ugtSZatBJH0hzA,7737
|
@@ -28,7 +28,7 @@ linkml/generators/javagen/java_record_template.jinja2,sha256=OQZffLSy_xR3FIhQMlt
|
|
28
28
|
linkml/generators/javagen.py,sha256=oZfUowKnBQNdklRqOM-yKptO4Te4y4N5ItIc5jTuWKU,5427
|
29
29
|
linkml/generators/jsonldcontextgen.py,sha256=2TUzEzFBX7wDOYJ51Kg0hp2CVXcOzJhgIbq0CrzL2oc,7832
|
30
30
|
linkml/generators/jsonldgen.py,sha256=KQYurjqp3gI0bevjzmrw4WDEgz4Yf4o4TJfZsqK4_vs,7575
|
31
|
-
linkml/generators/jsonschemagen.py,sha256=
|
31
|
+
linkml/generators/jsonschemagen.py,sha256=8fzOoR5ZRgchg7r-QxZsbkxlnfD7ytrLw6qKjIRgmWo,25294
|
32
32
|
linkml/generators/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
33
|
linkml/generators/linkmlgen.py,sha256=QhIPA1v2g_g5fien3ZKN-L6TkDk3t7puVFrcoEnwkwY,3540
|
34
34
|
linkml/generators/markdowngen.py,sha256=ZPLahEPjWsrAsKq4CHbVDXeVd0n1NO-2STs068-g0Ac,32948
|
@@ -39,11 +39,11 @@ linkml/generators/plantumlgen.py,sha256=Vs__5x9ioiT4IBTbvZUpgT8MsYJ0amfBL64MB_nm
|
|
39
39
|
linkml/generators/prefixmapgen.py,sha256=JJ7hgzuqKVfFZrbDV76Dk8dR2NHsmpp-eNUAspXkfwA,4626
|
40
40
|
linkml/generators/projectgen.py,sha256=g3JR2oXPM_QXhWUGukP9ts1P7tqxIeABaRdv130gbo4,9578
|
41
41
|
linkml/generators/protogen.py,sha256=9YfxBZkQdBWwsUbstxEUR4xRWNuAKSfz9zXPhgIYePU,2328
|
42
|
-
linkml/generators/pydanticgen.py,sha256=
|
42
|
+
linkml/generators/pydanticgen.py,sha256=Ak0bpRoQsirnnBd091NiJvMZ-2d0qaQbhxADHy5ocwY,25529
|
43
43
|
linkml/generators/pythongen.py,sha256=yGYlRJ4rNm2QQLFDjyuUnqCyKlzz-b3eSOhkSu8aCwI,52491
|
44
44
|
linkml/generators/rdfgen.py,sha256=LxzYBaFEkV7rlf54nWv_6H6AGcWMRXwkaeVXq9VYEc8,2693
|
45
45
|
linkml/generators/shaclgen.py,sha256=KxNmDZW2ciCuSqUhJ65TxLTjF8jME1FmN5SaWJCuW9k,8662
|
46
|
-
linkml/generators/shexgen.py,sha256=
|
46
|
+
linkml/generators/shexgen.py,sha256=E-R8jg5Z3JzzsVAIPu6Fs9FtFF7k-I5-5vMwG1jGW2U,9858
|
47
47
|
linkml/generators/sparqlgen.py,sha256=xIT4abjYTjPvAjczZ2mkqfap5z8-AImK_jaCvgZyRGs,6120
|
48
48
|
linkml/generators/sqlalchemy/__init__.py,sha256=mb9AC1rIFkSiNZhhG0TAk45ol9PjS1XvsrvCjgfVUpQ,249
|
49
49
|
linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py,sha256=X_Ws1NUBikMI5HuNgEhl_PIeWM-B-c2B0W9KUBH4QTg,2542
|
@@ -55,11 +55,11 @@ linkml/generators/sssomgen.py,sha256=yur3q7so9uwIELWZaZRzkJwNbz_ppBL7IQki9XLIM3k
|
|
55
55
|
linkml/generators/string_template.md,sha256=kRcfic6entgIaJdpSg6GF3jcjC9wbKsCVM6wVT2qipc,1788
|
56
56
|
linkml/generators/summarygen.py,sha256=aeWAUeOaWhn1WHZKnJ3TcKVku_6psrw88ubMc-GQzEc,2924
|
57
57
|
linkml/generators/terminusdbgen.py,sha256=_po9KnOz6Uoctb9Y4fJuU_voW4uA5pepvZTmHLQ2_DE,4470
|
58
|
-
linkml/generators/typescriptgen.py,sha256=
|
58
|
+
linkml/generators/typescriptgen.py,sha256=VDJ-97jk7zqYx6XlnIcxZmY8mCv885T7D2brKJHaihI,8565
|
59
59
|
linkml/generators/yamlgen.py,sha256=bI4ebWe8vebR3xGVgto5TH0ZDej-RlZPTYqJ26BxKpg,1651
|
60
60
|
linkml/generators/yumlgen.py,sha256=547atFkqJd9WtL_LdR-tUME9g7lWaFa3yHFvpnX6J1E,12145
|
61
61
|
linkml/linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
62
|
-
linkml/linter/cli.py,sha256=
|
62
|
+
linkml/linter/cli.py,sha256=BpQiETcRfQlZsI1-JALyU9wXPgPOm_KE_n11p0iJaC8,4494
|
63
63
|
linkml/linter/config/datamodel/.linkmllint.yaml,sha256=40rNhcL35FXQSjlVBMWnyPgplwEUqFT_sJmeZqUzxMw,292
|
64
64
|
linkml/linter/config/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
65
65
|
linkml/linter/config/datamodel/config.py,sha256=4HtqHF2ZiYx0Izm50eUQRvygsm1xSnkc49w0nd9zbGk,16837
|
@@ -72,7 +72,7 @@ linkml/linter/formatters/json_formatter.py,sha256=rrOELuETUCFTl1Ewnrus9Rx9hl2g4u
|
|
72
72
|
linkml/linter/formatters/markdown_formatter.py,sha256=sumF2MNJYL5oipLwCftCr3AiaCmVhd9V6di9aYpJ29I,2605
|
73
73
|
linkml/linter/formatters/terminal_formatter.py,sha256=xmNwlRieVCssRt3fpnNP5WWw_YXGmaBsbxFoMWufy5M,2085
|
74
74
|
linkml/linter/formatters/tsv_formatter.py,sha256=1VW-1Tv16mwhIDpHdExYpJJR3z42K5_XK2C-4mmYYdE,871
|
75
|
-
linkml/linter/linter.py,sha256=
|
75
|
+
linkml/linter/linter.py,sha256=B4zPHkS_8qWV2WJY74HDiIroajsXRmfJLIlwYky-cyA,5101
|
76
76
|
linkml/linter/rules.py,sha256=Bk87FMKgdF_aSBqeLe1uQartcTxV3-ZwUu-QRp2iK4s,11164
|
77
77
|
linkml/reporting/__init__.py,sha256=Jo0V_nyEcnWhMukMW-bqW9dlbgCfaRlWm3CO-XzgU84,92
|
78
78
|
linkml/reporting/model.py,sha256=-10yNfk8wuRC48ZI-akrWvtlJ9a6RYWET2TzlZV3XXo,8622
|
@@ -84,7 +84,7 @@ linkml/transformers/schema_renamer.py,sha256=Cr18TyktX64b5iFh5V6R_ILPVzXjbDYVDDZ
|
|
84
84
|
linkml/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
85
85
|
linkml/utils/cli_utils.py,sha256=MdVbox1qr6kDUHUCWAmFhV-D6ebs_nn8vVwB8KDQfew,742
|
86
86
|
linkml/utils/converter.py,sha256=rdhCI7Tsjddr3o1rVBfMq5gQubk_GE6fqlBBmyxI5_M,6270
|
87
|
-
linkml/utils/datautils.py,sha256=
|
87
|
+
linkml/utils/datautils.py,sha256=QlbzwXykh5Fphfe5KxPo6_ekXfniLbHiEGJtLWjUrvY,3742
|
88
88
|
linkml/utils/datavalidator.py,sha256=kBdWaVi8IZT1bOwEJgJYx-wZAb_PTBObB9nHpYORfKA,472
|
89
89
|
linkml/utils/execute_tutorial.py,sha256=T4kHTSyz3ItJGEUZxVjR-3yLVKnOr5Ix4NMGE47-IuE,6912
|
90
90
|
linkml/utils/generator.py,sha256=WAlP_gfZfAZYNklsh8l4GtiWZ338kjLg7xpQAANgUNg,38217
|
@@ -109,23 +109,23 @@ linkml/validator/loaders/loader.py,sha256=YKQXmSZhCymvvb2Dbr4lVCKVDt-lOIayzRD7CW
|
|
109
109
|
linkml/validator/loaders/passthrough_loader.py,sha256=fQvBZqzGnpdwpZio4Mbehmsb6ePpzcacHPuR1QWuhFM,525
|
110
110
|
linkml/validator/loaders/yaml_loader.py,sha256=ZsMz-oGDkX9oPEOVcKnFRGhU9q0fKoHcL6BLOkCeB4c,914
|
111
111
|
linkml/validator/plugins/__init__.py,sha256=F7Un7bfdpSRXvk8LTb7Z4Q22rCtJJKjNkqUfIVLFtT8,702
|
112
|
-
linkml/validator/plugins/jsonschema_validation_plugin.py,sha256=
|
112
|
+
linkml/validator/plugins/jsonschema_validation_plugin.py,sha256=hMPlCyAdMg_N_OHiHMaxcG0fsOA50V4oBNqorNz_oqE,2528
|
113
113
|
linkml/validator/plugins/pydantic_validation_plugin.py,sha256=C-Vp74bz5oqp5V-iuhXW8p0PPDoFY8NCU5x36Ur5Og4,1985
|
114
114
|
linkml/validator/plugins/recommended_slots_plugin.py,sha256=kOdoYQyye47nLA7BjorVmydS84nGpiVy3MoCbPq1Ymo,2308
|
115
115
|
linkml/validator/plugins/validation_plugin.py,sha256=9SMHF8b2bgG9-8351e8bY676e0A4aEBJSXvMjMF5kXg,1548
|
116
116
|
linkml/validator/report.py,sha256=kkkuh-IZF9--cO-2wGjwP3PDLvOcjjvC8AOlxXUIOAM,870
|
117
|
-
linkml/validator/validation_context.py,sha256=
|
117
|
+
linkml/validator/validation_context.py,sha256=2BYbw0czAYepJUNoIINyTnmW6SrgK6et7SNvH5ejzgU,2700
|
118
118
|
linkml/validator/validator.py,sha256=sdWbAOlnNYQWnZSEIuLpGQqH3W4cNq_8M_CdLtsNMH0,5648
|
119
119
|
linkml/validators/__init__.py,sha256=43W3J5NPKhwa3ZFHLRYsJMocwQKWGYCF9Ki9r0ccGbc,202
|
120
|
-
linkml/validators/jsonschemavalidator.py,sha256=
|
120
|
+
linkml/validators/jsonschemavalidator.py,sha256=_ku7MQGqA6KplbHMiyzDRqgRwwXGloobhLptuXqLCp4,7951
|
121
121
|
linkml/validators/sparqlvalidator.py,sha256=JowuZ5KxmWkldgWIXAb8DJi7YCPm8x3it0QkgM4lSi0,4612
|
122
122
|
linkml/workspaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
123
123
|
linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
124
124
|
linkml/workspaces/datamodel/workspaces.py,sha256=4HdkqweGNfMPqnB1_Onc9DcTfkhoagTRcqruh08nRoI,14905
|
125
125
|
linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
|
126
126
|
linkml/workspaces/example_runner.py,sha256=uumXyPZ7xUJSZyRtjDP4TCCxgKSSOfebpufXc0_l0jY,11610
|
127
|
-
linkml-1.6.
|
128
|
-
linkml-1.6.
|
129
|
-
linkml-1.6.
|
130
|
-
linkml-1.6.
|
131
|
-
linkml-1.6.
|
127
|
+
linkml-1.6.9.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
128
|
+
linkml-1.6.9.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
|
129
|
+
linkml-1.6.9.dist-info/entry_points.txt,sha256=za8r49Z5gcz3rAYTZLbxw5EPZr1rGuxSe1uiRUpf8R0,2143
|
130
|
+
linkml-1.6.9.dist-info/METADATA,sha256=KsqVPfLcVUKxAlb-hz4AFdd6Pk5VGUjtmGx3wj5x7U8,3446
|
131
|
+
linkml-1.6.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|