linkml 1.8.5__py3-none-any.whl → 1.8.6__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.
@@ -1,7 +1,15 @@
1
1
  import sys
2
2
  from abc import ABC, abstractmethod
3
3
  from enum import Enum
4
- from typing import TYPE_CHECKING, Any, ClassVar, Generic, Iterable, List, Optional, Type, TypeVar, Union, get_args
4
+ from typing import (
5
+ ClassVar,
6
+ Iterable,
7
+ List,
8
+ Optional,
9
+ Type,
10
+ TypeVar,
11
+ Union,
12
+ )
5
13
 
6
14
  from linkml_runtime.linkml_model import Element
7
15
  from linkml_runtime.linkml_model.meta import ArrayExpression, DimensionExpression
@@ -9,20 +17,15 @@ from pydantic import VERSION as PYDANTIC_VERSION
9
17
 
10
18
  from linkml.utils.deprecation import deprecation_warning
11
19
 
12
- if int(PYDANTIC_VERSION[0]) >= 2:
13
- from pydantic_core import core_schema
14
- else:
20
+ if int(PYDANTIC_VERSION[0]) < 2:
15
21
  # Support for having pydantic 1 installed in the same environment will be dropped in 1.9.0
16
22
  deprecation_warning("pydantic-v1")
17
23
 
18
- if TYPE_CHECKING:
19
- from pydantic import GetCoreSchemaHandler
20
- from pydantic_core import CoreSchema
21
-
22
- if sys.version_info.minor <= 8:
23
- from typing_extensions import Annotated
24
+ if sys.version_info.minor < 12:
25
+ from typing_extensions import TypeAliasType
24
26
  else:
25
- from typing import Annotated
27
+ from typing import TypeAliasType
28
+
26
29
 
27
30
  from linkml.generators.pydanticgen.build import RangeResult
28
31
  from linkml.generators.pydanticgen.template import ConditionalImport, Import, Imports, ObjectImport
@@ -37,75 +40,32 @@ class ArrayRepresentation(Enum):
37
40
  _BOUNDED_ARRAY_FIELDS = ("exact_number_dimensions", "minimum_number_dimensions", "maximum_number_dimensions")
38
41
 
39
42
  _T = TypeVar("_T")
40
- _RecursiveListType = Iterable[Union[_T, Iterable["_RecursiveListType"]]]
41
-
42
-
43
- class AnyShapeArrayType(Generic[_T]):
44
- @classmethod
45
- def __get_pydantic_core_schema__(cls, source_type: Any, handler: "GetCoreSchemaHandler") -> "CoreSchema":
46
- # double-nested parameterized types here
47
- # source_type: List[Union[T,List[...]]]
48
- item_type = (Any,) if get_args(get_args(source_type)[0])[0] is _T else get_args(get_args(source_type)[0])[:-1]
49
-
50
- if len(item_type) == 1:
51
- item_schema = handler.generate_schema(item_type[0])
52
- else:
53
- item_schema = core_schema.union_schema([handler.generate_schema(i) for i in item_type])
54
-
55
- if all([getattr(i, "__module__", "") == "builtins" and i is not Any for i in item_type]):
56
- item_schema["strict"] = True
57
-
58
- # Before python 3.11, `Any` type was a special object without a __name__
59
- item_name = "_".join(["Any" if i is Any else i.__name__ for i in item_type])
60
-
61
- array_ref = f"any-shape-array-{item_name}"
62
-
63
- schema = core_schema.definitions_schema(
64
- core_schema.list_schema(core_schema.definition_reference_schema(array_ref)),
65
- [
66
- core_schema.union_schema(
67
- [
68
- core_schema.list_schema(core_schema.definition_reference_schema(array_ref)),
69
- item_schema,
70
- ],
71
- ref=array_ref,
72
- )
73
- ],
74
- )
75
-
76
- return schema
77
-
78
-
79
- AnyShapeArray = Annotated[_RecursiveListType, AnyShapeArrayType]
43
+ AnyShapeArray = TypeAliasType("AnyShapeArray", Iterable[Union[_T, Iterable["AnyShapeArray[_T]"]]], type_params=(_T,))
80
44
 
81
45
  _AnyShapeArrayImports = (
82
46
  Imports()
83
47
  + Import(
84
48
  module="typing",
85
49
  objects=[
86
- ObjectImport(name="Generic"),
87
50
  ObjectImport(name="Iterable"),
88
51
  ObjectImport(name="TypeVar"),
89
52
  ObjectImport(name="Union"),
90
- ObjectImport(name="get_args"),
91
53
  ],
92
54
  )
93
55
  + ConditionalImport(
94
- condition="sys.version_info.minor > 8",
56
+ condition="sys.version_info.minor >= 12",
95
57
  module="typing",
96
- objects=[ObjectImport(name="Annotated")],
97
- alternative=Import(module="typing_extensions", objects=[ObjectImport(name="Annotated")]),
58
+ objects=[ObjectImport(name="TypeAliasType")],
59
+ alternative=Import(module="typing_extensions", objects=[ObjectImport(name="TypeAliasType")]),
98
60
  )
99
- + Import(module="pydantic", objects=[ObjectImport(name="GetCoreSchemaHandler")])
100
- + Import(module="pydantic_core", objects=[ObjectImport(name="CoreSchema"), ObjectImport(name="core_schema")])
101
61
  )
102
62
 
103
63
  # annotated types are special and inspect.getsource() can't stringify them
104
64
  _AnyShapeArrayInjects = [
105
65
  '_T = TypeVar("_T")',
106
- '_RecursiveListType = Iterable[Union[_T, Iterable["_RecursiveListType"]]]',
107
- AnyShapeArrayType,
108
- "AnyShapeArray = Annotated[_RecursiveListType, AnyShapeArrayType]",
66
+ """AnyShapeArray = TypeAliasType(
67
+ "AnyShapeArray", Iterable[Union[_T, Iterable["AnyShapeArray[_T]"]]], type_params=(_T,)
68
+ )""",
109
69
  ]
110
70
 
111
71
  _ConListImports = Imports() + Import(module="pydantic", objects=[ObjectImport(name="conlist")])
@@ -1,4 +1,4 @@
1
- {{name}}: {{ range }} = Field({{ field }}
1
+ {{name}}: {{ range }} = Field(default={{ field }}
2
2
  {%- if title != None %}, title="{{title}}"{% endif -%}
3
3
  {%- if description %}, description="""{{description}}"""{% endif -%}
4
4
  {%- if equals_number != None %}
@@ -116,10 +116,20 @@ class ShaclGenerator(Generator):
116
116
  order += 1
117
117
  prop_pv_literal(SH.name, s.title)
118
118
  prop_pv_literal(SH.description, s.description)
119
- if not s.multivalued:
120
- prop_pv_literal(SH.maxCount, 1)
121
- if s.required:
119
+ # minCount
120
+ if s.minimum_cardinality:
121
+ prop_pv_literal(SH.minCount, s.minimum_cardinality)
122
+ elif s.exact_cardinality:
123
+ prop_pv_literal(SH.minCount, s.exact_cardinality)
124
+ elif s.required:
122
125
  prop_pv_literal(SH.minCount, 1)
126
+ # maxCount
127
+ if s.maximum_cardinality:
128
+ prop_pv_literal(SH.maxCount, s.maximum_cardinality)
129
+ elif s.exact_cardinality:
130
+ prop_pv_literal(SH.maxCount, s.exact_cardinality)
131
+ elif not s.multivalued:
132
+ prop_pv_literal(SH.maxCount, 1)
123
133
  prop_pv_literal(SH.minInclusive, s.minimum_value)
124
134
  prop_pv_literal(SH.maxInclusive, s.maximum_value)
125
135
 
@@ -198,8 +208,6 @@ class ShaclGenerator(Generator):
198
208
  add_simple_data_type(prop_pv, r)
199
209
  if s.pattern:
200
210
  prop_pv(SH.pattern, Literal(s.pattern))
201
- if s.annotations and self.include_annotations:
202
- self._add_annotations(prop_pv, s)
203
211
  if s.equals_string:
204
212
  # Map equal_string and equal_string_in to sh:in
205
213
  self._and_equals_string(g, prop_pv, [s.equals_string])
@@ -207,6 +215,9 @@ class ShaclGenerator(Generator):
207
215
  # Map equal_string and equal_string_in to sh:in
208
216
  self._and_equals_string(g, prop_pv, s.equals_string_in)
209
217
 
218
+ if s.annotations and self.include_annotations:
219
+ self._add_annotations(prop_pv, s)
220
+
210
221
  default_value = ifabsent_processor.process_slot(s, c)
211
222
  if default_value:
212
223
  prop_pv(SH.defaultValue, default_value)
@@ -280,7 +280,9 @@ def cli(yamlfile, gen_type_utils=False, include_induced_slots=False, output=None
280
280
  gen = TypescriptGenerator(
281
281
  yamlfile, gen_type_utils=gen_type_utils, include_induced_slots=include_induced_slots, **args
282
282
  )
283
- gen.serialize(output=output)
283
+ serialized = gen.serialize(output=output)
284
+ if output is None:
285
+ print(serialized)
284
286
 
285
287
 
286
288
  if __name__ == "__main__":
linkml/linter/rules.py CHANGED
@@ -134,7 +134,9 @@ class TreeRootClassRule(LinterRule):
134
134
  if self.config.validate_existing_class_name:
135
135
  for tree_root in tree_roots:
136
136
  if str(tree_root.name) != self.config.root_class_name:
137
- yield LinterProblem(message=f"Tree root class has name '{tree_root.name}'")
137
+ yield LinterProblem(message=f"Tree root class has an invalid name '{tree_root.name}'")
138
+ if len(tree_roots) > 1:
139
+ yield LinterProblem("Schema has more than one class with `tree_root: true`")
138
140
  else:
139
141
  if fix:
140
142
  container = ClassDefinition(self.config.root_class_name, tree_root=True)
linkml/utils/converter.py CHANGED
@@ -1,8 +1,10 @@
1
1
  import logging
2
2
  import os
3
+ import pathlib
3
4
  import sys
4
5
 
5
6
  import click
7
+ import yaml
6
8
  from linkml_runtime.linkml_model import Prefix
7
9
  from linkml_runtime.utils import inference_utils
8
10
  from linkml_runtime.utils.compile_python import compile_python
@@ -55,6 +57,7 @@ logger = logging.getLogger(__name__)
55
57
  @click.option("--index-slot", "-S", help="top level slot. Required for CSV dumping/loading")
56
58
  @click.option("--schema", "-s", help="Path to schema specified as LinkML yaml")
57
59
  @click.option("--prefix", "-P", multiple=True, help="Prefixmap base=URI pairs")
60
+ @click.option("--prefix-file", help="Path to yaml file containing base=URI pairs")
58
61
  @click.option(
59
62
  "--validate/--no-validate",
60
63
  default=True,
@@ -79,6 +82,7 @@ def cli(
79
82
  input_format=None,
80
83
  output_format=None,
81
84
  prefix=None,
85
+ prefix_file=None,
82
86
  target_class_from_path=None,
83
87
  schema=None,
84
88
  validate=None,
@@ -99,6 +103,8 @@ def cli(
99
103
 
100
104
  For more information, see https://linkml.io/linkml/data/index.html
101
105
  """
106
+ if prefix and prefix_file is not None:
107
+ raise Exception("Either set prefix OR prefix_file, not both.")
102
108
  if prefix is None:
103
109
  prefix = []
104
110
  if module is None:
@@ -113,6 +119,17 @@ def cli(
113
119
  for p in prefix:
114
120
  base, uri = p.split("=")
115
121
  prefix_map[base] = uri
122
+ if prefix_file is not None:
123
+ prefix_path = pathlib.Path(prefix_file).resolve()
124
+ if not prefix_path.exists():
125
+ raise Exception(f"Path {prefix_file} to prefix map does not exists.")
126
+ with open(prefix_path, "r") as prefix_stream:
127
+ raw_prefix_map = yaml.safe_load(prefix_stream)
128
+ prefix_file_map = raw_prefix_map.get("prefixes", None)
129
+ if prefix_file_map is None:
130
+ raise Exception("Provided prefix file does not contain the prefixes key.")
131
+ prefix_map = prefix_file_map
132
+
116
133
  if schema is not None:
117
134
  sv = SchemaView(schema)
118
135
  if prefix_map:
@@ -222,6 +222,16 @@ DEPRECATIONS = (
222
222
  recommendation="Update dependent packages to use pydantic>=2",
223
223
  issue=1925,
224
224
  ),
225
+ Deprecation(
226
+ name="validators",
227
+ deprecated_in=SemVer.from_str("1.8.6"),
228
+ removed_in=SemVer.from_str("1.9.0"),
229
+ message=(
230
+ "linkml.validators and linkml.utils.validation are the older versions "
231
+ "of linkml.validator and have unmaintained, duplicated functionality"
232
+ ),
233
+ recommendation="Update to use linkml.validator",
234
+ ),
225
235
  ) # type: tuple[Deprecation, ...]
226
236
 
227
237
  EMITTED = set() # type: set[str]
linkml/utils/helpers.py CHANGED
@@ -1,4 +1,13 @@
1
1
  import re
2
+ from functools import lru_cache
3
+ from typing import List, Tuple, Union
4
+
5
+ from linkml_runtime import SchemaView
6
+ from linkml_runtime.linkml_model.meta import (
7
+ ClassDefinition,
8
+ ElementName,
9
+ SlotDefinition,
10
+ )
2
11
 
3
12
 
4
13
  def remove_duplicates(lst):
@@ -14,3 +23,59 @@ def write_to_file(file_path, data, mode="w", encoding="utf-8"):
14
23
  def convert_to_snake_case(str):
15
24
  str = re.sub(r"(?<=[a-z])(?=[A-Z])|[^a-zA-Z]", " ", str).strip().replace(" ", "_")
16
25
  return "".join(str.lower())
26
+
27
+
28
+ @lru_cache(None)
29
+ def get_range_associated_slots(
30
+ schemaview: SchemaView, range_class: ClassDefinition
31
+ ) -> Tuple[Union[SlotDefinition, None], Union[SlotDefinition, None], Union[List[SlotDefinition], None]]:
32
+ if isinstance(range_class, ElementName):
33
+ range_class = schemaview.get_class(range_class)
34
+ if range_class is None:
35
+ return None, None, None
36
+
37
+ range_class_id_slot = schemaview.get_identifier_slot(range_class.name, use_key=True)
38
+ if range_class_id_slot is None:
39
+ return None, None, None
40
+
41
+ non_id_slots = [s for s in schemaview.class_induced_slots(range_class.name) if s.name != range_class_id_slot.name]
42
+ non_id_required_slots = [s for s in non_id_slots if s.required]
43
+
44
+ # Some lists of objects can be serialized as SimpleDicts.
45
+ # A SimpleDict is serialized as simple key-value pairs where the value is atomic.
46
+ # The key must be declared as a key, and the value must satisfy one of the following conditions:
47
+ # 1. The value slot is the only other slot in the object other than the key
48
+ # 2. The value slot is explicitly annotated as a simple_dict_value
49
+ # 3. The value slot is the only non-key that is required
50
+ # See also: https://github.com/linkml/linkml/issues/1250
51
+ range_simple_dict_value_slot = None
52
+ if len(non_id_slots) == 1:
53
+ range_simple_dict_value_slot = non_id_slots[0]
54
+ elif len(non_id_slots) > 1:
55
+ candidate_non_id_slots = []
56
+ for non_id_slot in non_id_slots:
57
+ if isinstance(non_id_slot.annotations, dict):
58
+ is_simple_dict_value = non_id_slot.annotations.get("simple_dict_value", False)
59
+ else:
60
+ is_simple_dict_value = getattr(non_id_slot.annotations, "simple_dict_value", False)
61
+ if is_simple_dict_value:
62
+ candidate_non_id_slots.append(non_id_slot)
63
+ if len(candidate_non_id_slots) == 1:
64
+ range_simple_dict_value_slot = candidate_non_id_slots[0]
65
+ else:
66
+ candidate_non_id_slots = []
67
+ for non_id_slot in non_id_slots:
68
+ if non_id_slot.required:
69
+ candidate_non_id_slots.append(non_id_slot)
70
+ if len(candidate_non_id_slots) == 1:
71
+ range_simple_dict_value_slot = candidate_non_id_slots[0]
72
+
73
+ return range_class_id_slot, range_simple_dict_value_slot, non_id_required_slots
74
+
75
+
76
+ def is_simple_dict(schemaview: SchemaView, slot: SlotDefinition) -> bool:
77
+ if not slot.multivalued or not slot.inlined or slot.inlined_as_list:
78
+ return False
79
+ else:
80
+ _, range_simple_dict_value_slot, _ = get_range_associated_slots(schemaview, slot.range)
81
+ return range_simple_dict_value_slot is not None
@@ -7,6 +7,7 @@ from linkml_runtime.linkml_model import SchemaDefinition
7
7
  from linkml_runtime.utils.yamlutils import YAMLRoot
8
8
 
9
9
  from linkml.generators.jsonschemagen import JsonSchemaGenerator
10
+ from linkml.utils.deprecation import deprecation_warning
10
11
 
11
12
 
12
13
  def _as_dict(inst):
@@ -16,7 +17,6 @@ def _as_dict(inst):
16
17
  return inst_dict
17
18
 
18
19
 
19
- # Deprecated: use validators module
20
20
  def validate_object(
21
21
  data: YAMLRoot,
22
22
  schema: Union[str, TextIO, SchemaDefinition],
@@ -32,6 +32,7 @@ def validate_object(
32
32
  :param closed:
33
33
  :return:
34
34
  """
35
+ deprecation_warning("validators")
35
36
  if target_class is None:
36
37
  target_class = type(data)
37
38
  inst_dict = _as_dict(data)
@@ -60,7 +60,7 @@ def validate(
60
60
  otherwise it should be a ``SchemaDefinition`` instance.
61
61
  :param target_class: Name of the class within the schema to validate
62
62
  against. If ``None``, the class will be inferred from the schema by
63
- looked for a class with ``tree_root: true``. Defaults to ``None``.
63
+ looking for a class with ``tree_root: true``. Defaults to ``None``.
64
64
  :param strict: If ``True``, validation will stop after the first validation
65
65
  error is found, Otherwise all validation problems will be reported.
66
66
  Defaults to ``False``.
@@ -99,7 +99,7 @@ def validate_file(
99
99
  otherwise it should be a ``SchemaDefinition`` instance.
100
100
  :param target_class: Name of the class within the schema to validate
101
101
  against. If ``None``, the class will be inferred from the schema by
102
- looked for a class with ``tree_root: true``. Defaults to ``None``.
102
+ looking for a class with ``tree_root: true``. Defaults to ``None``.
103
103
  :param strict: If ``True``, validation will stop after the first validation
104
104
  error is found, Otherwise all validation problems will be reported.
105
105
  Defaults to ``False``.
@@ -55,4 +55,5 @@ class JsonschemaValidationPlugin(ValidationPlugin):
55
55
  instantiates=context.target_class,
56
56
  message=f"{best_error.message} in /{'/'.join(str(p) for p in best_error.absolute_path)}",
57
57
  context=error_context,
58
+ source=best_error,
58
59
  )
@@ -1,7 +1,7 @@
1
1
  from enum import Enum
2
2
  from typing import Any, List, Optional
3
3
 
4
- from pydantic import BaseModel
4
+ from pydantic import BaseModel, Field
5
5
 
6
6
 
7
7
  class Severity(str, Enum):
@@ -30,6 +30,9 @@ class ValidationResult(BaseModel):
30
30
  instantiates: Optional[str] = None
31
31
  context: List[str] = []
32
32
 
33
+ # The source object that caused this validation result
34
+ source: Any = Field(None, description="The source of this validation result", exclude=True)
35
+
33
36
 
34
37
  class ValidationReport(BaseModel):
35
38
  """
@@ -48,7 +48,7 @@ class Validator:
48
48
  :param instance: The instance to validate
49
49
  :param target_class: Name of the class within the schema to validate
50
50
  against. If ``None``, the class will be inferred from the schema by
51
- looked for a class with ``tree_root: true``. Defaults to ``None``.
51
+ looking for a class with ``tree_root: true``. Defaults to ``None``.
52
52
  :return: A validation report
53
53
  :rtype: ValidationReport
54
54
  """
@@ -61,7 +61,7 @@ class Validator:
61
61
  which provides the instances to validate
62
62
  :param target_class: Name of the class within the schema to validate
63
63
  against. If ``None``, the class will be inferred from the schema by
64
- looked for a class with ``tree_root: true``. Defaults to ``None``.
64
+ looking for a class with ``tree_root: true``. Defaults to ``None``.
65
65
  :return: A validation report
66
66
  :rtype: ValidationReport
67
67
  """
@@ -73,7 +73,7 @@ class Validator:
73
73
  :param instance: The instance to validate
74
74
  :param target_class: Name of the class within the schema to validate
75
75
  against. If ``None``, the class will be inferred from the schema by
76
- looked for a class with ``tree_root: true``. Defaults to ``None``.
76
+ looking for a class with ``tree_root: true``. Defaults to ``None``.
77
77
  :return: Iterator over validation results
78
78
  :rtype: Iterator[ValidationResult]
79
79
  """
@@ -89,7 +89,7 @@ class Validator:
89
89
  which provides the instances to validate
90
90
  :param target_class: Name of the class within the schema to validate
91
91
  against. If ``None``, the class will be inferred from the schema by
92
- looked for a class with ``tree_root: true``. Defaults to ``None``.
92
+ looking for a class with ``tree_root: true``. Defaults to ``None``.
93
93
  :return: Iterator over validation results
94
94
  :rtype: Iterator[ValidationResult]
95
95
  """
@@ -18,6 +18,7 @@ from linkml.generators.jsonschemagen import JsonSchemaGenerator
18
18
  from linkml.generators.pythongen import PythonGenerator
19
19
  from linkml.utils import datautils
20
20
  from linkml.utils.datavalidator import DataValidator
21
+ from linkml.utils.deprecation import deprecation_warning
21
22
 
22
23
  logger = logging.getLogger(__name__)
23
24
 
@@ -29,6 +30,7 @@ class HashableSchemaDefinition(SchemaDefinition):
29
30
 
30
31
  @lru_cache(maxsize=None)
31
32
  def _generate_jsonschema(schema, top_class, closed, include_range_class_descendants):
33
+ deprecation_warning("validators")
32
34
  logger.debug("Generating JSON Schema")
33
35
  not_closed = not closed
34
36
  return JsonSchemaGenerator(
@@ -42,6 +44,7 @@ def _generate_jsonschema(schema, top_class, closed, include_range_class_descenda
42
44
 
43
45
  class JsonSchemaDataValidatorError(Exception):
44
46
  def __init__(self, validation_messages: List[str]) -> None:
47
+ deprecation_warning("validators")
45
48
  super().__init__("\n".join(validation_messages))
46
49
  self.validation_messages = validation_messages
47
50
 
@@ -56,6 +59,7 @@ class JsonSchemaDataValidator(DataValidator):
56
59
  _hashable_schema: Union[str, HashableSchemaDefinition] = field(init=False, repr=False)
57
60
 
58
61
  def __setattr__(self, __name: str, __value: Any) -> None:
62
+ deprecation_warning("validators")
59
63
  if __name == "schema":
60
64
  if isinstance(__value, SchemaDefinition):
61
65
  self._hashable_schema = HashableSchemaDefinition(**asdict(__value))
@@ -65,6 +69,7 @@ class JsonSchemaDataValidator(DataValidator):
65
69
 
66
70
  def validate_file(self, input: str, format: str = "json", **kwargs):
67
71
  # return self.validate_object(obj)
72
+ deprecation_warning("validators")
68
73
  pass
69
74
 
70
75
  def validate_object(self, data: YAMLRoot, target_class: Type[YAMLRoot] = None, closed: bool = True) -> None:
@@ -76,6 +81,7 @@ class JsonSchemaDataValidator(DataValidator):
76
81
  :param closed:
77
82
  :return:
78
83
  """
84
+ deprecation_warning("validators")
79
85
  if target_class is None:
80
86
  target_class = type(data)
81
87
  inst_dict = as_simple_dict(data)
@@ -90,6 +96,7 @@ class JsonSchemaDataValidator(DataValidator):
90
96
  :param closed:
91
97
  :return:
92
98
  """
99
+ deprecation_warning("validators")
93
100
  results = list(self.iter_validate_dict(data, target_class, closed))
94
101
  if results:
95
102
  raise JsonSchemaDataValidatorError(results)
@@ -97,6 +104,7 @@ class JsonSchemaDataValidator(DataValidator):
97
104
  def iter_validate_dict(
98
105
  self, data: dict, target_class_name: ClassDefinitionName = None, closed: bool = True
99
106
  ) -> Iterable[str]:
107
+ deprecation_warning("validators")
100
108
  if self.schema is None:
101
109
  raise ValueError("schema object must be set")
102
110
  if target_class_name is None:
@@ -159,6 +167,8 @@ def cli(
159
167
  """
160
168
  Validates instance data
161
169
  """
170
+ deprecation_warning("validators")
171
+
162
172
  if module is None:
163
173
  if schema is None:
164
174
  raise Exception("must pass one of module OR schema")
@@ -14,11 +14,13 @@ from linkml.generators.sparqlgen import SparqlGenerator
14
14
  from linkml.reporting import CheckResult, Report
15
15
  from linkml.utils.datautils import _get_format, dumpers_loaders, get_dumper
16
16
  from linkml.utils.datavalidator import DataValidator
17
+ from linkml.utils.deprecation import deprecation_warning
17
18
 
18
19
  logger = logging.getLogger(__name__)
19
20
 
20
21
 
21
22
  def sparqljson2dict(row: dict):
23
+ deprecation_warning("validators")
22
24
  return {k: v["value"] for k, v in row.items()}
23
25
 
24
26
 
@@ -37,11 +39,13 @@ class SparqlDataValidator(DataValidator):
37
39
  queries: dict = None
38
40
 
39
41
  def validate_file(self, input: str, format: str = "turtle", **kwargs):
42
+ deprecation_warning("validators")
40
43
  g = Graph()
41
44
  g.parse(input, format=format)
42
45
  return self.validate_graph(g, **kwargs)
43
46
 
44
47
  def validate_graph(self, g: Graph, **kwargs):
48
+ deprecation_warning("validators")
45
49
  if self.queries is None:
46
50
  self.queries = SparqlGenerator(self.schema, **kwargs).queries
47
51
  invalid = []
@@ -61,6 +65,7 @@ class SparqlDataValidator(DataValidator):
61
65
  return invalid
62
66
 
63
67
  def validate_endpoint(self, url: str, **kwargs):
68
+ deprecation_warning("validators")
64
69
  if self.queries is None:
65
70
  self.queries = SparqlGenerator(self.schema, **kwargs).queries
66
71
  invalid = []
@@ -81,6 +86,7 @@ class SparqlDataValidator(DataValidator):
81
86
  return report
82
87
 
83
88
  def load_schema(self, schema: Union[str, SchemaDefinition]):
89
+ deprecation_warning("validators")
84
90
  self.schemaview = SchemaView(schema)
85
91
  self.schema = self.schemaview.schema
86
92
  # self.schema = YAMLGenerator(schema).schema
@@ -124,6 +130,7 @@ def cli(
124
130
 
125
131
  linkml-sparql-validate -U http://sparql.hegroup.org/sparql -s tests/test_validation/input/omo.yaml
126
132
  """
133
+ deprecation_warning("validators")
127
134
  validator = SparqlDataValidator(schema)
128
135
  if endpoint_url is not None:
129
136
  results = validator.validate_endpoint(endpoint_url, limit=limit, named_graphs=named_graph)
@@ -22,6 +22,7 @@ from linkml_runtime.utils.formatutils import camelcase
22
22
 
23
23
  from linkml._version import __version__
24
24
  from linkml.generators.pythongen import PythonGenerator
25
+ from linkml.utils.helpers import get_range_associated_slots
25
26
  from linkml.validator import Validator, _get_default_validator
26
27
 
27
28
  logger = logging.getLogger(__name__)
@@ -244,10 +245,28 @@ class ExampleRunner:
244
245
  raise ValueError(f"Cannot find unique class for URI {target_class}; got: {target_classes}")
245
246
  target_class = target_classes[0]
246
247
  new_dict_obj = {}
248
+
247
249
  for k, v in dict_obj.items():
248
250
  if v is not None:
249
251
  islot = sv.induced_slot(k, target_class)
250
- v2 = self._load_from_dict(v, target_class=islot.range)
252
+ # if slot is a dictionary, repeat key in dictionary value object
253
+ if islot.multivalued and islot.inlined and not islot.inlined_as_list:
254
+ (range_id_slot, range_simple_dict_value_slot, _) = get_range_associated_slots(
255
+ self.schemaview, islot.range
256
+ )
257
+ v_as_list = []
258
+ for ik, iv in v.items():
259
+ # simple dictionaries can be simply created
260
+ if range_simple_dict_value_slot is not None:
261
+ value = {range_id_slot.name: ik, range_simple_dict_value_slot.name: iv}
262
+ # other dictionaries => simply add the identifier to the dictionary
263
+ else:
264
+ value = iv
265
+ value[range_id_slot.name] = ik
266
+ v_as_list.append(value)
267
+ v2 = self._load_from_dict(v_as_list, target_class=islot.range)
268
+ else:
269
+ v2 = self._load_from_dict(v, target_class=islot.range)
251
270
  new_dict_obj[k] = v2
252
271
  py_target_class = getattr(self.python_module, camelcase(target_class))
253
272
  return py_target_class(**new_dict_obj)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkml
3
- Version: 1.8.5
3
+ Version: 1.8.6
4
4
  Summary: Linked Open Data Modeling Language
5
5
  Home-page: https://linkml.io/linkml/
6
6
  Keywords: schema,linked data,data modeling,rdf,owl,biolink
@@ -53,7 +53,7 @@ Requires-Dist: pyyaml
53
53
  Requires-Dist: rdflib (>=6.0.0)
54
54
  Requires-Dist: requests (>=2.22)
55
55
  Requires-Dist: sqlalchemy (>=1.4.31)
56
- Requires-Dist: typing-extensions (>=4.4.0) ; python_version < "3.9"
56
+ Requires-Dist: typing-extensions (>=4.6.0) ; python_version < "3.12"
57
57
  Requires-Dist: watchdog (>=0.9.0)
58
58
  Project-URL: Documentation, https://linkml.io/linkml/
59
59
  Project-URL: Repository, https://github.com/linkml/linkml