linkml 1.6.3__py3-none-any.whl → 1.6.5__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 +8 -4
- linkml/generators/docgen/slot.md.jinja2 +5 -1
- linkml/generators/docgen.py +30 -2
- linkml/generators/excelgen.py +75 -73
- linkml/generators/javagen/java_record_template.jinja2 +2 -2
- linkml/generators/javagen.py +3 -3
- linkml/generators/jsonschemagen.py +12 -8
- linkml/generators/pydanticgen.py +60 -11
- linkml/generators/pythongen.py +9 -2
- linkml/generators/shaclgen.py +2 -2
- linkml/generators/sqlalchemygen.py +1 -1
- linkml/utils/generator.py +25 -8
- linkml/utils/schemaloader.py +1 -1
- linkml/validator/validation_context.py +6 -3
- linkml-1.6.5.dist-info/LICENSE +13 -0
- {linkml-1.6.3.dist-info → linkml-1.6.5.dist-info}/METADATA +1 -1
- {linkml-1.6.3.dist-info → linkml-1.6.5.dist-info}/RECORD +19 -19
- linkml-1.6.3.dist-info/LICENSE +0 -116
- {linkml-1.6.3.dist-info → linkml-1.6.5.dist-info}/WHEEL +0 -0
- {linkml-1.6.3.dist-info → linkml-1.6.5.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,11 @@
|
|
1
|
-
{%- if element.title
|
2
|
-
{%- set title = element.title ~ ' (' ~
|
3
|
-
{%- else
|
4
|
-
{%-
|
1
|
+
{%- if element.title %}
|
2
|
+
{%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
|
3
|
+
{%- else %}
|
4
|
+
{%- if gen.use_class_uris -%}
|
5
|
+
{%- set title = element.name -%}
|
6
|
+
{%- else -%}
|
7
|
+
{%- set title = gen.name(element) -%}
|
8
|
+
{%- endif -%}
|
5
9
|
{%- endif -%}
|
6
10
|
|
7
11
|
# Class: {{ title }}
|
@@ -1,7 +1,11 @@
|
|
1
1
|
{%- if element.title %}
|
2
2
|
{%- set title = element.title ~ ' (' ~ element.name ~ ')' -%}
|
3
3
|
{%- else %}
|
4
|
-
{%-
|
4
|
+
{%- if gen.use_slot_uris -%}
|
5
|
+
{%- set title = element.name -%}
|
6
|
+
{%- else -%}
|
7
|
+
{%- set title = gen.name(element) -%}
|
8
|
+
{%- endif -%}
|
5
9
|
{%- endif -%}
|
6
10
|
|
7
11
|
# Slot: {{ title }}
|
linkml/generators/docgen.py
CHANGED
@@ -150,6 +150,7 @@ class DocGenerator(Generator):
|
|
150
150
|
gen_slots: bool = field(default_factory=lambda: True)
|
151
151
|
no_types_dir: bool = field(default_factory=lambda: False)
|
152
152
|
use_slot_uris: bool = field(default_factory=lambda: False)
|
153
|
+
use_class_uris: bool = field(default_factory=lambda: False)
|
153
154
|
hierarchical_class_view: bool = field(default_factory=lambda: False)
|
154
155
|
|
155
156
|
def __post_init__(self):
|
@@ -331,6 +332,13 @@ class DocGenerator(Generator):
|
|
331
332
|
return curie.split(":")[1]
|
332
333
|
|
333
334
|
return underscore(element.name)
|
335
|
+
elif type(element).class_name == "class_definition":
|
336
|
+
if self.use_class_uris:
|
337
|
+
curie = self.schemaview.get_uri(element)
|
338
|
+
if curie:
|
339
|
+
return curie.split(":")[1]
|
340
|
+
|
341
|
+
return camelcase(element.name)
|
334
342
|
else:
|
335
343
|
return camelcase(element.name)
|
336
344
|
|
@@ -374,6 +382,10 @@ class DocGenerator(Generator):
|
|
374
382
|
if self._is_external(e):
|
375
383
|
return self.uri_link(e)
|
376
384
|
elif isinstance(e, ClassDefinition):
|
385
|
+
if self.use_class_uris:
|
386
|
+
curie = self.schemaview.get_uri(e)
|
387
|
+
if curie is not None:
|
388
|
+
return self._markdown_link(n=curie.split(":")[1], name=e.name)
|
377
389
|
return self._markdown_link(camelcase(e.name))
|
378
390
|
elif isinstance(e, EnumDefinition):
|
379
391
|
return self._markdown_link(camelcase(e.name))
|
@@ -474,7 +486,7 @@ class DocGenerator(Generator):
|
|
474
486
|
) -> str:
|
475
487
|
indent = " " * depth * 4
|
476
488
|
|
477
|
-
if self.use_slot_uris:
|
489
|
+
if self.use_slot_uris or self.use_class_uris:
|
478
490
|
name = self.schemaview.get_element(element).name
|
479
491
|
else:
|
480
492
|
name = self.name(element)
|
@@ -878,6 +890,11 @@ class DocGenerator(Generator):
|
|
878
890
|
default=False,
|
879
891
|
help="Use IDs from slot_uri instead of names",
|
880
892
|
)
|
893
|
+
@click.option(
|
894
|
+
"--use-class-uris/--no-use-class-uris",
|
895
|
+
default=False,
|
896
|
+
help="Use IDs from class_uri instead of names",
|
897
|
+
)
|
881
898
|
@click.option(
|
882
899
|
"--hierarchical-class-view/--no-hierarchical-class-view",
|
883
900
|
default=True,
|
@@ -889,7 +906,17 @@ class DocGenerator(Generator):
|
|
889
906
|
)
|
890
907
|
@click.version_option(__version__, "-V", "--version")
|
891
908
|
@click.command()
|
892
|
-
def cli(
|
909
|
+
def cli(
|
910
|
+
yamlfile,
|
911
|
+
directory,
|
912
|
+
index_name,
|
913
|
+
dialect,
|
914
|
+
template_directory,
|
915
|
+
use_slot_uris,
|
916
|
+
use_class_uris,
|
917
|
+
hierarchical_class_view,
|
918
|
+
**args,
|
919
|
+
):
|
893
920
|
"""Generate documentation folder from a LinkML YAML schema
|
894
921
|
|
895
922
|
Currently a default set of templates for markdown is provided (see the
|
@@ -915,6 +942,7 @@ def cli(yamlfile, directory, index_name, dialect, template_directory, use_slot_u
|
|
915
942
|
dialect=dialect,
|
916
943
|
template_directory=template_directory,
|
917
944
|
use_slot_uris=use_slot_uris,
|
945
|
+
use_class_uris=use_class_uris,
|
918
946
|
hierarchical_class_view=hierarchical_class_view,
|
919
947
|
index_name=index_name,
|
920
948
|
**args,
|
linkml/generators/excelgen.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
|
-
import
|
3
|
-
from
|
2
|
+
from dataclasses import dataclass, field
|
3
|
+
from pathlib import Path
|
4
4
|
from typing import List
|
5
5
|
|
6
6
|
import click
|
@@ -8,78 +8,80 @@ from linkml_runtime.utils.schemaview import SchemaView
|
|
8
8
|
from openpyxl import Workbook
|
9
9
|
from openpyxl.utils import get_column_letter
|
10
10
|
from openpyxl.worksheet.datavalidation import DataValidation
|
11
|
-
from openpyxl.worksheet.worksheet import Worksheet
|
12
11
|
|
13
12
|
from linkml._version import __version__
|
14
13
|
from linkml.utils.generator import Generator, shared_arguments
|
15
|
-
from linkml.utils.helpers import convert_to_snake_case
|
16
14
|
|
17
15
|
|
18
16
|
@dataclass
|
19
17
|
class ExcelGenerator(Generator):
|
20
18
|
# ClassVars
|
21
|
-
generatorname =
|
19
|
+
generatorname = Path(__file__).name
|
22
20
|
generatorversion = "0.1.1"
|
23
21
|
valid_formats = ["xlsx"]
|
24
22
|
uses_schemaloader = False
|
25
23
|
requires_metamodel = False
|
26
24
|
|
25
|
+
split_workbook_by_class: bool = field(default_factory=lambda: False)
|
26
|
+
|
27
27
|
def __post_init__(self) -> None:
|
28
28
|
super().__post_init__()
|
29
29
|
self.logger = logging.getLogger(__name__)
|
30
30
|
self.schemaview = SchemaView(self.schema)
|
31
31
|
|
32
|
-
def create_workbook(self,
|
32
|
+
def create_workbook(self, workbook_path: Path) -> Workbook:
|
33
33
|
"""
|
34
34
|
Creates an Excel workbook using the openpyxl library and returns it.
|
35
35
|
|
36
|
-
:param
|
36
|
+
:param workbook_path: Path of the workbook to be created.
|
37
37
|
:return: An openpyxl Workbook object representing the newly created workbook.
|
38
38
|
"""
|
39
39
|
workbook = Workbook()
|
40
|
-
workbook.
|
40
|
+
workbook.save(workbook_path)
|
41
41
|
return workbook
|
42
42
|
|
43
|
-
def
|
44
|
-
"""
|
45
|
-
Returns the name of the given workbook.
|
46
|
-
|
47
|
-
:param workbook: The workbook whose name should be returned.
|
48
|
-
:return: Name of the workbook.
|
49
|
-
"""
|
50
|
-
return workbook.title
|
51
|
-
|
52
|
-
def remove_worksheet_by_name(self, workbook: Workbook, worksheet_name: str) -> None:
|
53
|
-
"""
|
54
|
-
Remove worksheet from workbook by name.
|
55
|
-
"""
|
56
|
-
worksheet = workbook[worksheet_name]
|
57
|
-
workbook.remove(worksheet)
|
58
|
-
|
59
|
-
def create_worksheet(self, workbook: Workbook, worksheet_name: str) -> Worksheet:
|
43
|
+
def create_workbook_and_worksheets(self, output_path: Path, classes: List[str]) -> None:
|
60
44
|
"""
|
61
|
-
Creates
|
45
|
+
Creates a workbook with worksheets for each class.
|
62
46
|
|
63
|
-
:param
|
64
|
-
:param
|
47
|
+
:param output_path: The path where the workbook should be created.
|
48
|
+
:param classes: List of class names for which worksheets should be created.
|
65
49
|
"""
|
66
|
-
|
67
|
-
|
68
|
-
|
50
|
+
workbook = self.create_workbook(output_path)
|
51
|
+
workbook.remove(workbook.active)
|
52
|
+
sv = self.schemaview
|
69
53
|
|
70
|
-
|
54
|
+
for cls_name in classes:
|
55
|
+
cls = sv.get_class(class_name=cls_name, imports=self.mergeimports)
|
56
|
+
if not cls.mixin and not cls.abstract:
|
57
|
+
workbook.create_sheet(cls_name)
|
71
58
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
59
|
+
# Add columns to the worksheet for the current class
|
60
|
+
slots = [s.name for s in sv.class_induced_slots(cls_name, self.mergeimports)]
|
61
|
+
self.add_columns_to_worksheet(workbook, cls_name, slots)
|
62
|
+
workbook.save(output_path)
|
76
63
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
64
|
+
# Add enum validation for columns with enum types
|
65
|
+
enum_list = list(sv.all_enums(imports=self.mergeimports).keys())
|
66
|
+
for s in sv.class_induced_slots(cls_name, self.mergeimports):
|
67
|
+
if s.range in enum_list:
|
68
|
+
pv_list = list(sv.get_enum(s.range).permissible_values.keys())
|
69
|
+
|
70
|
+
# Check if the total length of permissible values is <= 255 characters
|
71
|
+
enum_length = sum(len(value) for value in pv_list)
|
72
|
+
if enum_length <= 255:
|
73
|
+
self.column_enum_validation(workbook, cls_name, s.name, pv_list)
|
74
|
+
else:
|
75
|
+
self.logger.warning(
|
76
|
+
f"'{s.range}' has permissible values with total "
|
77
|
+
"length > 255 characters. Dropdowns may not work properly "
|
78
|
+
f"in {output_path}"
|
79
|
+
)
|
80
|
+
workbook.save(output_path)
|
81
|
+
|
82
|
+
workbook.save(output_path)
|
83
|
+
if self.split_workbook_by_class:
|
84
|
+
self.logger.info(f"The Excel workbooks have been written to {output_path}")
|
83
85
|
|
84
86
|
def add_columns_to_worksheet(self, workbook: Workbook, worksheet_name: str, sheet_headings: List[str]) -> None:
|
85
87
|
"""
|
@@ -96,10 +98,6 @@ class ExcelGenerator(Generator):
|
|
96
98
|
for i, heading in enumerate(sheet_headings):
|
97
99
|
worksheet.cell(row=1, column=i + 1, value=heading)
|
98
100
|
|
99
|
-
# Save the changes to the workbook
|
100
|
-
workbook_name = self.get_workbook_name(workbook)
|
101
|
-
workbook.save(workbook_name)
|
102
|
-
|
103
101
|
def column_enum_validation(
|
104
102
|
self,
|
105
103
|
workbook: Workbook,
|
@@ -129,48 +127,52 @@ class ExcelGenerator(Generator):
|
|
129
127
|
|
130
128
|
dv.add(f"{column_letter}2:{column_letter}1048576")
|
131
129
|
|
132
|
-
workbook_name = self.get_workbook_name(workbook)
|
133
|
-
workbook.save(workbook_name)
|
134
|
-
|
135
130
|
def serialize(self, **kwargs) -> str:
|
136
|
-
|
137
|
-
|
138
|
-
|
131
|
+
sv = self.schemaview
|
132
|
+
classes_to_process = [
|
133
|
+
cls_name
|
134
|
+
for cls_name, cls in sv.all_classes(imports=self.mergeimports).items()
|
135
|
+
if not cls.mixin and not cls.abstract
|
136
|
+
]
|
139
137
|
|
140
|
-
|
141
|
-
|
142
|
-
|
138
|
+
if self.split_workbook_by_class:
|
139
|
+
output_path = Path(self.schema.name + "_worksheets") if not self.output else Path(self.output)
|
140
|
+
output_path = output_path.absolute()
|
143
141
|
|
144
|
-
|
145
|
-
|
146
|
-
if not cls.mixin and not cls.abstract:
|
147
|
-
slots = [s.name for s in sv.class_induced_slots(cls_name, imports=self.mergeimports)]
|
148
|
-
self.add_columns_to_worksheet(workbook, cls_name, slots)
|
142
|
+
if not output_path.is_dir():
|
143
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
149
144
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
for
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
145
|
+
for cls_name in classes_to_process:
|
146
|
+
cls_output_path = output_path.joinpath(f"{cls_name}.xlsx")
|
147
|
+
self.create_workbook_and_worksheets(cls_output_path, [cls_name])
|
148
|
+
self.logger.info(f"The Excel workbook for class '{cls_name}' has been written to {cls_output_path}")
|
149
|
+
else:
|
150
|
+
output_path = Path(self.schema.name + ".xlsx") if not self.output else Path(self.output)
|
151
|
+
output_path = output_path.absolute()
|
152
|
+
|
153
|
+
self.create_workbook_and_worksheets(output_path, classes_to_process)
|
154
|
+
|
155
|
+
self.logger.info(f"The Excel workbook has been written to {output_path}")
|
160
156
|
|
161
157
|
|
162
158
|
@shared_arguments(ExcelGenerator)
|
163
159
|
@click.command()
|
160
|
+
@click.option(
|
161
|
+
"--split-workbook-by-class",
|
162
|
+
is_flag=True,
|
163
|
+
default=False,
|
164
|
+
help="""Split model into separate Excel workbooks/files, one for each class""",
|
165
|
+
)
|
164
166
|
@click.option(
|
165
167
|
"-o",
|
166
168
|
"--output",
|
167
169
|
type=click.Path(),
|
168
|
-
help="""Name of Excel spreadsheet to be created""",
|
170
|
+
help="""Name of Excel spreadsheet to be created, or name of directory to create split workbooks in""",
|
169
171
|
)
|
170
172
|
@click.version_option(__version__, "-V", "--version")
|
171
|
-
def cli(yamlfile, **kwargs):
|
173
|
+
def cli(yamlfile, split_workbook_by_class, **kwargs):
|
172
174
|
"""Generate Excel representation of a LinkML model"""
|
173
|
-
ExcelGenerator(yamlfile, **kwargs).serialize(**kwargs)
|
175
|
+
ExcelGenerator(yamlfile, split_workbook_by_class=split_workbook_by_class, **kwargs).serialize(**kwargs)
|
174
176
|
|
175
177
|
|
176
178
|
if __name__ == "__main__":
|
@@ -5,8 +5,8 @@ package {{ doc.package }};
|
|
5
5
|
import java.math.BigDecimal;{% endif -%}
|
6
6
|
{% if f.range.startswith('Instant') %}
|
7
7
|
import java.time.Instant;{% endif -%}
|
8
|
-
{% if f.range.startswith('
|
9
|
-
import java.time.
|
8
|
+
{% if f.range.startswith('LocalDate') %}
|
9
|
+
import java.time.LocalDate;{% endif -%}
|
10
10
|
{% if f.range.startswith('ZonedDateTime') %}
|
11
11
|
import java.time.ZonedDateTime;{% endif -%}
|
12
12
|
{% if f.range.startswith('List') %}
|
linkml/generators/javagen.py
CHANGED
@@ -45,9 +45,9 @@ TYPEMAP = {
|
|
45
45
|
"xsd:float": "Float",
|
46
46
|
"xsd:double": "Double",
|
47
47
|
"xsd:boolean": "boolean",
|
48
|
-
"
|
49
|
-
"
|
50
|
-
"
|
48
|
+
"xsd:dateTime": "ZonedDateTime",
|
49
|
+
"xsd:date": "LocalDate",
|
50
|
+
"xsd:time": "Instant",
|
51
51
|
"xsd:anyURI": "String",
|
52
52
|
"xsd:decimal": "BigDecimal",
|
53
53
|
}
|
@@ -65,19 +65,23 @@ class JsonSchema(UserDict):
|
|
65
65
|
identifier_name = self._lax_forward_refs.pop(canonical_name)
|
66
66
|
self.add_lax_def(canonical_name, identifier_name)
|
67
67
|
|
68
|
-
def add_lax_def(self,
|
68
|
+
def add_lax_def(self, names: Union[str, List[str]], identifier_name: str) -> None:
|
69
69
|
# JSON-Schema does not have inheritance,
|
70
70
|
# so we duplicate slots from inherited parents and mixins
|
71
71
|
# Maps e.g. Person --> Person__identifier_optional
|
72
72
|
# for use when Person is a range of an inlined-as-dict slot
|
73
|
-
|
73
|
+
if isinstance(names, str):
|
74
|
+
names = [names]
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
76
|
+
for name in names:
|
77
|
+
canonical_name = camelcase(name)
|
78
|
+
|
79
|
+
if "$defs" not in self or canonical_name not in self["$defs"]:
|
80
|
+
self._lax_forward_refs[canonical_name] = identifier_name
|
81
|
+
else:
|
82
|
+
lax_cls = deepcopy(self["$defs"][canonical_name])
|
83
|
+
lax_cls["required"].remove(identifier_name)
|
84
|
+
self["$defs"][canonical_name + self.OPTIONAL_IDENTIFIER_SUFFIX] = lax_cls
|
81
85
|
|
82
86
|
def add_property(self, name: str, subschema: "JsonSchema", required: bool = False) -> None:
|
83
87
|
canonical_name = underscore(name)
|
linkml/generators/pydanticgen.py
CHANGED
@@ -32,7 +32,7 @@ from linkml.utils.generator import shared_arguments
|
|
32
32
|
from linkml.utils.ifabsent_functions import ifabsent_value_declaration
|
33
33
|
|
34
34
|
|
35
|
-
def default_template(pydantic_ver: str = "1") -> str:
|
35
|
+
def default_template(pydantic_ver: str = "1", extra_fields: str = "forbid") -> str:
|
36
36
|
"""Constructs a default template for pydantic classes based on the version of pydantic"""
|
37
37
|
### HEADER ###
|
38
38
|
template = """
|
@@ -64,7 +64,7 @@ version = "{{version if version else None}}"
|
|
64
64
|
"""
|
65
65
|
### BASE MODEL ###
|
66
66
|
if pydantic_ver == "1":
|
67
|
-
template += """
|
67
|
+
template += f"""
|
68
68
|
class WeakRefShimBaseModel(BaseModel):
|
69
69
|
__slots__ = '__weakref__'
|
70
70
|
|
@@ -72,18 +72,18 @@ class ConfiguredBaseModel(WeakRefShimBaseModel,
|
|
72
72
|
validate_assignment = True,
|
73
73
|
validate_all = True,
|
74
74
|
underscore_attrs_are_private = True,
|
75
|
-
extra =
|
75
|
+
extra = '{extra_fields}',
|
76
76
|
arbitrary_types_allowed = True,
|
77
77
|
use_enum_values = True):
|
78
78
|
pass
|
79
79
|
"""
|
80
80
|
else:
|
81
|
-
template += """
|
81
|
+
template += f"""
|
82
82
|
class ConfiguredBaseModel(BaseModel):
|
83
83
|
model_config = ConfigDict(
|
84
84
|
validate_assignment=True,
|
85
85
|
validate_default=True,
|
86
|
-
extra=
|
86
|
+
extra = '{extra_fields}',
|
87
87
|
arbitrary_types_allowed=True,
|
88
88
|
use_enum_values = True)
|
89
89
|
"""
|
@@ -108,7 +108,46 @@ class {{ e.name }}(str{% if e['values'] %}, Enum{% endif %}):
|
|
108
108
|
{% endfor %}
|
109
109
|
"""
|
110
110
|
### CLASSES ###
|
111
|
-
|
111
|
+
if pydantic_ver == "1":
|
112
|
+
template += """
|
113
|
+
{%- for c in schema.classes.values() %}
|
114
|
+
class {{ c.name }}
|
115
|
+
{%- if class_isa_plus_mixins[c.name] -%}
|
116
|
+
({{class_isa_plus_mixins[c.name]|join(', ')}})
|
117
|
+
{%- else -%}
|
118
|
+
(ConfiguredBaseModel)
|
119
|
+
{%- endif -%}
|
120
|
+
:
|
121
|
+
{% if c.description -%}
|
122
|
+
\"\"\"
|
123
|
+
{{ c.description }}
|
124
|
+
\"\"\"
|
125
|
+
{%- endif %}
|
126
|
+
{% for attr in c.attributes.values() if c.attributes -%}
|
127
|
+
{{attr.name}}: {{ attr.annotations['python_range'].value }} = Field(
|
128
|
+
{%- if predefined_slot_values[c.name][attr.name] -%}
|
129
|
+
{{ predefined_slot_values[c.name][attr.name] }}
|
130
|
+
{%- elif (attr.required or attr.identifier or attr.key) -%}
|
131
|
+
...
|
132
|
+
{%- else -%}
|
133
|
+
None
|
134
|
+
{%- endif -%}
|
135
|
+
{%- if attr.title != None %}, title="{{attr.title}}"{% endif -%}
|
136
|
+
{%- if attr.description %}, description=\"\"\"{{attr.description}}\"\"\"{% endif -%}
|
137
|
+
{%- if attr.pattern %}, regex=\"{{attr.pattern}}\"{% endif -%}
|
138
|
+
{%- if attr.equals_number != None %}, le={{attr.equals_number}}, ge={{attr.equals_number}}
|
139
|
+
{%- else -%}
|
140
|
+
{%- if attr.minimum_value != None %}, ge={{attr.minimum_value}}{% endif -%}
|
141
|
+
{%- if attr.maximum_value != None %}, le={{attr.maximum_value}}{% endif -%}
|
142
|
+
{%- endif -%}
|
143
|
+
)
|
144
|
+
{% else -%}
|
145
|
+
None
|
146
|
+
{% endfor %}
|
147
|
+
{% endfor %}
|
148
|
+
"""
|
149
|
+
elif pydantic_ver == "2":
|
150
|
+
template += """
|
112
151
|
{%- for c in schema.classes.values() %}
|
113
152
|
class {{ c.name }}
|
114
153
|
{%- if class_isa_plus_mixins[c.name] -%}
|
@@ -133,6 +172,7 @@ class {{ c.name }}
|
|
133
172
|
{%- endif -%}
|
134
173
|
{%- if attr.title != None %}, title="{{attr.title}}"{% endif -%}
|
135
174
|
{%- if attr.description %}, description=\"\"\"{{attr.description}}\"\"\"{% endif -%}
|
175
|
+
{%- if attr.pattern %}, pattern=\"{{attr.pattern}}\"{% endif -%}
|
136
176
|
{%- if attr.equals_number != None %}, le={{attr.equals_number}}, ge={{attr.equals_number}}
|
137
177
|
{%- else -%}
|
138
178
|
{%- if attr.minimum_value != None %}, ge={{attr.minimum_value}}{% endif -%}
|
@@ -144,6 +184,7 @@ class {{ c.name }}
|
|
144
184
|
{% endfor %}
|
145
185
|
{% endfor %}
|
146
186
|
"""
|
187
|
+
|
147
188
|
### FWD REFS / REBUILD MODEL ###
|
148
189
|
if pydantic_ver == "1":
|
149
190
|
template += """
|
@@ -196,7 +237,7 @@ class PydanticGenerator(OOCodeGenerator):
|
|
196
237
|
# ObjectVars
|
197
238
|
pydantic_version: str = field(default_factory=lambda: PYDANTIC_VERSION[0])
|
198
239
|
template_file: str = None
|
199
|
-
|
240
|
+
extra_fields: str = field(default_factory=lambda: "forbid")
|
200
241
|
gen_mixin_inheritance: bool = field(default_factory=lambda: True)
|
201
242
|
|
202
243
|
# ObjectVars (identical to pythongen)
|
@@ -454,7 +495,7 @@ class PydanticGenerator(OOCodeGenerator):
|
|
454
495
|
with open(self.template_file) as template_file:
|
455
496
|
template_obj = Template(template_file.read())
|
456
497
|
else:
|
457
|
-
template_obj = Template(default_template(self.pydantic_version))
|
498
|
+
template_obj = Template(default_template(self.pydantic_version, self.extra_fields))
|
458
499
|
|
459
500
|
sv: SchemaView
|
460
501
|
sv = self.schemaview
|
@@ -536,7 +577,7 @@ class PydanticGenerator(OOCodeGenerator):
|
|
536
577
|
underscore=underscore,
|
537
578
|
enums=enums,
|
538
579
|
predefined_slot_values=self.get_predefined_slot_values(),
|
539
|
-
|
580
|
+
extra_fields=self.extra_fields,
|
540
581
|
metamodel_version=self.schema.metamodel_version,
|
541
582
|
version=self.schema.version,
|
542
583
|
class_isa_plus_mixins=self.get_class_isa_plus_mixins(),
|
@@ -548,13 +589,19 @@ class PydanticGenerator(OOCodeGenerator):
|
|
548
589
|
|
549
590
|
|
550
591
|
@shared_arguments(PydanticGenerator)
|
551
|
-
@click.option("--
|
592
|
+
@click.option("--template-file", help="Optional jinja2 template to use for class generation")
|
552
593
|
@click.option(
|
553
|
-
"--
|
594
|
+
"--pydantic-version",
|
554
595
|
type=click.Choice(["1", "2"]),
|
555
596
|
default="1",
|
556
597
|
help="Pydantic version to use (1 or 2)",
|
557
598
|
)
|
599
|
+
@click.option(
|
600
|
+
"--extra-fields",
|
601
|
+
type=click.Choice(["allow", "ignore", "forbid"], case_sensitive=False),
|
602
|
+
default="forbid",
|
603
|
+
help="How to handle extra fields in BaseModel.",
|
604
|
+
)
|
558
605
|
@click.version_option(__version__, "-V", "--version")
|
559
606
|
@click.command()
|
560
607
|
def cli(
|
@@ -566,6 +613,7 @@ def cli(
|
|
566
613
|
classvars=True,
|
567
614
|
slots=True,
|
568
615
|
pydantic_version="1",
|
616
|
+
extra_fields="forbid",
|
569
617
|
**args,
|
570
618
|
):
|
571
619
|
"""Generate pydantic classes to represent a LinkML model"""
|
@@ -573,6 +621,7 @@ def cli(
|
|
573
621
|
yamlfile,
|
574
622
|
template_file=template_file,
|
575
623
|
pydantic_version=pydantic_version,
|
624
|
+
extra_fields=extra_fields,
|
576
625
|
emit_metadata=head,
|
577
626
|
genmeta=genmeta,
|
578
627
|
gen_classvars=classvars,
|
linkml/generators/pythongen.py
CHANGED
@@ -509,6 +509,7 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
509
509
|
initializers += [self.gen_class_variable(cls, slot, False) for slot in slot_variables]
|
510
510
|
|
511
511
|
# Followed by everything else
|
512
|
+
|
512
513
|
slot_variables = self._slot_iter(cls, lambda slot: not slot.required and slot in domain_slots)
|
513
514
|
initializers += [self.gen_class_variable(cls, slot, False) for slot in slot_variables]
|
514
515
|
|
@@ -604,7 +605,7 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
604
605
|
|
605
606
|
def class_reference_type(self, slot: SlotDefinition, cls: Optional[ClassDefinition]) -> Tuple[str, str, str]:
|
606
607
|
"""
|
607
|
-
Return the type of
|
608
|
+
Return the type of slot referencing a class
|
608
609
|
|
609
610
|
:param slot: slot to be typed
|
610
611
|
:param cls: owning class. Used for generating key references
|
@@ -734,6 +735,12 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
734
735
|
return typ_name
|
735
736
|
|
736
737
|
def gen_constructor(self, cls: ClassDefinition) -> Optional[str]:
|
738
|
+
"""
|
739
|
+
Generate python constructor for class
|
740
|
+
|
741
|
+
:param cls: class to generate constructor for
|
742
|
+
:return: python constructor
|
743
|
+
"""
|
737
744
|
rlines: List[str] = []
|
738
745
|
designators = [x for x in self.domain_slots(cls) if x.designates_type]
|
739
746
|
if len(designators) > 0:
|
@@ -845,7 +852,7 @@ dataclasses._init_fn = dataclasses_init_fn_with_kwargs
|
|
845
852
|
elif slot.inlined:
|
846
853
|
slot_range_cls = self.schema.classes[slot.range]
|
847
854
|
identifier = self.class_identifier(slot_range_cls)
|
848
|
-
# If we don't have an identifier and we are expecting to be inlined first class elements
|
855
|
+
# If we don't have an identifier, and we are expecting to be inlined first class elements
|
849
856
|
# (inlined_as_list is not True), we will use the first required field as the key.
|
850
857
|
# Note that this may not always work, but the workaround is straight forward -- set inlined_as_list to
|
851
858
|
# True
|
linkml/generators/shaclgen.py
CHANGED
@@ -51,12 +51,12 @@ class ShaclGenerator(Generator):
|
|
51
51
|
if self.schema.version:
|
52
52
|
print(f"# version: {self.schema.version}")
|
53
53
|
|
54
|
-
def serialize(self, **args) ->
|
54
|
+
def serialize(self, **args) -> str:
|
55
55
|
g = self.as_graph()
|
56
56
|
data = g.serialize(format="turtle" if self.format in ["owl", "ttl"] else self.format)
|
57
57
|
return data
|
58
58
|
|
59
|
-
def as_graph(self) ->
|
59
|
+
def as_graph(self) -> Graph:
|
60
60
|
sv = self.schemaview
|
61
61
|
g = Graph()
|
62
62
|
g.bind("sh", SH)
|
@@ -161,7 +161,7 @@ class SQLAlchemyGenerator(Generator):
|
|
161
161
|
# concatenate the python dataclasses with the sqla code
|
162
162
|
if pydantic:
|
163
163
|
# mixin inheritance doesn't get along with SQLAlchemy's imperative (aka classical) mapping
|
164
|
-
pygen = PydanticGenerator(self.original_schema,
|
164
|
+
pygen = PydanticGenerator(self.original_schema, extra_fields="allow", gen_mixin_inheritance=False)
|
165
165
|
else:
|
166
166
|
pygen = PythonGenerator(self.original_schema)
|
167
167
|
dc_code = pygen.serialize()
|
linkml/utils/generator.py
CHANGED
@@ -223,7 +223,7 @@ class Generator(metaclass=abc.ABCMeta):
|
|
223
223
|
else:
|
224
224
|
if isinstance(schema, SchemaDefinition):
|
225
225
|
# schemaloader based methods require schemas to have been created via SchemaLoader,
|
226
|
-
# which prepopulates some fields (e.g definition_url). If the schema has not been processed through the
|
226
|
+
# which prepopulates some fields (e.g. definition_url). If the schema has not been processed through the
|
227
227
|
# loader, then roundtrip
|
228
228
|
if any(c for c in schema.classes.values() if not c.definition_uri):
|
229
229
|
schema = yaml_dumper.dumps(schema)
|
@@ -339,11 +339,11 @@ class Generator(metaclass=abc.ABCMeta):
|
|
339
339
|
|
340
340
|
def visit_class_slot(self, cls: ClassDefinition, aliased_slot_name: str, slot: SlotDefinition) -> None:
|
341
341
|
"""Visited for each slot in a class. If class level visit_all_slots is true, this is visited once
|
342
|
-
for any class that is inherited (class itself, is_a, mixin, apply_to). Otherwise just the own slots.
|
342
|
+
for any class that is inherited (class itself, is_a, mixin, apply_to). Otherwise, just the own slots.
|
343
343
|
|
344
344
|
@param cls: containing class
|
345
345
|
@param aliased_slot_name: Aliased slot name. May not be unique across all class slots
|
346
|
-
@param slot:
|
346
|
+
@param slot: being visited
|
347
347
|
"""
|
348
348
|
...
|
349
349
|
|
@@ -758,11 +758,28 @@ class Generator(metaclass=abc.ABCMeta):
|
|
758
758
|
# TODO: add lru cache once we get identity into the classes
|
759
759
|
def domain_slots(self, cls: ClassDefinition) -> List[SlotDefinition]:
|
760
760
|
"""Return all slots in the class definition that are owned by the class"""
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
761
|
+
domain_slots = []
|
762
|
+
for slot_name in cls.slots:
|
763
|
+
slot = self.schema.slots[slot_name]
|
764
|
+
|
765
|
+
# add any mixin ancestors here so that slots will be distributed to descendents correctly via mixin
|
766
|
+
# hierarchy.
|
767
|
+
mixin_ancestors = []
|
768
|
+
if cls.mixins:
|
769
|
+
for mixin in cls.mixins:
|
770
|
+
for ancestor in self.schemaview.class_ancestors(mixin, mixins=False):
|
771
|
+
if ancestor not in mixin_ancestors:
|
772
|
+
mixin_ancestors.append(ancestor)
|
773
|
+
|
774
|
+
for mixin_ancestor in mixin_ancestors:
|
775
|
+
if mixin_ancestor not in cls.mixins:
|
776
|
+
cls.mixins.append(mixin_ancestor)
|
777
|
+
|
778
|
+
# Check if the class is in the domain of the slot or if any of its mixins are in the domain
|
779
|
+
if cls.name in slot.domain_of or (set(cls.mixins).intersection(slot.domain_of)):
|
780
|
+
domain_slots.append(slot)
|
781
|
+
|
782
|
+
return domain_slots
|
766
783
|
|
767
784
|
def add_mappings(self, defn: Definition) -> None:
|
768
785
|
"""
|
linkml/utils/schemaloader.py
CHANGED
@@ -691,7 +691,7 @@ class SchemaLoader:
|
|
691
691
|
cls.is_a,
|
692
692
|
)
|
693
693
|
for mixin in cls.mixins:
|
694
|
-
# Note that apply_to has
|
694
|
+
# Note that apply_to has been injected as a faux mixin, so it gets covered here
|
695
695
|
if mixin in self.schema.classes:
|
696
696
|
self.merge_class(self.schema.classes[mixin], merged_classes)
|
697
697
|
merge_classes(self.schema, cls, self.schema.classes[mixin], True)
|
@@ -51,12 +51,15 @@ class ValidationContext:
|
|
51
51
|
return jsonschema_gen.generate()
|
52
52
|
|
53
53
|
def pydantic_model(self, *, closed: bool):
|
54
|
-
module = self._pydantic_module(closed)
|
54
|
+
module = self._pydantic_module(closed=closed)
|
55
55
|
return module.__dict__[self._target_class]
|
56
56
|
|
57
57
|
@lru_cache
|
58
|
-
def _pydantic_module(self,
|
59
|
-
return PydanticGenerator(
|
58
|
+
def _pydantic_module(self, *, closed: bool):
|
59
|
+
return PydanticGenerator(
|
60
|
+
self._schema,
|
61
|
+
extra_fields="forbid" if closed else "ignore" if closed is None else "allow",
|
62
|
+
).compile_module()
|
60
63
|
|
61
64
|
def _get_target_class(self, target_class: Optional[str] = None) -> str:
|
62
65
|
if target_class is None:
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Apache-2.0
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
@@ -6,29 +6,29 @@ 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=
|
9
|
+
linkml/generators/docgen/class.md.jinja2,sha256=05Kbl83ApOMzA7gZeRJjPU7jkZHCIsaKN1BYWNMRTfM,3275
|
10
10
|
linkml/generators/docgen/class_diagram.md.jinja2,sha256=ShRhNnIae54Y_4zrfXuIF6BjX8oCHRZJnovE8G1fjOU,2542
|
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
|
14
14
|
linkml/generators/docgen/index.tex.jinja2,sha256=Go_EA-_N4JUpbOYbk3OY11mz5yV70VF2l2sMtgIPWw4,501
|
15
15
|
linkml/generators/docgen/schema.md.jinja2,sha256=xlENfnzNRYgPT_0tdqNFxgklVM4Qf5BuzhFVvSMDuxs,70
|
16
|
-
linkml/generators/docgen/slot.md.jinja2,sha256=
|
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=zsLzbXN2t9pafQubEnb7QshufMKBMqUWjdLE1OyFyq8,33296
|
20
20
|
linkml/generators/dotgen.py,sha256=CnbVY6CO1OMuiYXYnvxgNN2IW1mtOQW-J-QnwZlXkUI,5012
|
21
21
|
linkml/generators/erdiagramgen.py,sha256=Gu-_nhLuEPTsYYaoV6tNS1V6cZ2dNJdm6YwxC0VGl7g,10315
|
22
|
-
linkml/generators/excelgen.py,sha256=
|
22
|
+
linkml/generators/excelgen.py,sha256=ClzWs3wO-QjH2XzzQVUsGF2n6fnoozmXopxPYDEJyPs,7232
|
23
23
|
linkml/generators/golanggen.py,sha256=Dnl7dhmb1AIK3Is7KRaUbxPd3kBTjWuspFqardiBTJ8,5751
|
24
24
|
linkml/generators/golrgen.py,sha256=tIsbsr4SM9HxeK7TCUwnq-GdSKZ_qW5f7fybg_aqCZE,3436
|
25
25
|
linkml/generators/graphqlgen.py,sha256=6qZpI0rwg3ypsv_KrLVzXgdsJfR8LNPqgMwaRwzwnDs,2151
|
26
26
|
linkml/generators/javagen/example_template.java.jinja2,sha256=ec4CVTv_0zS7V5Y-1E6H4lRraya10gfX7BEMBlu38X4,444
|
27
|
-
linkml/generators/javagen/java_record_template.jinja2,sha256=
|
28
|
-
linkml/generators/javagen.py,sha256=
|
27
|
+
linkml/generators/javagen/java_record_template.jinja2,sha256=OQZffLSy_xR3FIhQMltvrYyVeut7l2Q-tzK7AOiVmWs,1729
|
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=CWTvj7n8pWomRqeb-vmG-z99TpzzvBu0UIbBRRag4eI,23958
|
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,16 +39,16 @@ 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=EVgS5bDzFTm3WAuMg3lC3rzdcaW-hgpq99qZA4nksSY,9544
|
41
41
|
linkml/generators/protogen.py,sha256=9YfxBZkQdBWwsUbstxEUR4xRWNuAKSfz9zXPhgIYePU,2328
|
42
|
-
linkml/generators/pydanticgen.py,sha256=
|
43
|
-
linkml/generators/pythongen.py,sha256=
|
42
|
+
linkml/generators/pydanticgen.py,sha256=rH__R3Pt7TKQzG2DBo1R5OehQG3FaBMCjXBzZlAWMqw,23742
|
43
|
+
linkml/generators/pythongen.py,sha256=7XNlOpScOOpxpo9Q_sasDOZFYaKifbXWQL-OKczpkfY,52327
|
44
44
|
linkml/generators/rdfgen.py,sha256=LxzYBaFEkV7rlf54nWv_6H6AGcWMRXwkaeVXq9VYEc8,2693
|
45
|
-
linkml/generators/shaclgen.py,sha256=
|
45
|
+
linkml/generators/shaclgen.py,sha256=KxNmDZW2ciCuSqUhJ65TxLTjF8jME1FmN5SaWJCuW9k,8662
|
46
46
|
linkml/generators/shexgen.py,sha256=Awtn5SyjS-TUcVCwMdT0F7hNO4K8VcSCYBaFru45Mwg,8994
|
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
|
50
50
|
linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py,sha256=u4ZpponG1h6XROrOHGOf_0H2e6xL1_s8twAOA-gx94A,1622
|
51
|
-
linkml/generators/sqlalchemygen.py,sha256=
|
51
|
+
linkml/generators/sqlalchemygen.py,sha256=XjvyCYr9h0EsFaKy4y-lMXunYw4dnk9vSpwlPjZK8gU,9186
|
52
52
|
linkml/generators/sqlddlgen.py,sha256=t7U0-ZOWnulA7CMrlaih73H7fQdaGNRhdVLmvWGxFT4,18436
|
53
53
|
linkml/generators/sqltablegen.py,sha256=h_zVuNC8huRzzTa9nSHNWBxq-4TuLq7nR5nZfpDnWiM,11481
|
54
54
|
linkml/generators/sssomgen.py,sha256=yur3q7so9uwIELWZaZRzkJwNbz_ppBL7IQki9XLIM3k,6879
|
@@ -86,7 +86,7 @@ linkml/utils/converter.py,sha256=rdhCI7Tsjddr3o1rVBfMq5gQubk_GE6fqlBBmyxI5_M,627
|
|
86
86
|
linkml/utils/datautils.py,sha256=2XWM9LBSVp8v3SwIZECrX3SjDUYzdnP-syjp6YdL89E,3734
|
87
87
|
linkml/utils/datavalidator.py,sha256=kBdWaVi8IZT1bOwEJgJYx-wZAb_PTBObB9nHpYORfKA,472
|
88
88
|
linkml/utils/execute_tutorial.py,sha256=T4kHTSyz3ItJGEUZxVjR-3yLVKnOr5Ix4NMGE47-IuE,6912
|
89
|
-
linkml/utils/generator.py,sha256=
|
89
|
+
linkml/utils/generator.py,sha256=dW9kfVL-7an0ieXR5HLe8bqOyEgDGAoIzdLOu_TFQhc,39101
|
90
90
|
linkml/utils/helpers.py,sha256=yR8n4zFA5wPcYC7xzRuNF3wO16vG80v6j7DM3qTNmIc,447
|
91
91
|
linkml/utils/ifabsent_functions.py,sha256=FZwceqwlq81lMPDsdNfSHhtzDXSf8F4cbbhRdnDzjss,5765
|
92
92
|
linkml/utils/logictools.py,sha256=GSmBiobC49TcQjE08RtXEE3JwJEOV7eEREio25uJiFs,21184
|
@@ -94,7 +94,7 @@ linkml/utils/mergeutils.py,sha256=QVm2iQB4v_L2rSvPBsPe9C865R03BgV3TzlPoTTTwWQ,90
|
|
94
94
|
linkml/utils/rawloader.py,sha256=QB7Rdvy4o4ZJEWBWa2_2xzz2TOh_6Oe4slvUn8IBVIc,4329
|
95
95
|
linkml/utils/schema_builder.py,sha256=WLSit3J4lTifaFLLWTwjqIRiTru1pqvTIUuC1TrxS6Y,9902
|
96
96
|
linkml/utils/schema_fixer.py,sha256=rjwJB5ukfrgc0Z-j3mKSNzRMkHPp_k_zFKaFNIPeIv8,15086
|
97
|
-
linkml/utils/schemaloader.py,sha256=
|
97
|
+
linkml/utils/schemaloader.py,sha256=bBSTqimMDTFH2FcKtRz99dKNJzV_myPsZSkIFp_6-A0,46421
|
98
98
|
linkml/utils/schemasynopsis.py,sha256=6NKa89bkZfZQE9QM0St-6xQcrsHPkYmBgnnWnlgAcQ4,18455
|
99
99
|
linkml/utils/sqlutils.py,sha256=86XeEbfY0Dk-EObw4q5-dxyzSeBtmIhjqqyDcR8ALS0,16591
|
100
100
|
linkml/utils/typereferences.py,sha256=8Yfuz9-HAwOPoJLbIcO_sY9zf32hvPRzGeSOzECfMWA,2232
|
@@ -113,7 +113,7 @@ linkml/validator/plugins/pydantic_validation_plugin.py,sha256=C-Vp74bz5oqp5V-iuh
|
|
113
113
|
linkml/validator/plugins/recommended_slots_plugin.py,sha256=kOdoYQyye47nLA7BjorVmydS84nGpiVy3MoCbPq1Ymo,2308
|
114
114
|
linkml/validator/plugins/validation_plugin.py,sha256=9SMHF8b2bgG9-8351e8bY676e0A4aEBJSXvMjMF5kXg,1548
|
115
115
|
linkml/validator/report.py,sha256=kkkuh-IZF9--cO-2wGjwP3PDLvOcjjvC8AOlxXUIOAM,870
|
116
|
-
linkml/validator/validation_context.py,sha256=
|
116
|
+
linkml/validator/validation_context.py,sha256=MmOwLk4cF_Cy7fPdFK61Eti3c3dgzKSIu6r_PmkkoZs,2388
|
117
117
|
linkml/validator/validator.py,sha256=jOSdYyC8QIm1GWmllM7Z1_GV-2VO3hwEwdF2AHE-DNY,5476
|
118
118
|
linkml/validators/__init__.py,sha256=43W3J5NPKhwa3ZFHLRYsJMocwQKWGYCF9Ki9r0ccGbc,202
|
119
119
|
linkml/validators/jsonschemavalidator.py,sha256=_v0finzU2RGPC5xo0CylYge9XkY7oAigcly2SKLwFuI,7865
|
@@ -123,8 +123,8 @@ linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
123
123
|
linkml/workspaces/datamodel/workspaces.py,sha256=4HdkqweGNfMPqnB1_Onc9DcTfkhoagTRcqruh08nRoI,14905
|
124
124
|
linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
|
125
125
|
linkml/workspaces/example_runner.py,sha256=hblnsZVntuwFO4vqcwl_K5XH6jxb52xCtvdc7Sfq_Yc,11452
|
126
|
-
linkml-1.6.
|
127
|
-
linkml-1.6.
|
128
|
-
linkml-1.6.
|
129
|
-
linkml-1.6.
|
130
|
-
linkml-1.6.
|
126
|
+
linkml-1.6.5.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
|
127
|
+
linkml-1.6.5.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
|
128
|
+
linkml-1.6.5.dist-info/METADATA,sha256=dB0BnsijpuHie4nRiNeQ2N5mLQrr0pCu_6msKi2eWZo,3496
|
129
|
+
linkml-1.6.5.dist-info/entry_points.txt,sha256=za8r49Z5gcz3rAYTZLbxw5EPZr1rGuxSe1uiRUpf8R0,2143
|
130
|
+
linkml-1.6.5.dist-info/RECORD,,
|
linkml-1.6.3.dist-info/LICENSE
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
CC0 1.0 Universal
|
2
|
-
|
3
|
-
Statement of Purpose
|
4
|
-
|
5
|
-
The laws of most jurisdictions throughout the world automatically confer
|
6
|
-
exclusive Copyright and Related Rights (defined below) upon the creator and
|
7
|
-
subsequent owner(s) (each and all, an "owner") of an original work of
|
8
|
-
authorship and/or a database (each, a "Work").
|
9
|
-
|
10
|
-
Certain owners wish to permanently relinquish those rights to a Work for the
|
11
|
-
purpose of contributing to a commons of creative, cultural and scientific
|
12
|
-
works ("Commons") that the public can reliably and without fear of later
|
13
|
-
claims of infringement build upon, modify, incorporate in other works, reuse
|
14
|
-
and redistribute as freely as possible in any form whatsoever and for any
|
15
|
-
purposes, including without limitation commercial purposes. These owners may
|
16
|
-
contribute to the Commons to promote the ideal of a free culture and the
|
17
|
-
further production of creative, cultural and scientific works, or to gain
|
18
|
-
reputation or greater distribution for their Work in part through the use and
|
19
|
-
efforts of others.
|
20
|
-
|
21
|
-
For these and/or other purposes and motivations, and without any expectation
|
22
|
-
of additional consideration or compensation, the person associating CC0 with a
|
23
|
-
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
24
|
-
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
25
|
-
and publicly distribute the Work under its terms, with knowledge of his or her
|
26
|
-
Copyright and Related Rights in the Work and the meaning and intended legal
|
27
|
-
effect of CC0 on those rights.
|
28
|
-
|
29
|
-
1. Copyright and Related Rights. A Work made available under CC0 may be
|
30
|
-
protected by copyright and related or neighboring rights ("Copyright and
|
31
|
-
Related Rights"). Copyright and Related Rights include, but are not limited
|
32
|
-
to, the following:
|
33
|
-
|
34
|
-
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
35
|
-
and translate a Work;
|
36
|
-
|
37
|
-
ii. moral rights retained by the original author(s) and/or performer(s);
|
38
|
-
|
39
|
-
iii. publicity and privacy rights pertaining to a person's image or likeness
|
40
|
-
depicted in a Work;
|
41
|
-
|
42
|
-
iv. rights protecting against unfair competition in regards to a Work,
|
43
|
-
subject to the limitations in paragraph 4(a), below;
|
44
|
-
|
45
|
-
v. rights protecting the extraction, dissemination, use and reuse of data in
|
46
|
-
a Work;
|
47
|
-
|
48
|
-
vi. database rights (such as those arising under Directive 96/9/EC of the
|
49
|
-
European Parliament and of the Council of 11 March 1996 on the legal
|
50
|
-
protection of databases, and under any national implementation thereof,
|
51
|
-
including any amended or successor version of such directive); and
|
52
|
-
|
53
|
-
vii. other similar, equivalent or corresponding rights throughout the world
|
54
|
-
based on applicable law or treaty, and any national implementations thereof.
|
55
|
-
|
56
|
-
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
57
|
-
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
58
|
-
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
59
|
-
and Related Rights and associated claims and causes of action, whether now
|
60
|
-
known or unknown (including existing as well as future claims and causes of
|
61
|
-
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
62
|
-
duration provided by applicable law or treaty (including future time
|
63
|
-
extensions), (iii) in any current or future medium and for any number of
|
64
|
-
copies, and (iv) for any purpose whatsoever, including without limitation
|
65
|
-
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
66
|
-
the Waiver for the benefit of each member of the public at large and to the
|
67
|
-
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
68
|
-
shall not be subject to revocation, rescission, cancellation, termination, or
|
69
|
-
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
70
|
-
by the public as contemplated by Affirmer's express Statement of Purpose.
|
71
|
-
|
72
|
-
3. Public License Fallback. Should any part of the Waiver for any reason be
|
73
|
-
judged legally invalid or ineffective under applicable law, then the Waiver
|
74
|
-
shall be preserved to the maximum extent permitted taking into account
|
75
|
-
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
76
|
-
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
77
|
-
non transferable, non sublicensable, non exclusive, irrevocable and
|
78
|
-
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
79
|
-
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
80
|
-
provided by applicable law or treaty (including future time extensions), (iii)
|
81
|
-
in any current or future medium and for any number of copies, and (iv) for any
|
82
|
-
purpose whatsoever, including without limitation commercial, advertising or
|
83
|
-
promotional purposes (the "License"). The License shall be deemed effective as
|
84
|
-
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
85
|
-
License for any reason be judged legally invalid or ineffective under
|
86
|
-
applicable law, such partial invalidity or ineffectiveness shall not
|
87
|
-
invalidate the remainder of the License, and in such case Affirmer hereby
|
88
|
-
affirms that he or she will not (i) exercise any of his or her remaining
|
89
|
-
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
90
|
-
and causes of action with respect to the Work, in either case contrary to
|
91
|
-
Affirmer's express Statement of Purpose.
|
92
|
-
|
93
|
-
4. Limitations and Disclaimers.
|
94
|
-
|
95
|
-
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
96
|
-
surrendered, licensed or otherwise affected by this document.
|
97
|
-
|
98
|
-
b. Affirmer offers the Work as-is and makes no representations or warranties
|
99
|
-
of any kind concerning the Work, express, implied, statutory or otherwise,
|
100
|
-
including without limitation warranties of title, merchantability, fitness
|
101
|
-
for a particular purpose, non infringement, or the absence of latent or
|
102
|
-
other defects, accuracy, or the present or absence of errors, whether or not
|
103
|
-
discoverable, all to the greatest extent permissible under applicable law.
|
104
|
-
|
105
|
-
c. Affirmer disclaims responsibility for clearing rights of other persons
|
106
|
-
that may apply to the Work or any use thereof, including without limitation
|
107
|
-
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
108
|
-
disclaims responsibility for obtaining any necessary consents, permissions
|
109
|
-
or other rights required for any use of the Work.
|
110
|
-
|
111
|
-
d. Affirmer understands and acknowledges that Creative Commons is not a
|
112
|
-
party to this document and has no duty or obligation with respect to this
|
113
|
-
CC0 or use of the Work.
|
114
|
-
|
115
|
-
For more information, please see
|
116
|
-
<http://creativecommons.org/publicdomain/zero/1.0/>
|
File without changes
|
File without changes
|