linkml 1.8.1__py3-none-any.whl → 1.8.3__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/cli/__init__.py +0 -0
- linkml/cli/__main__.py +4 -0
- linkml/cli/main.py +130 -0
- linkml/generators/common/build.py +105 -0
- linkml/generators/common/ifabsent_processor.py +286 -0
- linkml/generators/common/lifecycle.py +124 -0
- linkml/generators/common/template.py +89 -0
- linkml/generators/csvgen.py +1 -1
- linkml/generators/docgen/slot.md.jinja2 +4 -0
- linkml/generators/docgen.py +1 -1
- linkml/generators/dotgen.py +1 -1
- linkml/generators/erdiagramgen.py +1 -1
- linkml/generators/excelgen.py +1 -1
- linkml/generators/golanggen.py +1 -1
- linkml/generators/golrgen.py +1 -1
- linkml/generators/graphqlgen.py +1 -1
- linkml/generators/javagen.py +1 -1
- linkml/generators/jsonldcontextgen.py +4 -5
- linkml/generators/jsonldgen.py +1 -1
- linkml/generators/jsonschemagen.py +69 -22
- linkml/generators/linkmlgen.py +1 -1
- linkml/generators/markdowngen.py +1 -1
- linkml/generators/namespacegen.py +1 -1
- linkml/generators/oocodegen.py +2 -1
- linkml/generators/owlgen.py +1 -1
- linkml/generators/plantumlgen.py +1 -1
- linkml/generators/prefixmapgen.py +1 -1
- linkml/generators/projectgen.py +1 -1
- linkml/generators/protogen.py +1 -1
- linkml/generators/pydanticgen/__init__.py +8 -3
- linkml/generators/pydanticgen/array.py +114 -194
- linkml/generators/pydanticgen/build.py +64 -25
- linkml/generators/pydanticgen/includes.py +1 -31
- linkml/generators/pydanticgen/pydanticgen.py +621 -276
- linkml/generators/pydanticgen/template.py +152 -184
- linkml/generators/pydanticgen/templates/attribute.py.jinja +9 -7
- linkml/generators/pydanticgen/templates/base_model.py.jinja +0 -13
- linkml/generators/pydanticgen/templates/class.py.jinja +2 -2
- linkml/generators/pydanticgen/templates/footer.py.jinja +2 -10
- linkml/generators/pydanticgen/templates/module.py.jinja +2 -2
- linkml/generators/pydanticgen/templates/validator.py.jinja +0 -4
- linkml/generators/python/__init__.py +1 -0
- linkml/generators/python/python_ifabsent_processor.py +92 -0
- linkml/generators/pythongen.py +19 -23
- linkml/generators/rdfgen.py +1 -1
- linkml/generators/shacl/__init__.py +1 -3
- linkml/generators/shacl/shacl_data_type.py +1 -1
- linkml/generators/shacl/shacl_ifabsent_processor.py +89 -0
- linkml/generators/shaclgen.py +11 -5
- linkml/generators/shexgen.py +1 -1
- linkml/generators/sparqlgen.py +1 -1
- linkml/generators/sqlalchemygen.py +1 -1
- linkml/generators/sqltablegen.py +1 -1
- linkml/generators/sssomgen.py +1 -1
- linkml/generators/summarygen.py +1 -1
- linkml/generators/terminusdbgen.py +7 -4
- linkml/generators/typescriptgen.py +1 -1
- linkml/generators/yamlgen.py +1 -1
- linkml/generators/yumlgen.py +1 -1
- linkml/linter/cli.py +1 -1
- linkml/transformers/logical_model_transformer.py +117 -18
- linkml/utils/converter.py +1 -1
- linkml/utils/execute_tutorial.py +2 -0
- linkml/utils/logictools.py +142 -29
- linkml/utils/schema_builder.py +7 -6
- linkml/utils/schema_fixer.py +1 -1
- linkml/utils/sqlutils.py +1 -1
- linkml/validator/cli.py +4 -1
- linkml/validators/jsonschemavalidator.py +1 -1
- linkml/validators/sparqlvalidator.py +1 -1
- linkml/workspaces/example_runner.py +1 -1
- {linkml-1.8.1.dist-info → linkml-1.8.3.dist-info}/METADATA +2 -2
- {linkml-1.8.1.dist-info → linkml-1.8.3.dist-info}/RECORD +76 -68
- {linkml-1.8.1.dist-info → linkml-1.8.3.dist-info}/entry_points.txt +1 -1
- linkml/generators/shacl/ifabsent_processor.py +0 -59
- linkml/utils/ifabsent_functions.py +0 -138
- {linkml-1.8.1.dist-info → linkml-1.8.3.dist-info}/LICENSE +0 -0
- {linkml-1.8.1.dist-info → linkml-1.8.3.dist-info}/WHEEL +0 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
"""
|
2
|
+
Base classes for jinja template handling classes.
|
3
|
+
|
4
|
+
See :mod:`.linkml.generators.pydanticgen.template` for example implementation
|
5
|
+
"""
|
6
|
+
|
7
|
+
from copy import copy
|
8
|
+
from typing import Any, ClassVar, Dict, List, Optional, Union
|
9
|
+
|
10
|
+
from jinja2 import Environment
|
11
|
+
from pydantic import BaseModel
|
12
|
+
|
13
|
+
|
14
|
+
class TemplateModel(BaseModel):
|
15
|
+
"""
|
16
|
+
Metaclass to render model results with jinja templates.
|
17
|
+
|
18
|
+
Each subclass needs to declare a :class:`typing.ClassVar` for a
|
19
|
+
jinja template within the `templates` directory.
|
20
|
+
|
21
|
+
Templates are written expecting each of the other TemplateModels
|
22
|
+
to already be rendered to strings - ie. rather than the ``class.py.jinja``
|
23
|
+
template receiving a full :class:`.PydanticAttribute` object or dictionary,
|
24
|
+
it receives it having already been rendered to a string. See the :meth:`.render` method.
|
25
|
+
"""
|
26
|
+
|
27
|
+
template: ClassVar[str]
|
28
|
+
_environment: ClassVar[Environment]
|
29
|
+
|
30
|
+
meta_exclude: ClassVar[List[str]] = None
|
31
|
+
|
32
|
+
def render(self, environment: Optional[Environment] = None, **kwargs) -> str:
|
33
|
+
"""
|
34
|
+
Recursively render a template model to a string.
|
35
|
+
|
36
|
+
For each field in the model, recurse through, rendering each :class:`.TemplateModel`
|
37
|
+
using the template set in :attr:`.TemplateModel.template` , but preserving the structure
|
38
|
+
of lists and dictionaries. Regular :class:`.BaseModel` s are rendered to dictionaries.
|
39
|
+
Any other value is passed through unchanged.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
environment (:class:`jinja2.Environment`): Template environment - see :meth:`.environment`
|
43
|
+
"""
|
44
|
+
if environment is None:
|
45
|
+
environment = TemplateModel.environment()
|
46
|
+
|
47
|
+
fields = {**self.model_fields, **self.model_computed_fields}
|
48
|
+
|
49
|
+
data = {k: _render(getattr(self, k, None), environment) for k in fields}
|
50
|
+
template = environment.get_template(self.template)
|
51
|
+
rendered = template.render(**data)
|
52
|
+
return rendered
|
53
|
+
|
54
|
+
@classmethod
|
55
|
+
def environment(cls) -> Environment:
|
56
|
+
"""
|
57
|
+
Default environment for Template models.
|
58
|
+
uses a :class:`jinja2.PackageLoader` for the templates directory within this module
|
59
|
+
with the ``trim_blocks`` and ``lstrip_blocks`` parameters set to ``True`` so that the
|
60
|
+
default templates could be written in a more readable way.
|
61
|
+
"""
|
62
|
+
return copy(cls._environment)
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def exclude_from_meta(cls: "TemplateModel") -> List[str]:
|
66
|
+
"""
|
67
|
+
Attributes in the source definition to exclude from linkml_meta
|
68
|
+
"""
|
69
|
+
ret = [*cls.model_fields.keys()]
|
70
|
+
if cls.meta_exclude is not None:
|
71
|
+
ret = ret + cls.meta_exclude
|
72
|
+
return ret
|
73
|
+
|
74
|
+
|
75
|
+
def _render(
|
76
|
+
item: Union[TemplateModel, Any, List[Union[Any, TemplateModel]], Dict[str, Union[Any, TemplateModel]]],
|
77
|
+
environment: Environment,
|
78
|
+
) -> Union[str, List[str], Dict[str, str]]:
|
79
|
+
if isinstance(item, TemplateModel):
|
80
|
+
return item.render(environment)
|
81
|
+
elif isinstance(item, list):
|
82
|
+
return [_render(i, environment) for i in item]
|
83
|
+
elif isinstance(item, dict):
|
84
|
+
return {k: _render(v, environment) for k, v in item.items()}
|
85
|
+
elif isinstance(item, BaseModel):
|
86
|
+
fields = item.model_fields
|
87
|
+
return {k: _render(getattr(item, k, None), environment) for k in fields.keys()}
|
88
|
+
else:
|
89
|
+
return item
|
linkml/generators/csvgen.py
CHANGED
@@ -95,7 +95,7 @@ class CsvGenerator(Generator):
|
|
95
95
|
|
96
96
|
|
97
97
|
@shared_arguments(CsvGenerator)
|
98
|
-
@click.command()
|
98
|
+
@click.command(name="csv")
|
99
99
|
@click.version_option(__version__, "-V", "--version")
|
100
100
|
@click.option("--root", "-r", multiple=True, help="Class(es) to transform")
|
101
101
|
def cli(yamlfile, root=None, **args):
|
linkml/generators/docgen.py
CHANGED
linkml/generators/dotgen.py
CHANGED
@@ -312,7 +312,7 @@ class ERDiagramGenerator(Generator):
|
|
312
312
|
@click.option("--classes", "-c", multiple=True, help="List of classes to serialize")
|
313
313
|
@click.option("--include-upstream", is_flag=True, help="Include upstream classes")
|
314
314
|
@click.version_option(__version__, "-V", "--version")
|
315
|
-
@click.command()
|
315
|
+
@click.command(name="erdiagram")
|
316
316
|
def cli(
|
317
317
|
yamlfile,
|
318
318
|
classes: List[str],
|
linkml/generators/excelgen.py
CHANGED
linkml/generators/golanggen.py
CHANGED
@@ -189,7 +189,7 @@ class GolangGenerator(Generator):
|
|
189
189
|
|
190
190
|
@shared_arguments(GolangGenerator)
|
191
191
|
@click.version_option(__version__, "-V", "--version")
|
192
|
-
@click.command()
|
192
|
+
@click.command(name="golang")
|
193
193
|
def cli(yamlfile, **args):
|
194
194
|
"""Generate Golang types
|
195
195
|
|
linkml/generators/golrgen.py
CHANGED
@@ -101,7 +101,7 @@ class GolrSchemaGenerator(Generator):
|
|
101
101
|
|
102
102
|
|
103
103
|
@shared_arguments(GolrSchemaGenerator)
|
104
|
-
@click.command()
|
104
|
+
@click.command(name="golr-views")
|
105
105
|
@click.option("--dir", "-d", default="golr-views", show_default=True, help="Output directory")
|
106
106
|
@click.version_option(__version__, "-V", "--version")
|
107
107
|
def cli(yamlfile, dir=None, **args):
|
linkml/generators/graphqlgen.py
CHANGED
@@ -52,7 +52,7 @@ class GraphqlGenerator(Generator):
|
|
52
52
|
|
53
53
|
|
54
54
|
@shared_arguments(GraphqlGenerator)
|
55
|
-
@click.command()
|
55
|
+
@click.command(name="graphql")
|
56
56
|
@click.version_option(__version__, "-V", "--version")
|
57
57
|
def cli(yamlfile, **args):
|
58
58
|
"""Generate graphql representation of a LinkML model"""
|
linkml/generators/javagen.py
CHANGED
@@ -146,7 +146,7 @@ class JavaGenerator(OOCodeGenerator):
|
|
146
146
|
help="Optional Java 17 record implementation",
|
147
147
|
)
|
148
148
|
@click.version_option(__version__, "-V", "--version")
|
149
|
-
@click.command()
|
149
|
+
@click.command(name="java")
|
150
150
|
def cli(
|
151
151
|
yamlfile,
|
152
152
|
output_directory=None,
|
@@ -18,11 +18,9 @@ from rdflib import SKOS, XSD, Namespace
|
|
18
18
|
from linkml._version import __version__
|
19
19
|
from linkml.utils.generator import Generator, shared_arguments
|
20
20
|
|
21
|
-
URI_RANGES = (
|
22
|
-
|
21
|
+
URI_RANGES = (SHEX.nonliteral, SHEX.bnode, SHEX.iri)
|
23
22
|
|
24
23
|
ENUM_CONTEXT = {
|
25
|
-
"@vocab": "@null",
|
26
24
|
"text": "skos:notation",
|
27
25
|
"description": "skos:prefLabel",
|
28
26
|
"meaning": "@id",
|
@@ -99,7 +97,7 @@ class ContextGenerator(Generator):
|
|
99
97
|
comments.generation_date = self.schema.generation_date
|
100
98
|
comments.source = self.schema.source_file
|
101
99
|
context.comments = comments
|
102
|
-
context_content = {}
|
100
|
+
context_content = {"xsd": "http://www.w3.org/2001/XMLSchema#"}
|
103
101
|
if base:
|
104
102
|
base = str(base)
|
105
103
|
if "://" not in base:
|
@@ -193,6 +191,7 @@ class ContextGenerator(Generator):
|
|
193
191
|
elif not uri_prefix or is_default_namespace:
|
194
192
|
definition["@id"] = uri_suffix
|
195
193
|
else:
|
194
|
+
|
196
195
|
definition["@id"] = (uri_prefix + ":" + uri_suffix) if uri_prefix else uri
|
197
196
|
|
198
197
|
if uri_prefix and not is_default_namespace:
|
@@ -203,7 +202,7 @@ class ContextGenerator(Generator):
|
|
203
202
|
|
204
203
|
|
205
204
|
@shared_arguments(ContextGenerator)
|
206
|
-
@click.command()
|
205
|
+
@click.command(name="jsonld-context")
|
207
206
|
@click.option("--base", help="Base URI for model")
|
208
207
|
@click.option(
|
209
208
|
"--prefixes/--no-prefixes",
|
linkml/generators/jsonldgen.py
CHANGED
@@ -126,7 +126,13 @@ class JsonSchema(dict):
|
|
126
126
|
|
127
127
|
@property
|
128
128
|
def is_array(self):
|
129
|
-
|
129
|
+
typ = self.get("type", False)
|
130
|
+
if isinstance(typ, str):
|
131
|
+
return typ == "array"
|
132
|
+
elif isinstance(typ, list):
|
133
|
+
return "array" in typ
|
134
|
+
else:
|
135
|
+
return False
|
130
136
|
|
131
137
|
@property
|
132
138
|
def is_object(self):
|
@@ -136,7 +142,7 @@ class JsonSchema(dict):
|
|
136
142
|
return json.dumps(self, **kwargs)
|
137
143
|
|
138
144
|
@classmethod
|
139
|
-
def ref_for(cls, class_name: Union[str, List[str]], identifier_optional: bool = False):
|
145
|
+
def ref_for(cls, class_name: Union[str, List[str]], identifier_optional: bool = False, required: bool = True):
|
140
146
|
def _ref(class_name):
|
141
147
|
def_name = camelcase(class_name)
|
142
148
|
def_suffix = cls.OPTIONAL_IDENTIFIER_SUFFIX if identifier_optional else ""
|
@@ -144,15 +150,27 @@ class JsonSchema(dict):
|
|
144
150
|
|
145
151
|
if isinstance(class_name, list):
|
146
152
|
if len(class_name) == 1:
|
147
|
-
|
153
|
+
ref = _ref(class_name[0])
|
148
154
|
else:
|
149
|
-
|
155
|
+
ref = JsonSchema({"anyOf": [_ref(name) for name in class_name]})
|
150
156
|
else:
|
151
|
-
|
157
|
+
ref = _ref(class_name)
|
158
|
+
|
159
|
+
if not required:
|
160
|
+
if "anyOf" in ref:
|
161
|
+
ref["anyOf"].append({"type": "null"})
|
162
|
+
else:
|
163
|
+
ref = JsonSchema({"anyOf": [ref, {"type": "null"}]})
|
164
|
+
return ref
|
152
165
|
|
153
166
|
@classmethod
|
154
|
-
def array_of(cls, subschema: "JsonSchema") -> "JsonSchema":
|
155
|
-
|
167
|
+
def array_of(cls, subschema: "JsonSchema", required: bool = True) -> "JsonSchema":
|
168
|
+
if required:
|
169
|
+
typ = "array"
|
170
|
+
else:
|
171
|
+
typ = ["array", "null"]
|
172
|
+
|
173
|
+
schema = {"type": typ, "items": subschema}
|
156
174
|
|
157
175
|
return JsonSchema(schema)
|
158
176
|
|
@@ -199,6 +217,9 @@ class JsonSchemaGenerator(Generator):
|
|
199
217
|
|
200
218
|
top_level_schema: JsonSchema = None
|
201
219
|
|
220
|
+
include_null: bool = True
|
221
|
+
"""Whether to include a "null" type in optional slots"""
|
222
|
+
|
202
223
|
def __post_init__(self):
|
203
224
|
if self.topClass:
|
204
225
|
logging.warning("topClass is deprecated - use top_class")
|
@@ -315,7 +336,7 @@ class JsonSchemaGenerator(Generator):
|
|
315
336
|
|
316
337
|
subschema = JsonSchema()
|
317
338
|
for slot in cls.slot_conditions.values():
|
318
|
-
prop = self.get_subschema_for_slot(slot, omit_type=True)
|
339
|
+
prop = self.get_subschema_for_slot(slot, omit_type=True, include_null=False)
|
319
340
|
value_required = False
|
320
341
|
value_disallowed = False
|
321
342
|
if slot.value_presence:
|
@@ -433,11 +454,17 @@ class JsonSchemaGenerator(Generator):
|
|
433
454
|
constraints.add_keyword("maximum", slot.maximum_value)
|
434
455
|
constraints.add_keyword("const", slot.equals_string)
|
435
456
|
constraints.add_keyword("const", slot.equals_number)
|
457
|
+
if slot.equals_string_in:
|
458
|
+
constraints.add_keyword("enum", slot.equals_string_in)
|
436
459
|
return constraints
|
437
460
|
|
438
461
|
def get_subschema_for_slot(
|
439
|
-
self, slot: Union[SlotDefinition, AnonymousSlotExpression], omit_type: bool = False
|
462
|
+
self, slot: Union[SlotDefinition, AnonymousSlotExpression], omit_type: bool = False, include_null: bool = True
|
440
463
|
) -> JsonSchema:
|
464
|
+
"""
|
465
|
+
Args:
|
466
|
+
include_null: Include ``type: null`` when generating ranges that are not required
|
467
|
+
"""
|
441
468
|
prop = JsonSchema()
|
442
469
|
if isinstance(slot, SlotDefinition) and slot.array:
|
443
470
|
# TODO: this is currently too lax, in that it will validate ANY array.
|
@@ -448,9 +475,10 @@ class JsonSchemaGenerator(Generator):
|
|
448
475
|
"additionalProperties": True,
|
449
476
|
}
|
450
477
|
)
|
451
|
-
return JsonSchema.array_of(prop)
|
478
|
+
return JsonSchema.array_of(prop, required=slot.required)
|
452
479
|
slot_is_multivalued = "multivalued" in slot and slot.multivalued
|
453
480
|
slot_is_inlined = self.schemaview.is_inlined(slot)
|
481
|
+
slot_is_boolean = any([slot.any_of, slot.all_of, slot.exactly_one_of, slot.none_of])
|
454
482
|
if not omit_type:
|
455
483
|
typ, fmt, reference = self.get_type_info_for_slot_subschema(slot)
|
456
484
|
if slot_is_inlined:
|
@@ -471,7 +499,9 @@ class JsonSchemaGenerator(Generator):
|
|
471
499
|
# If the range can be collected as a simple dict, then we can also accept the value
|
472
500
|
# of that simple dict directly.
|
473
501
|
if range_simple_dict_value_slot is not None:
|
474
|
-
additionalProps.append(
|
502
|
+
additionalProps.append(
|
503
|
+
self.get_subschema_for_slot(range_simple_dict_value_slot, include_null=False)
|
504
|
+
)
|
475
505
|
|
476
506
|
# If the range has no required slots, then null is acceptable
|
477
507
|
if len(range_required_slots) == 0:
|
@@ -483,12 +513,17 @@ class JsonSchemaGenerator(Generator):
|
|
483
513
|
additionalProps = additionalProps[0]
|
484
514
|
else:
|
485
515
|
additionalProps = JsonSchema({"anyOf": additionalProps})
|
486
|
-
|
516
|
+
if slot.required or not include_null:
|
517
|
+
typ = "object"
|
518
|
+
else:
|
519
|
+
typ = ["object", "null"]
|
520
|
+
prop = JsonSchema({"type": typ, "additionalProperties": additionalProps})
|
487
521
|
self.top_level_schema.add_lax_def(reference, self.aliased_slot_name(range_id_slot))
|
488
522
|
else:
|
489
|
-
prop = JsonSchema.array_of(JsonSchema.ref_for(reference))
|
523
|
+
prop = JsonSchema.array_of(JsonSchema.ref_for(reference), required=slot.required)
|
490
524
|
else:
|
491
|
-
prop = JsonSchema.ref_for(reference)
|
525
|
+
prop = JsonSchema.ref_for(reference, required=slot.required or not include_null)
|
526
|
+
|
492
527
|
else:
|
493
528
|
if reference is not None:
|
494
529
|
prop = JsonSchema.ref_for(reference)
|
@@ -498,7 +533,12 @@ class JsonSchemaGenerator(Generator):
|
|
498
533
|
prop = JsonSchema({"type": typ, "format": fmt})
|
499
534
|
|
500
535
|
if slot_is_multivalued:
|
501
|
-
prop = JsonSchema.array_of(prop)
|
536
|
+
prop = JsonSchema.array_of(prop, required=slot.required)
|
537
|
+
else:
|
538
|
+
# handle optionals - bools like any_of, etc. below as they call this method recursively
|
539
|
+
if not slot.required and not slot_is_boolean and include_null:
|
540
|
+
if "type" in prop:
|
541
|
+
prop["type"] = [prop["type"], "null"]
|
502
542
|
|
503
543
|
prop.add_keyword("description", slot.description)
|
504
544
|
if self.title_from == "title" and slot.title:
|
@@ -524,22 +564,29 @@ class JsonSchemaGenerator(Generator):
|
|
524
564
|
|
525
565
|
bool_subschema = JsonSchema()
|
526
566
|
if slot.any_of is not None and len(slot.any_of) > 0:
|
527
|
-
bool_subschema["anyOf"] = [self.get_subschema_for_slot(s) for s in slot.any_of]
|
567
|
+
bool_subschema["anyOf"] = [self.get_subschema_for_slot(s, include_null=False) for s in slot.any_of]
|
568
|
+
if not slot.required and not prop.is_array and include_null:
|
569
|
+
bool_subschema["anyOf"].append({"type": "null"})
|
528
570
|
|
529
571
|
if slot.all_of is not None and len(slot.all_of) > 0:
|
530
|
-
bool_subschema["allOf"] = [self.get_subschema_for_slot(s) for s in slot.all_of]
|
572
|
+
bool_subschema["allOf"] = [self.get_subschema_for_slot(s, include_null=False) for s in slot.all_of]
|
531
573
|
|
532
574
|
if slot.exactly_one_of is not None and len(slot.exactly_one_of) > 0:
|
533
|
-
bool_subschema["oneOf"] = [self.get_subschema_for_slot(s) for s in slot.exactly_one_of]
|
575
|
+
bool_subschema["oneOf"] = [self.get_subschema_for_slot(s, include_null=False) for s in slot.exactly_one_of]
|
534
576
|
|
535
577
|
if slot.none_of is not None and len(slot.none_of) > 0:
|
536
|
-
bool_subschema["not"] = {
|
578
|
+
bool_subschema["not"] = {
|
579
|
+
"anyOf": [self.get_subschema_for_slot(s, include_null=False) for s in slot.none_of]
|
580
|
+
}
|
537
581
|
|
538
582
|
if bool_subschema:
|
539
583
|
if prop.is_array:
|
540
584
|
if "items" not in prop:
|
541
585
|
prop["items"] = {}
|
542
|
-
|
586
|
+
if slot.required or not include_null:
|
587
|
+
prop["type"] = "array"
|
588
|
+
else:
|
589
|
+
prop["type"] = ["array", "null"]
|
543
590
|
prop["items"].update(bool_subschema)
|
544
591
|
else:
|
545
592
|
prop.update(bool_subschema)
|
@@ -554,7 +601,7 @@ class JsonSchemaGenerator(Generator):
|
|
554
601
|
value_disallowed = slot.value_presence == PresenceEnum(PresenceEnum.ABSENT)
|
555
602
|
|
556
603
|
aliased_slot_name = self.aliased_slot_name(slot)
|
557
|
-
prop = self.get_subschema_for_slot(slot)
|
604
|
+
prop = self.get_subschema_for_slot(slot, include_null=self.include_null)
|
558
605
|
subschema.add_property(
|
559
606
|
aliased_slot_name, prop, value_required=value_required, value_disallowed=value_disallowed
|
560
607
|
)
|
@@ -625,7 +672,7 @@ class JsonSchemaGenerator(Generator):
|
|
625
672
|
|
626
673
|
|
627
674
|
@shared_arguments(JsonSchemaGenerator)
|
628
|
-
@click.command()
|
675
|
+
@click.command(name="json-schema")
|
629
676
|
@click.option(
|
630
677
|
"-i",
|
631
678
|
"--inline",
|
linkml/generators/linkmlgen.py
CHANGED
@@ -97,7 +97,7 @@ class LinkmlGenerator(Generator):
|
|
97
97
|
help="Name of JSON or YAML file to be created",
|
98
98
|
)
|
99
99
|
@click.version_option(__version__, "-V", "--version")
|
100
|
-
@click.command()
|
100
|
+
@click.command(name="linkml")
|
101
101
|
def cli(
|
102
102
|
yamlfile,
|
103
103
|
materialize_attributes: bool,
|
linkml/generators/markdowngen.py
CHANGED
@@ -789,7 +789,7 @@ def pad_heading(text: str) -> str:
|
|
789
789
|
|
790
790
|
|
791
791
|
@shared_arguments(MarkdownGenerator)
|
792
|
-
@click.command()
|
792
|
+
@click.command(name="markdown")
|
793
793
|
@click.option("--dir", "-d", required=True, help="Output directory")
|
794
794
|
@click.option("--classes", "-c", multiple=True, help="Class(es) to emit")
|
795
795
|
@click.option("--map-fields", "-M", multiple=True, help="Map metamodel fields, e.g. slot=field")
|
@@ -195,7 +195,7 @@ def curie(identifier) -> str:
|
|
195
195
|
|
196
196
|
@shared_arguments(NamespaceGenerator)
|
197
197
|
@click.version_option(__version__, "-V", "--version")
|
198
|
-
@click.command()
|
198
|
+
@click.command(name="namespaces")
|
199
199
|
def cli(yamlfile, **args):
|
200
200
|
"""Generate a namespace manager for all of the prefixes represented in a LinkML model"""
|
201
201
|
print(NamespaceGenerator(yamlfile, **args).serialize(**args))
|
linkml/generators/oocodegen.py
CHANGED
@@ -76,6 +76,7 @@ class OOCodeGenerator(Generator):
|
|
76
76
|
visit_all_class_slots = False
|
77
77
|
uses_schemaloader = False
|
78
78
|
requires_metamodel = False
|
79
|
+
schemaview: SchemaView = None
|
79
80
|
|
80
81
|
template_file: str = None
|
81
82
|
"""Path to template"""
|
@@ -84,7 +85,7 @@ class OOCodeGenerator(Generator):
|
|
84
85
|
|
85
86
|
def __post_init__(self):
|
86
87
|
# TODO: consider moving up a level
|
87
|
-
self.schemaview = SchemaView(self.schema)
|
88
|
+
self.schemaview: SchemaView = SchemaView(self.schema)
|
88
89
|
super().__post_init__()
|
89
90
|
|
90
91
|
@abc.abstractmethod
|
linkml/generators/owlgen.py
CHANGED
@@ -1271,7 +1271,7 @@ class OwlSchemaGenerator(Generator):
|
|
1271
1271
|
|
1272
1272
|
|
1273
1273
|
@shared_arguments(OwlSchemaGenerator)
|
1274
|
-
@click.command()
|
1274
|
+
@click.command(name="owl")
|
1275
1275
|
@click.option("-o", "--output", help="Output file name")
|
1276
1276
|
@click.option(
|
1277
1277
|
"--metadata-profile",
|
linkml/generators/plantumlgen.py
CHANGED
@@ -339,7 +339,7 @@ class PlantumlGenerator(Generator):
|
|
339
339
|
|
340
340
|
|
341
341
|
@shared_arguments(PlantumlGenerator)
|
342
|
-
@click.command()
|
342
|
+
@click.command(name="plantuml")
|
343
343
|
@click.option("--classes", "-c", multiple=True, help="Class(es) to emit")
|
344
344
|
@click.option(
|
345
345
|
"--directory",
|
@@ -112,7 +112,7 @@ class PrefixGenerator(Generator):
|
|
112
112
|
|
113
113
|
|
114
114
|
@shared_arguments(PrefixGenerator)
|
115
|
-
@click.command()
|
115
|
+
@click.command(name="prefix-map")
|
116
116
|
@click.option("--base", help="Base URI for model")
|
117
117
|
@click.option("--output", "-o", help="Output file path")
|
118
118
|
@click.version_option(__version__, "-V", "--version")
|
linkml/generators/projectgen.py
CHANGED
linkml/generators/protogen.py
CHANGED
@@ -69,7 +69,7 @@ class ProtoGenerator(Generator):
|
|
69
69
|
|
70
70
|
@shared_arguments(ProtoGenerator)
|
71
71
|
@click.version_option(__version__, "-V", "--version")
|
72
|
-
@click.command()
|
72
|
+
@click.command(name="proto")
|
73
73
|
def cli(yamlfile, **args):
|
74
74
|
"""Generate proto representation of LinkML model"""
|
75
75
|
print(ProtoGenerator(yamlfile, **args).serialize(**args))
|
@@ -1,4 +1,9 @@
|
|
1
|
-
from linkml.generators.pydanticgen.pydanticgen import
|
1
|
+
from linkml.generators.pydanticgen.pydanticgen import (
|
2
|
+
DEFAULT_IMPORTS,
|
3
|
+
MetadataMode,
|
4
|
+
PydanticGenerator,
|
5
|
+
cli,
|
6
|
+
)
|
2
7
|
from linkml.generators.pydanticgen.template import (
|
3
8
|
ConditionalImport,
|
4
9
|
Import,
|
@@ -8,8 +13,8 @@ from linkml.generators.pydanticgen.template import (
|
|
8
13
|
PydanticClass,
|
9
14
|
PydanticEnum,
|
10
15
|
PydanticModule,
|
16
|
+
PydanticTemplateModel,
|
11
17
|
PydanticValidator,
|
12
|
-
TemplateModel,
|
13
18
|
)
|
14
19
|
|
15
20
|
__all__ = [
|
@@ -26,5 +31,5 @@ __all__ = [
|
|
26
31
|
"PydanticGenerator",
|
27
32
|
"PydanticModule",
|
28
33
|
"PydanticValidator",
|
29
|
-
"
|
34
|
+
"PydanticTemplateModel",
|
30
35
|
]
|