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.
Files changed (50) hide show
  1. linkml/cli/main.py +4 -0
  2. linkml/generators/__init__.py +2 -0
  3. linkml/generators/common/ifabsent_processor.py +286 -0
  4. linkml/generators/docgen/index.md.jinja2 +6 -6
  5. linkml/generators/docgen.py +64 -14
  6. linkml/generators/golanggen.py +3 -1
  7. linkml/generators/jsonldcontextgen.py +0 -1
  8. linkml/generators/jsonschemagen.py +4 -2
  9. linkml/generators/owlgen.py +36 -17
  10. linkml/generators/projectgen.py +13 -11
  11. linkml/generators/pydanticgen/array.py +340 -56
  12. linkml/generators/pydanticgen/build.py +4 -2
  13. linkml/generators/pydanticgen/pydanticgen.py +46 -24
  14. linkml/generators/pydanticgen/template.py +108 -3
  15. linkml/generators/pydanticgen/templates/imports.py.jinja +11 -3
  16. linkml/generators/pydanticgen/templates/module.py.jinja +1 -3
  17. linkml/generators/pydanticgen/templates/validator.py.jinja +2 -2
  18. linkml/generators/python/__init__.py +1 -0
  19. linkml/generators/python/python_ifabsent_processor.py +92 -0
  20. linkml/generators/pythongen.py +19 -31
  21. linkml/generators/shacl/__init__.py +1 -3
  22. linkml/generators/shacl/shacl_data_type.py +1 -1
  23. linkml/generators/shacl/shacl_ifabsent_processor.py +89 -0
  24. linkml/generators/shaclgen.py +39 -13
  25. linkml/generators/sparqlgen.py +3 -1
  26. linkml/generators/sqlalchemygen.py +5 -3
  27. linkml/generators/sqltablegen.py +4 -2
  28. linkml/generators/typescriptgen.py +13 -6
  29. linkml/linter/linter.py +2 -1
  30. linkml/transformers/logical_model_transformer.py +3 -3
  31. linkml/transformers/relmodel_transformer.py +18 -4
  32. linkml/utils/converter.py +3 -1
  33. linkml/utils/exceptions.py +11 -0
  34. linkml/utils/execute_tutorial.py +22 -20
  35. linkml/utils/generator.py +6 -4
  36. linkml/utils/mergeutils.py +4 -2
  37. linkml/utils/schema_fixer.py +5 -5
  38. linkml/utils/schemaloader.py +5 -3
  39. linkml/utils/sqlutils.py +3 -1
  40. linkml/validator/plugins/pydantic_validation_plugin.py +1 -1
  41. linkml/validators/jsonschemavalidator.py +3 -1
  42. linkml/validators/sparqlvalidator.py +5 -3
  43. linkml/workspaces/example_runner.py +3 -1
  44. {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/METADATA +3 -1
  45. {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/RECORD +48 -45
  46. linkml/generators/shacl/ifabsent_processor.py +0 -59
  47. linkml/utils/ifabsent_functions.py +0 -138
  48. {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/LICENSE +0 -0
  49. {linkml-1.8.2.dist-info → linkml-1.8.4.dist-info}/WHEEL +0 -0
  50. {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