linkml 1.9.4rc1__py3-none-any.whl → 1.9.5rc1__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/main.py +4 -0
- linkml/generators/__init__.py +2 -0
- linkml/generators/common/build.py +5 -20
- linkml/generators/common/template.py +289 -3
- linkml/generators/docgen.py +55 -10
- linkml/generators/erdiagramgen.py +9 -5
- linkml/generators/graphqlgen.py +32 -6
- linkml/generators/jsonldcontextgen.py +78 -12
- linkml/generators/jsonschemagen.py +29 -12
- linkml/generators/mermaidclassdiagramgen.py +21 -3
- linkml/generators/owlgen.py +4 -1
- linkml/generators/panderagen/dataframe_class.py +13 -0
- linkml/generators/panderagen/dataframe_field.py +50 -0
- linkml/generators/panderagen/linkml_pandera_validator.py +186 -0
- linkml/generators/panderagen/panderagen.py +22 -5
- linkml/generators/panderagen/panderagen_class_based/class.jinja2 +70 -13
- linkml/generators/panderagen/panderagen_class_based/custom_checks.jinja2 +27 -0
- linkml/generators/panderagen/panderagen_class_based/enums.jinja2 +3 -3
- linkml/generators/panderagen/panderagen_class_based/pandera.jinja2 +12 -2
- linkml/generators/panderagen/panderagen_class_based/slots.jinja2 +19 -17
- linkml/generators/panderagen/slot_generator_mixin.py +143 -16
- linkml/generators/panderagen/transforms/__init__.py +19 -0
- linkml/generators/panderagen/transforms/collection_dict_model_transform.py +62 -0
- linkml/generators/panderagen/transforms/list_dict_model_transform.py +66 -0
- linkml/generators/panderagen/transforms/model_transform.py +8 -0
- linkml/generators/panderagen/transforms/nested_struct_model_transform.py +27 -0
- linkml/generators/panderagen/transforms/simple_dict_model_transform.py +86 -0
- linkml/generators/plantumlgen.py +17 -11
- linkml/generators/pydanticgen/pydanticgen.py +53 -2
- linkml/generators/pydanticgen/template.py +45 -233
- linkml/generators/pydanticgen/templates/attribute.py.jinja +1 -0
- linkml/generators/pydanticgen/templates/base_model.py.jinja +16 -2
- linkml/generators/pydanticgen/templates/imports.py.jinja +1 -1
- linkml/generators/rdfgen.py +11 -2
- linkml/generators/rustgen/__init__.py +3 -0
- linkml/generators/rustgen/build.py +94 -0
- linkml/generators/rustgen/cli.py +65 -0
- linkml/generators/rustgen/rustgen.py +1038 -0
- linkml/generators/rustgen/template.py +865 -0
- linkml/generators/rustgen/templates/Cargo.toml.jinja +42 -0
- linkml/generators/rustgen/templates/anything.rs.jinja +142 -0
- linkml/generators/rustgen/templates/as_key_value.rs.jinja +56 -0
- linkml/generators/rustgen/templates/class_module.rs.jinja +8 -0
- linkml/generators/rustgen/templates/enum.rs.jinja +54 -0
- linkml/generators/rustgen/templates/file.rs.jinja +62 -0
- linkml/generators/rustgen/templates/import.rs.jinja +4 -0
- linkml/generators/rustgen/templates/imports.rs.jinja +8 -0
- linkml/generators/rustgen/templates/poly.rs.jinja +9 -0
- linkml/generators/rustgen/templates/poly_containers.rs.jinja +439 -0
- linkml/generators/rustgen/templates/poly_trait.rs.jinja +15 -0
- linkml/generators/rustgen/templates/poly_trait_impl.rs.jinja +5 -0
- linkml/generators/rustgen/templates/poly_trait_impl_orsubtype.rs.jinja +5 -0
- linkml/generators/rustgen/templates/poly_trait_property.rs.jinja +8 -0
- linkml/generators/rustgen/templates/poly_trait_property_impl.rs.jinja +132 -0
- linkml/generators/rustgen/templates/poly_trait_property_match.rs.jinja +10 -0
- linkml/generators/rustgen/templates/property.rs.jinja +19 -0
- linkml/generators/rustgen/templates/pyproject.toml.jinja +10 -0
- linkml/generators/rustgen/templates/serde_utils.rs.jinja +310 -0
- linkml/generators/rustgen/templates/slot_range_as_union.rs.jinja +61 -0
- linkml/generators/rustgen/templates/struct.rs.jinja +75 -0
- linkml/generators/rustgen/templates/struct_or_subtype_enum.rs.jinja +108 -0
- linkml/generators/rustgen/templates/typealias.rs.jinja +13 -0
- linkml/generators/sqltablegen.py +18 -16
- linkml/generators/yarrrmlgen.py +157 -0
- linkml/linter/config/datamodel/config.py +160 -293
- linkml/linter/config/datamodel/config.yaml +34 -26
- linkml/linter/config/default.yaml +4 -0
- linkml/linter/config/recommended.yaml +4 -0
- linkml/linter/linter.py +1 -2
- linkml/linter/rules.py +37 -0
- linkml/utils/schemaloader.py +55 -3
- {linkml-1.9.4rc1.dist-info → linkml-1.9.5rc1.dist-info}/METADATA +2 -2
- {linkml-1.9.4rc1.dist-info → linkml-1.9.5rc1.dist-info}/RECORD +76 -38
- {linkml-1.9.4rc1.dist-info → linkml-1.9.5rc1.dist-info}/entry_points.txt +1 -0
- linkml/generators/panderagen/panderagen_class_based/mixins.jinja2 +0 -26
- {linkml-1.9.4rc1.dist-info → linkml-1.9.5rc1.dist-info}/WHEEL +0 -0
- {linkml-1.9.4rc1.dist-info → linkml-1.9.5rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Any, TextIO
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
import yaml
|
|
8
|
+
from linkml_runtime.linkml_model.meta import ClassDefinition, SchemaDefinition
|
|
9
|
+
from linkml_runtime.utils.schemaview import SchemaView
|
|
10
|
+
|
|
11
|
+
from linkml._version import __version__
|
|
12
|
+
from linkml.utils.generator import Generator, shared_arguments
|
|
13
|
+
|
|
14
|
+
# defaults
|
|
15
|
+
DEFAULT_SOURCE_JSON = "data.json~jsonpath"
|
|
16
|
+
DEFAULT_SOURCE_CSV = "data.csv~csv"
|
|
17
|
+
DEFAULT_ITERATOR = "$.items[*]" # generic top-level array
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _YamlDumper(yaml.Dumper):
|
|
21
|
+
# keep list indentation stable
|
|
22
|
+
def increase_indent(self, flow: bool = False, indentless: bool = False):
|
|
23
|
+
return super().increase_indent(flow, False)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class YarrrmlGenerator(Generator):
|
|
27
|
+
"""LinkML -> YARRRML exporter."""
|
|
28
|
+
|
|
29
|
+
generatorname = os.path.basename(__file__)
|
|
30
|
+
generatorversion = "0.2.0"
|
|
31
|
+
valid_formats = ["yml", "yaml"]
|
|
32
|
+
visit_all_class_slots = False
|
|
33
|
+
|
|
34
|
+
def __init__(self, schema: str | TextIO | SchemaDefinition, format: str = "yml", **kwargs):
|
|
35
|
+
src = kwargs.pop("source", None)
|
|
36
|
+
it = kwargs.pop("iterator_template", None)
|
|
37
|
+
|
|
38
|
+
super().__init__(schema, **kwargs)
|
|
39
|
+
|
|
40
|
+
self.schemaview = SchemaView(schema)
|
|
41
|
+
self.schema: SchemaDefinition = self.schemaview.schema
|
|
42
|
+
|
|
43
|
+
self.format = format
|
|
44
|
+
|
|
45
|
+
self.source: str = src or DEFAULT_SOURCE_JSON
|
|
46
|
+
self.iterator_template: str = it or DEFAULT_ITERATOR
|
|
47
|
+
|
|
48
|
+
# public
|
|
49
|
+
def serialize(self, **args) -> str:
|
|
50
|
+
data = yaml.dump(
|
|
51
|
+
self.as_dict(),
|
|
52
|
+
Dumper=_YamlDumper,
|
|
53
|
+
sort_keys=False,
|
|
54
|
+
default_flow_style=False,
|
|
55
|
+
allow_unicode=True,
|
|
56
|
+
)
|
|
57
|
+
return data
|
|
58
|
+
|
|
59
|
+
def as_dict(self) -> dict[str, Any]:
|
|
60
|
+
sv = self.schemaview
|
|
61
|
+
mappings = {}
|
|
62
|
+
for cls in sv.all_classes().values():
|
|
63
|
+
if not (sv.get_identifier_slot(cls.name) or sv.get_key_slot(cls.name)):
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
mapping = {
|
|
67
|
+
"s": self._subject_template_for_class(cls),
|
|
68
|
+
"po": self._po_list_for_class(cls),
|
|
69
|
+
}
|
|
70
|
+
if self._is_json_source():
|
|
71
|
+
mapping["sources"] = [[self.source, self._iterator_for_class(cls)]]
|
|
72
|
+
else:
|
|
73
|
+
mapping["sources"] = [self.source]
|
|
74
|
+
|
|
75
|
+
mappings[str(cls.name)] = mapping
|
|
76
|
+
|
|
77
|
+
return {"prefixes": self._prefixes(), "mappings": mappings}
|
|
78
|
+
|
|
79
|
+
# helpers
|
|
80
|
+
def _is_json_source(self) -> bool:
|
|
81
|
+
return "~jsonpath" in (self.source or "")
|
|
82
|
+
|
|
83
|
+
def _prefixes(self) -> dict[str, str]:
|
|
84
|
+
px: dict[str, str] = {}
|
|
85
|
+
if self.schema.prefixes:
|
|
86
|
+
for p in self.schema.prefixes.values():
|
|
87
|
+
if p.prefix_prefix and p.prefix_reference:
|
|
88
|
+
px[str(p.prefix_prefix)] = str(p.prefix_reference)
|
|
89
|
+
px.setdefault("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
|
|
90
|
+
return px
|
|
91
|
+
|
|
92
|
+
def _iterator_for_class(self, c: ClassDefinition) -> str:
|
|
93
|
+
# supports {Class}
|
|
94
|
+
return self.iterator_template.replace("{Class}", c.name)
|
|
95
|
+
|
|
96
|
+
def _subject_template_for_class(self, c: ClassDefinition) -> str:
|
|
97
|
+
sv = self.schemaview
|
|
98
|
+
default_prefix = sv.schema.default_prefix or "ex"
|
|
99
|
+
id_slot = sv.get_identifier_slot(c.name)
|
|
100
|
+
if id_slot:
|
|
101
|
+
return f"{default_prefix}:$({id_slot.name})"
|
|
102
|
+
key_slot = sv.get_key_slot(c.name)
|
|
103
|
+
if key_slot:
|
|
104
|
+
return f"{default_prefix}:$({key_slot.name})"
|
|
105
|
+
return f"{default_prefix}:{c.name}/$(subject_id)" # safe fallback
|
|
106
|
+
|
|
107
|
+
def _po_list_for_class(self, c: ClassDefinition) -> list[dict[str, Any]]:
|
|
108
|
+
sv = self.schemaview
|
|
109
|
+
po = []
|
|
110
|
+
class_curie = sv.get_uri(c, expand=False)
|
|
111
|
+
if class_curie:
|
|
112
|
+
po.append({"p": "rdf:type", "o": str(class_curie)})
|
|
113
|
+
|
|
114
|
+
default_prefix = sv.schema.default_prefix or "ex"
|
|
115
|
+
|
|
116
|
+
for s in sv.class_induced_slots(c.name):
|
|
117
|
+
pred = sv.get_uri(s, expand=False) or f"{default_prefix}:{s.name}"
|
|
118
|
+
decl = sv.get_slot(s.name)
|
|
119
|
+
alias = decl.alias if decl and decl.alias else s.alias
|
|
120
|
+
var = alias or s.name
|
|
121
|
+
|
|
122
|
+
is_obj = sv.get_class(s.range) is not None if s.range else False
|
|
123
|
+
if is_obj:
|
|
124
|
+
inlined = None
|
|
125
|
+
if decl and decl.inlined is not None:
|
|
126
|
+
inlined = decl.inlined
|
|
127
|
+
if inlined is False:
|
|
128
|
+
po.append({"p": pred, "o": {"value": f"$({var})", "type": "iri"}})
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
po.append({"p": pred, "o": f"$({var})"})
|
|
132
|
+
return po
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@shared_arguments(YarrrmlGenerator)
|
|
136
|
+
@click.command(name="yarrrml")
|
|
137
|
+
@click.option(
|
|
138
|
+
"--source",
|
|
139
|
+
help="YARRRML source shorthand, e.g., data.json~jsonpath or data.csv~csv",
|
|
140
|
+
)
|
|
141
|
+
@click.option(
|
|
142
|
+
"--iterator-template",
|
|
143
|
+
help='JSONPath iterator template; supports {Class}, default: "$.items[*]"',
|
|
144
|
+
)
|
|
145
|
+
@click.version_option(__version__, "-V", "--version")
|
|
146
|
+
def cli(yamlfile, source, iterator_template, **args):
|
|
147
|
+
"""Generate YARRRML mappings from a LinkML schema."""
|
|
148
|
+
if source:
|
|
149
|
+
args["source"] = source
|
|
150
|
+
if iterator_template:
|
|
151
|
+
args["iterator_template"] = iterator_template
|
|
152
|
+
gen = YarrrmlGenerator(yamlfile, **args)
|
|
153
|
+
print(gen.serialize(**args))
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
cli()
|