linkml 1.8.2__py3-none-any.whl → 1.8.4__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/ifabsent_processor.py +286 -0
- linkml/generators/docgen/index.md.jinja2 +6 -6
- linkml/generators/docgen.py +64 -14
- linkml/generators/golanggen.py +3 -1
- linkml/generators/jsonldcontextgen.py +0 -1
- linkml/generators/jsonschemagen.py +4 -2
- linkml/generators/owlgen.py +36 -17
- linkml/generators/projectgen.py +13 -11
- linkml/generators/pydanticgen/array.py +340 -56
- linkml/generators/pydanticgen/build.py +4 -2
- linkml/generators/pydanticgen/pydanticgen.py +46 -24
- linkml/generators/pydanticgen/template.py +108 -3
- linkml/generators/pydanticgen/templates/imports.py.jinja +11 -3
- linkml/generators/pydanticgen/templates/module.py.jinja +1 -3
- linkml/generators/pydanticgen/templates/validator.py.jinja +2 -2
- linkml/generators/python/__init__.py +1 -0
- linkml/generators/python/python_ifabsent_processor.py +92 -0
- linkml/generators/pythongen.py +19 -31
- 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 +39 -13
- linkml/generators/sparqlgen.py +3 -1
- linkml/generators/sqlalchemygen.py +5 -3
- linkml/generators/sqltablegen.py +4 -2
- linkml/generators/typescriptgen.py +13 -6
- linkml/linter/linter.py +2 -1
- linkml/transformers/logical_model_transformer.py +3 -3
- linkml/transformers/relmodel_transformer.py +18 -4
- linkml/utils/converter.py +3 -1
- linkml/utils/exceptions.py +11 -0
- linkml/utils/execute_tutorial.py +22 -20
- linkml/utils/generator.py +6 -4
- linkml/utils/mergeutils.py +4 -2
- linkml/utils/schema_fixer.py +5 -5
- linkml/utils/schemaloader.py +5 -3
- linkml/utils/sqlutils.py +3 -1
- linkml/validator/plugins/pydantic_validation_plugin.py +1 -1
- linkml/validators/jsonschemavalidator.py +3 -1
- linkml/validators/sparqlvalidator.py +5 -3
- linkml/workspaces/example_runner.py +3 -1
- {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/METADATA +3 -1
- {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/RECORD +48 -45
- linkml/generators/shacl/ifabsent_processor.py +0 -59
- linkml/utils/ifabsent_functions.py +0 -138
- {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/LICENSE +0 -0
- {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/WHEEL +0 -0
- {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/entry_points.txt +0 -0
@@ -1,59 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
from typing import Any, Callable, Optional
|
3
|
-
|
4
|
-
from linkml_runtime import SchemaView
|
5
|
-
from linkml_runtime.linkml_model import SlotDefinition
|
6
|
-
from rdflib import SH, Literal, URIRef
|
7
|
-
from rdflib.term import Identifier
|
8
|
-
|
9
|
-
from linkml.generators.shacl.shacl_data_type import ShaclDataType
|
10
|
-
|
11
|
-
|
12
|
-
class IfAbsentProcessor:
|
13
|
-
"""
|
14
|
-
Processes value of ifabsent slot.
|
15
|
-
|
16
|
-
See `<https://w3id.org/linkml/ifabsent>`_.
|
17
|
-
|
18
|
-
TODO: unify this with ifabsent_functions
|
19
|
-
"""
|
20
|
-
|
21
|
-
ifabsent_regex = re.compile("""(?:(?P<type>\w+)\()?[\"\']?(?P<default_value>[^\(\)\"\')]*)[\"\']?\)?""")
|
22
|
-
|
23
|
-
def __init__(self, schema_view: SchemaView):
|
24
|
-
self.schema_view = schema_view
|
25
|
-
|
26
|
-
def process_slot(
|
27
|
-
self, add_prop: Callable[[URIRef, Identifier], None], slot: SlotDefinition, class_uri: Optional[URIRef] = None
|
28
|
-
) -> None:
|
29
|
-
if slot.ifabsent:
|
30
|
-
ifabsent_match = self.ifabsent_regex.search(slot.ifabsent)
|
31
|
-
ifabsent_default_value = ifabsent_match.group("default_value")
|
32
|
-
|
33
|
-
self._map_to_default_value(slot, add_prop, ifabsent_default_value, class_uri)
|
34
|
-
|
35
|
-
def _map_to_default_value(
|
36
|
-
self,
|
37
|
-
slot: SlotDefinition,
|
38
|
-
add_prop: Callable[[URIRef, Identifier], None],
|
39
|
-
ifabsent_default_value: Any,
|
40
|
-
class_uri: Optional[URIRef] = None,
|
41
|
-
) -> None:
|
42
|
-
for datatype in list(ShaclDataType):
|
43
|
-
if datatype.linkml_type == slot.range:
|
44
|
-
add_prop(SH.defaultValue, Literal(ifabsent_default_value, datatype=datatype.uri_ref))
|
45
|
-
return
|
46
|
-
|
47
|
-
for enum_name, enum in self.schema_view.all_enums().items():
|
48
|
-
if enum_name == slot.range:
|
49
|
-
for permissible_value_name, permissible_value in enum.permissible_values.items():
|
50
|
-
if permissible_value_name == ifabsent_default_value:
|
51
|
-
add_prop(SH.defaultValue, Literal(ifabsent_default_value))
|
52
|
-
return
|
53
|
-
|
54
|
-
if ifabsent_default_value == "class_curie":
|
55
|
-
if class_uri:
|
56
|
-
add_prop(SH.defaultValue, class_uri)
|
57
|
-
return
|
58
|
-
|
59
|
-
raise ValueError(f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot could not be processed")
|
@@ -1,138 +0,0 @@
|
|
1
|
-
import re
|
2
|
-
from typing import Callable, List, Match, Optional, Text, Tuple, Union
|
3
|
-
|
4
|
-
from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
|
5
|
-
from linkml_runtime.utils.formatutils import sfx
|
6
|
-
|
7
|
-
from linkml.utils.schemaloader import SchemaLoader
|
8
|
-
|
9
|
-
|
10
|
-
def strval(txt: str) -> str:
|
11
|
-
txt = str(txt).replace('"', '\\"')
|
12
|
-
return f'"{txt}"'
|
13
|
-
|
14
|
-
|
15
|
-
def default_uri_for(loader: SchemaLoader) -> str:
|
16
|
-
dflt = loader.schema.default_prefix if loader.schema.default_prefix else sfx(loader.schema.id)
|
17
|
-
return sfx(loader.namespaces.uri_for(dflt))
|
18
|
-
|
19
|
-
|
20
|
-
def default_curie_or_uri(loader: SchemaLoader) -> str:
|
21
|
-
dflt = loader.schema.default_prefix if loader.schema.default_prefix else sfx(loader.schema.id)
|
22
|
-
if ":/" in dflt:
|
23
|
-
prefix = loader.namespaces.prefix_for(loader.schema.default_prefix)
|
24
|
-
if prefix:
|
25
|
-
dflt = prefix
|
26
|
-
return dflt
|
27
|
-
|
28
|
-
|
29
|
-
def curie_for(loader: SchemaLoader, is_class: bool) -> Optional[str]:
|
30
|
-
"""Return the Curie for the schema in loader. Return None if there is no curie form"""
|
31
|
-
prefix = default_curie_or_uri(loader)
|
32
|
-
suffix = "camelcase(self.name)" if is_class else "underscore(self.alias if self.alias else self.name)"
|
33
|
-
if ":/" not in prefix:
|
34
|
-
return '"' + prefix + ":" + '" + ' + suffix
|
35
|
-
else:
|
36
|
-
pn = loader.namespaces.curie_for(prefix, default_ok=False)
|
37
|
-
return ('"' + pn + '" + ' + suffix) if pn else None
|
38
|
-
|
39
|
-
|
40
|
-
def uri_for(s: str, loader: SchemaLoader) -> str:
|
41
|
-
uri = str(loader.namespaces.uri_for(s))
|
42
|
-
return loader.namespaces.curie_for(uri, True, True) or strval(uri)
|
43
|
-
|
44
|
-
|
45
|
-
def default_ns_for(loader: SchemaLoader, cls: ClassDefinition) -> str:
|
46
|
-
"""Return code to produce the default namespace for the supplied class"""
|
47
|
-
# TODO: figure out how to mark a slot as a namespace
|
48
|
-
return "sfx(str(self.id))" if "id" in cls.slots else "None"
|
49
|
-
# cls_id = None
|
50
|
-
# for slotname in cls.slots:
|
51
|
-
# slot = loader.schema.slots[slotname]
|
52
|
-
# if slot.identifier:
|
53
|
-
# cls_id = slotname
|
54
|
-
# return f"sfx(str(self.{cls_id}))" if cls_id else "None"
|
55
|
-
|
56
|
-
|
57
|
-
# Library of named default values -- this is here to prevent code injection
|
58
|
-
# Contents: Match text (as re),
|
59
|
-
# flag that indicates whether we're generating a default value expression or postinig code
|
60
|
-
# Function that takes the match string, SchemaLoader, ClassDefinition, and SlotDefinition and returns the
|
61
|
-
# appropriate string
|
62
|
-
default_library: List[
|
63
|
-
Tuple[
|
64
|
-
Text,
|
65
|
-
bool,
|
66
|
-
Callable[[Match[str], SchemaLoader, ClassDefinition, SlotDefinition], str],
|
67
|
-
]
|
68
|
-
] = [
|
69
|
-
(r"[Tt]rue", False, lambda _, __, ___, ____: "True"),
|
70
|
-
(r"[Ff]alse", False, lambda _, __, ___, ____: "False"),
|
71
|
-
(r"int\(([-+]?[0-9]+)\)", False, lambda m, __, ___, ____: int(m[1])),
|
72
|
-
(
|
73
|
-
r"float\(([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)\)",
|
74
|
-
False,
|
75
|
-
lambda m, __, ___, ____: float(m[1]),
|
76
|
-
),
|
77
|
-
(
|
78
|
-
r"date\((\d{4})-(\d{2})-(\d{2})\)",
|
79
|
-
False,
|
80
|
-
lambda m, __, ___, ____: f"date({int(m[1])}, {int(m[2])}, {int(m[3])})",
|
81
|
-
),
|
82
|
-
(
|
83
|
-
r"datetime\((\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z\)",
|
84
|
-
False,
|
85
|
-
lambda m, __, ___, ____: f"datetime({int(m[1])}, {int(m[2])}, {int(m[3])}, "
|
86
|
-
f"{int(m[4])}, {int(m[5])}, {int(m[6])})",
|
87
|
-
),
|
88
|
-
# TODO: We have to make the real URI available before any of these can work
|
89
|
-
# ("class_uri", True,
|
90
|
-
# lambda _, loader, ___, ____: f'"{default_uri_for(loader)}" + camelcase(self.name)'),
|
91
|
-
# ("slot_uri", True,
|
92
|
-
# lambda _, loader, ___, ____: f'"{default_uri_for(loader)}" +
|
93
|
-
# underscore(self.alias if self.alias else self.name)'),
|
94
|
-
# ("class_curie", True, lambda _, loader, ___, ____: curie_for(loader, True)),
|
95
|
-
# ("slot_curie", True, lambda _, loader, ___, ____: curie_for(loader, False)),
|
96
|
-
("class_uri", True, lambda _, loader, ___, ____: "None"),
|
97
|
-
("slot_uri", True, lambda _, loader, ___, ____: "None"),
|
98
|
-
("class_curie", True, lambda _, loader, ___, ____: "None"),
|
99
|
-
("slot_curie", True, lambda _, loader, ___, ____: "None"),
|
100
|
-
# See: https://github.com/linkml/linkml/issues/1333
|
101
|
-
# ("class_uri", False, lambda _, __, class_definition, ____: 'class_class_uri'),
|
102
|
-
# ("class_curie", False, lambda _, __, class_definition, ____: 'class_class_curie'),
|
103
|
-
# ("slot_uri", True, lambda _, loader, ___, slot_definition: f'slots.{slot_definition.name}.uri'),
|
104
|
-
# ("slot_curie", True, lambda _, loader, ___, slot_definition: f'slots.{slot_definition.name}.curie'),
|
105
|
-
# ("default_range", False, lambda _, loader, __, ____: f"{strval(loader.schema.default_range)}"),
|
106
|
-
("default_range", False, lambda _, __, ___, ____: "None"),
|
107
|
-
("bnode", False, lambda _, __, ___, ____: "bnode()"),
|
108
|
-
(r"string\((.*)\)", False, lambda m, __, ___, ____: strval(m[1])),
|
109
|
-
(r"uri\((.*)\)", False, lambda m, loader, _, __: uri_for(m[1], loader)),
|
110
|
-
("default_ns", True, lambda _, loader, cls, ____: default_ns_for(loader, cls)),
|
111
|
-
# ("default_ns", False, lambda _, loader, __, ____: f"{strval(loader.schema.default_prefix)}"),
|
112
|
-
]
|
113
|
-
|
114
|
-
|
115
|
-
def isabsent_match(
|
116
|
-
txt: Text,
|
117
|
-
) -> Union[
|
118
|
-
Tuple[Match[str], bool, Callable[[Match[str], SchemaLoader, ClassDefinition, SlotDefinition], str]],
|
119
|
-
Tuple[None, None, None],
|
120
|
-
]:
|
121
|
-
txt = str(txt)
|
122
|
-
for pattern, postinit, f in default_library:
|
123
|
-
m = re.match(pattern + "$", txt)
|
124
|
-
if m:
|
125
|
-
return m, postinit, f
|
126
|
-
raise ValueError(f"Incompatible default value: {txt}")
|
127
|
-
|
128
|
-
|
129
|
-
def ifabsent_value_declaration(txt: Text, loader, cls, slot) -> Optional[str]:
|
130
|
-
m, postinit, f = isabsent_match(txt)
|
131
|
-
if m and not postinit:
|
132
|
-
return f(m, loader, cls, slot)
|
133
|
-
|
134
|
-
|
135
|
-
def ifabsent_postinit_declaration(txt: Text, loader, cls, slot) -> Optional[str]:
|
136
|
-
m, postinit, f = isabsent_match(txt)
|
137
|
-
if m and postinit:
|
138
|
-
return f(m, loader, cls, slot)
|
File without changes
|
File without changes
|
File without changes
|