linkml 1.9.0rc1__py3-none-any.whl → 1.9.1__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 (82) hide show
  1. linkml/generators/common/build.py +1 -7
  2. linkml/generators/common/ifabsent_processor.py +20 -20
  3. linkml/generators/common/lifecycle.py +2 -1
  4. linkml/generators/common/naming.py +1 -1
  5. linkml/generators/common/template.py +5 -5
  6. linkml/generators/common/type_designators.py +1 -3
  7. linkml/generators/csvgen.py +3 -3
  8. linkml/generators/docgen.py +20 -25
  9. linkml/generators/dotgen.py +4 -4
  10. linkml/generators/erdiagramgen.py +7 -7
  11. linkml/generators/excelgen.py +2 -3
  12. linkml/generators/golanggen.py +2 -2
  13. linkml/generators/golrgen.py +3 -3
  14. linkml/generators/jsonldcontextgen.py +4 -4
  15. linkml/generators/jsonschemagen.py +5 -5
  16. linkml/generators/markdowngen.py +8 -10
  17. linkml/generators/mermaidclassdiagramgen.py +2 -2
  18. linkml/generators/oocodegen.py +10 -10
  19. linkml/generators/owlgen.py +19 -18
  20. linkml/generators/plantumlgen.py +15 -15
  21. linkml/generators/prefixmapgen.py +5 -5
  22. linkml/generators/projectgen.py +10 -10
  23. linkml/generators/pydanticgen/array.py +15 -21
  24. linkml/generators/pydanticgen/build.py +4 -4
  25. linkml/generators/pydanticgen/includes.py +1 -1
  26. linkml/generators/pydanticgen/pydanticgen.py +24 -28
  27. linkml/generators/pydanticgen/template.py +36 -36
  28. linkml/generators/pythongen.py +21 -29
  29. linkml/generators/rdfgen.py +2 -2
  30. linkml/generators/shaclgen.py +9 -9
  31. linkml/generators/shexgen.py +3 -3
  32. linkml/generators/sparqlgen.py +3 -3
  33. linkml/generators/sqlalchemygen.py +2 -2
  34. linkml/generators/terminusdbgen.py +2 -3
  35. linkml/generators/typescriptgen.py +3 -3
  36. linkml/generators/yumlgen.py +13 -13
  37. linkml/linter/cli.py +1 -1
  38. linkml/linter/config/datamodel/config.py +207 -213
  39. linkml/linter/config/datamodel/config.yaml +51 -3
  40. linkml/linter/config/default.yaml +3 -0
  41. linkml/linter/formatters/markdown_formatter.py +2 -2
  42. linkml/linter/linter.py +4 -3
  43. linkml/linter/rules.py +38 -19
  44. linkml/reporting/model.py +11 -15
  45. linkml/transformers/logical_model_transformer.py +9 -8
  46. linkml/transformers/relmodel_transformer.py +6 -6
  47. linkml/transformers/schema_renamer.py +2 -2
  48. linkml/utils/converter.py +1 -1
  49. linkml/utils/deprecation.py +3 -3
  50. linkml/utils/execute_tutorial.py +5 -6
  51. linkml/utils/generator.py +17 -16
  52. linkml/utils/helpers.py +2 -2
  53. linkml/utils/logictools.py +5 -4
  54. linkml/utils/mergeutils.py +51 -5
  55. linkml/utils/schema_builder.py +8 -8
  56. linkml/utils/schema_fixer.py +8 -8
  57. linkml/utils/schemaloader.py +16 -15
  58. linkml/utils/schemasynopsis.py +29 -29
  59. linkml/utils/sqlutils.py +5 -5
  60. linkml/utils/typereferences.py +5 -6
  61. linkml/utils/validation.py +2 -2
  62. linkml/validator/cli.py +7 -6
  63. linkml/validator/loaders/delimited_file_loader.py +2 -1
  64. linkml/validator/loaders/json_loader.py +2 -1
  65. linkml/validator/loaders/loader.py +2 -1
  66. linkml/validator/loaders/passthrough_loader.py +2 -1
  67. linkml/validator/loaders/yaml_loader.py +2 -1
  68. linkml/validator/plugins/jsonschema_validation_plugin.py +2 -1
  69. linkml/validator/plugins/pydantic_validation_plugin.py +2 -1
  70. linkml/validator/plugins/recommended_slots_plugin.py +3 -2
  71. linkml/validator/plugins/shacl_validation_plugin.py +2 -1
  72. linkml/validator/plugins/validation_plugin.py +1 -1
  73. linkml/validator/report.py +3 -3
  74. linkml/validator/validator.py +3 -2
  75. linkml/validators/jsonschemavalidator.py +6 -5
  76. linkml/workspaces/datamodel/workspaces.py +21 -26
  77. linkml/workspaces/example_runner.py +7 -6
  78. {linkml-1.9.0rc1.dist-info → linkml-1.9.1.dist-info}/METADATA +6 -9
  79. {linkml-1.9.0rc1.dist-info → linkml-1.9.1.dist-info}/RECORD +82 -82
  80. {linkml-1.9.0rc1.dist-info → linkml-1.9.1.dist-info}/WHEEL +1 -1
  81. {linkml-1.9.0rc1.dist-info → linkml-1.9.1.dist-info}/LICENSE +0 -0
  82. {linkml-1.9.0rc1.dist-info → linkml-1.9.1.dist-info}/entry_points.txt +0 -0
@@ -38,7 +38,7 @@ classes:
38
38
  configured by a configuration file.
39
39
  attributes:
40
40
  no_empty_title:
41
- range: RuleConfig
41
+ range: NoEmptyTitleConfig
42
42
  description: >-
43
43
  Disallow empty titles on schema elements. Autofix will transform the element's
44
44
  name into a title.
@@ -141,8 +141,14 @@ classes:
141
141
  multivalued: true
142
142
  description: >-
143
143
  Default: []
144
- All elements except the ones with names specified in this list will be checked
145
-
144
+ All elements except the ones with names specified in this list will be checked
145
+ exclude_type:
146
+ range: MetamodelElementTypeEnum
147
+ multivalued: true
148
+ description: >-
149
+ Default: []
150
+ Elements of all types (ClassDefinition, SlotDefinition, EnumDefinition, PermissibleValue, etc.) except the types specified in this list will be checked
151
+
146
152
  StandardNamingConfig:
147
153
  description: >-
148
154
  Additional configuration options for the `standard_naming` rule
@@ -153,6 +159,24 @@ classes:
153
159
  description: >-
154
160
  Default: false
155
161
  If true, permissible values will be checked for snake_case, otherwise UPPER_SNAKE
162
+ exclude_type:
163
+ range: MetamodelElementTypeEnum
164
+ multivalued: true
165
+ description: >-
166
+ Default: []
167
+ Elements of all types (ClassDefinition, SlotDefinition, EnumDefinition, PermissibleValue, etc.) except the types specified in this list will be checked
168
+ class_pattern:
169
+ range: string
170
+ required: false
171
+ description: >
172
+ If specified, permissible format pattern for classes can be provided either as one of the following:
173
+ snake, uppersnake, camel, uppercamel, kebab or as regular expression (e.g. "[a-z][_a-z0-9]+" for snake case)
174
+ slot_pattern:
175
+ range: string
176
+ required: false
177
+ description: >
178
+ If specified, permissible format pattern for slots can be provided either as one of the following:
179
+ snake, uppersnake, camel, uppercamel, kebab or as regular expression (e.g. "[a-z][_a-z0-9]+" for snake case)
156
180
 
157
181
  CanonicalPrefixesConfig:
158
182
  description: >-
@@ -168,6 +192,18 @@ classes:
168
192
  validation. The order of names is meaningful and will be preserved. See:
169
193
  https://github.com/linkml/prefixmaps#usage
170
194
 
195
+ NoEmptyTitleConfig:
196
+ description: >-
197
+ Additional configuration options for the no_empty_title rule
198
+ is_a: RuleConfig
199
+ attributes:
200
+ exclude_type:
201
+ range: MetamodelElementTypeEnum
202
+ multivalued: true
203
+ description: >-
204
+ Default: []
205
+ Elements of all types (ClassDefinition, SlotDefinition, EnumDefinition, PermissibleValue, etc.) except the types specified in this list will be checked
206
+
171
207
  enums:
172
208
  ExtendableConfigs:
173
209
  description: The permissible values for the `extends` field of a config file
@@ -184,3 +220,15 @@ enums:
184
220
  description: A violation of a rule at this level is a minor issue that should be fixed
185
221
  error:
186
222
  description: A violation of a rule at this level is a major issue that must be fixed
223
+ MetamodelElementTypeEnum:
224
+ description: >-
225
+ The permissible values for the exclude_type slot
226
+ permissible_values:
227
+ class_definition:
228
+ meaning: linkml:ClassDefinition
229
+ enum_definition:
230
+ meaning: linkml:EnumDefinition
231
+ permissible_value:
232
+ meaning: linkml:PermissibleValue
233
+ slot_definition:
234
+ meaning: linkml:SlotDefinition
@@ -1,6 +1,7 @@
1
1
  rules:
2
2
  no_empty_title:
3
3
  level: disabled
4
+ exclude_type: []
4
5
  permissible_values_format:
5
6
  level: disabled
6
7
  format: uppersnake
@@ -12,6 +13,7 @@ rules:
12
13
  level: disabled
13
14
  include: []
14
15
  exclude: []
16
+ exclude_type: []
15
17
  no_xsd_int_type:
16
18
  level: disabled
17
19
  no_invalid_slot_usage:
@@ -19,6 +21,7 @@ rules:
19
21
  standard_naming:
20
22
  level: disabled
21
23
  permissible_values_upper_case: false
24
+ exclude_type: []
22
25
  canonical_prefixes:
23
26
  level: disabled
24
27
  prefixmaps_contexts:
@@ -1,5 +1,5 @@
1
1
  from collections import defaultdict
2
- from typing import IO, Any, List, Optional
2
+ from typing import IO, Any, Optional
3
3
 
4
4
  from linkml.linter.config.datamodel.config import RuleLevel
5
5
  from linkml.linter.linter import LinterProblem
@@ -53,7 +53,7 @@ class MarkdownFormatter(Formatter):
53
53
  self.write(f"### {name}")
54
54
  self.write_schema_problems(problems)
55
55
 
56
- def write_schema_problems(self, problems: List[LinterProblem]):
56
+ def write_schema_problems(self, problems: list[LinterProblem]):
57
57
  errors = [p for p in problems if str(p.level) == RuleLevel.error.text]
58
58
  warnings = [p for p in problems if str(p.level) == RuleLevel.warning.text]
59
59
  if errors:
linkml/linter/linter.py CHANGED
@@ -1,9 +1,10 @@
1
1
  import inspect
2
+ from collections.abc import Iterable
2
3
  from copy import deepcopy
3
4
  from dataclasses import dataclass
4
5
  from functools import lru_cache
5
6
  from pathlib import Path
6
- from typing import Any, Dict, Iterable, Union
7
+ from typing import Any, Union
7
8
 
8
9
  import jsonschema
9
10
  import yaml
@@ -29,7 +30,7 @@ class LinterProblem:
29
30
 
30
31
 
31
32
  @lru_cache
32
- def get_named_config(name: str) -> Dict[str, Any]:
33
+ def get_named_config(name: str) -> dict[str, Any]:
33
34
  config_path = str(Path(__file__).parent / f"config/{name}.yaml")
34
35
  with open(config_path) as config_file:
35
36
  return yaml.safe_load(config_file)
@@ -67,7 +68,7 @@ def _format_path(path):
67
68
 
68
69
 
69
70
  class Linter:
70
- def __init__(self, config: Dict[str, Any] = {}) -> None:
71
+ def __init__(self, config: dict[str, Any] = {}) -> None:
71
72
  default_config = deepcopy(get_named_config("default"))
72
73
  merged_config = config
73
74
  if config.get("extends") == ExtendableConfigs.recommended.text:
linkml/linter/rules.py CHANGED
@@ -1,7 +1,8 @@
1
1
  import re
2
2
  from abc import ABC, abstractmethod
3
- from functools import lru_cache
4
- from typing import Callable, Iterable, List
3
+ from collections.abc import Iterable
4
+ from functools import cache
5
+ from typing import Callable
5
6
 
6
7
  from linkml_runtime.linkml_model import ClassDefinition, ClassDefinitionName, Element, SlotDefinition
7
8
  from linkml_runtime.utils.schemaview import SchemaView
@@ -55,8 +56,14 @@ class LinterRule(ABC):
55
56
  class NoEmptyTitleRule(LinterRule):
56
57
  id = "no_empty_title"
57
58
 
59
+ # todo PVs are not checked for titles yet
60
+
58
61
  def check(self, schema_view: SchemaView, fix: bool = False) -> Iterable[LinterProblem]:
62
+ excluded_types = [t.text if hasattr(t, "text") else str(t) for t in getattr(self.config, "exclude_type", [])]
59
63
  for e in schema_view.all_elements(imports=False).values():
64
+ element_type_name = type(e).class_name
65
+ if element_type_name in excluded_types:
66
+ continue
60
67
  if fix and e.title is None:
61
68
  title = e.name.replace("_", " ")
62
69
  title = self.uncamel(title).lower()
@@ -89,8 +96,8 @@ class PermissibleValuesFormatRule(LinterRule):
89
96
  yield LinterProblem(f"{self.format_element(enum_def)} has permissible value '{value}'")
90
97
 
91
98
 
92
- @lru_cache(maxsize=None)
93
- def _get_recommended_metamodel_slots() -> List[str]:
99
+ @cache
100
+ def _get_recommended_metamodel_slots() -> list[str]:
94
101
  meta_schema_view = SchemaView(LOCAL_METAMODEL_YAML_FILE)
95
102
  recommended_meta_slots = []
96
103
  for class_name in meta_schema_view.all_classes(imports=False).keys():
@@ -104,16 +111,22 @@ def _get_recommended_metamodel_slots() -> List[str]:
104
111
  class RecommendedRule(LinterRule):
105
112
  id = "recommended"
106
113
 
114
+ # todo PVs are not checked for recommended fields yet
115
+
107
116
  def __init__(self, config: RecommendedRuleConfig) -> None:
108
117
  self.config = config
109
118
 
110
119
  def check(self, schema_view: SchemaView, fix: bool = False):
111
120
  recommended_meta_slots = _get_recommended_metamodel_slots()
121
+ excluded_types = [t.text if hasattr(t, "text") else str(t) for t in getattr(self.config, "exclude_type", [])]
112
122
  for element_name, element_definition in schema_view.all_elements(imports=False).items():
123
+ element_type_name = type(element_definition).class_name
113
124
  if self.config.include and element_name not in self.config.include:
114
125
  continue
115
126
  if element_name in self.config.exclude:
116
127
  continue
128
+ if element_type_name in excluded_types:
129
+ continue
117
130
  for meta_slot_name, meta_slot_value in vars(element_definition).items():
118
131
  key = f"{element_definition.class_name}__{meta_slot_name}"
119
132
  if key in recommended_meta_slots and not meta_slot_value:
@@ -153,7 +166,7 @@ class TreeRootClassRule(LinterRule):
153
166
  must_have_identifier=False,
154
167
  slot_name_func: Callable = None,
155
168
  convert_camel_case=False,
156
- ) -> List[SlotDefinition]:
169
+ ) -> list[SlotDefinition]:
157
170
  """
158
171
  Adds index slots to a container pointing at all top-level classes
159
172
 
@@ -216,6 +229,7 @@ class StandardNamingRule(LinterRule):
216
229
  self.config = config
217
230
 
218
231
  def check(self, schema_view: SchemaView, fix: bool = False) -> Iterable[LinterProblem]:
232
+ excluded_types = [t.text if hasattr(t, "text") else str(t) for t in getattr(self.config, "exclude_type", [])]
219
233
  class_pattern = (
220
234
  self.PATTERNS["uppercamel"]
221
235
  if not self.config.class_pattern
@@ -232,24 +246,29 @@ class StandardNamingRule(LinterRule):
232
246
  self.PATTERNS["uppersnake"] if self.config.permissible_values_upper_case else self.PATTERNS["snake"]
233
247
  )
234
248
 
235
- for class_name in schema_view.all_classes(imports=False).keys():
236
- if class_pattern.fullmatch(class_name) is None:
237
- yield LinterProblem(f"Class has name '{class_name}'")
249
+ if "class_definition" not in excluded_types:
250
+ for class_name in schema_view.all_classes(imports=False).keys():
251
+ if class_pattern.fullmatch(class_name) is None:
252
+ yield LinterProblem(f"Class has name '{class_name}'")
238
253
 
239
- for slot_name in schema_view.all_slots(imports=False).keys():
240
- if slot_pattern.fullmatch(slot_name) is None:
241
- yield LinterProblem(f"Slot has name '{slot_name}'")
254
+ if "slot_definition" not in excluded_types:
255
+ for slot_name in schema_view.all_slots(imports=False).keys():
256
+ if slot_pattern.fullmatch(slot_name) is None:
257
+ yield LinterProblem(f"Slot has name '{slot_name}'")
242
258
 
243
259
  for enum_name, enum_definition in schema_view.all_enums(imports=False).items():
244
- if enum_pattern.fullmatch(enum_name) is None:
245
- yield LinterProblem(f"Enum has name '{enum_name}'")
246
260
 
247
- for permissible_value_name in enum_definition.permissible_values.keys():
248
- if permissible_value_pattern.fullmatch(permissible_value_name) is None:
249
- yield LinterProblem(
250
- f"Permissible value of {self.format_element(enum_definition)} "
251
- f"has name '{permissible_value_name}'"
252
- )
261
+ if "enum_definition" not in excluded_types:
262
+ if enum_pattern.fullmatch(enum_name) is None:
263
+ yield LinterProblem(f"Enum has name '{enum_name}'")
264
+
265
+ if "permissible_value" not in excluded_types:
266
+ for permissible_value_name in enum_definition.permissible_values.keys():
267
+ if permissible_value_pattern.fullmatch(permissible_value_name) is None:
268
+ yield LinterProblem(
269
+ f"Permissible value of {self.format_element(enum_definition)} "
270
+ f"has name '{permissible_value_name}'"
271
+ )
253
272
 
254
273
 
255
274
  class CanonicalPrefixesRule(LinterRule):
linkml/reporting/model.py CHANGED
@@ -6,14 +6,12 @@
6
6
  # description: A datamodel for reports on data
7
7
  # license: https://creativecommons.org/publicdomain/zero/1.0/
8
8
 
9
- import dataclasses
10
9
  from dataclasses import dataclass
11
- from typing import Any, ClassVar, Dict, List, Optional, Union
10
+ from typing import Any, ClassVar, Optional, Union
12
11
 
13
12
  from jsonasobj2 import as_dict
14
13
  from linkml_runtime.linkml_model.meta import EnumDefinition, PermissibleValue
15
14
  from linkml_runtime.utils.curienamespace import CurieNamespace
16
- from linkml_runtime.utils.dataclass_extensions_376 import dataclasses_init_fn_with_kwargs
17
15
  from linkml_runtime.utils.enumerations import EnumDefinitionImpl
18
16
  from linkml_runtime.utils.metamodelcore import NodeIdentifier, URIorCURIE, empty_list
19
17
  from linkml_runtime.utils.slot import Slot
@@ -22,8 +20,6 @@ from rdflib import URIRef
22
20
 
23
21
  metamodel_version = "1.7.0"
24
22
 
25
- # Overwrite dataclasses _init_fn to add **kwargs in __init__
26
- dataclasses._init_fn = dataclasses_init_fn_with_kwargs
27
23
 
28
24
  # Namespaces
29
25
  LINKML = CurieNamespace("linkml", "https://w3id.org/linkml/")
@@ -49,16 +45,16 @@ class Report(YAMLRoot):
49
45
  A report object
50
46
  """
51
47
 
52
- _inherited_slots: ClassVar[List[str]] = []
48
+ _inherited_slots: ClassVar[list[str]] = []
53
49
 
54
50
  class_class_uri: ClassVar[URIRef] = REPORTING.Report
55
51
  class_class_curie: ClassVar[str] = "reporting:Report"
56
52
  class_name: ClassVar[str] = "report"
57
53
  class_model_uri: ClassVar[URIRef] = REPORTING.Report
58
54
 
59
- results: Optional[Union[Union[dict, "CheckResult"], List[Union[dict, "CheckResult"]]]] = empty_list()
55
+ results: Optional[Union[Union[dict, "CheckResult"], list[Union[dict, "CheckResult"]]]] = empty_list()
60
56
 
61
- def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
57
+ def __post_init__(self, *_: list[str], **kwargs: dict[str, Any]):
62
58
  if not isinstance(self.results, list):
63
59
  self.results = [self.results] if self.results is not None else []
64
60
  self.results = [v if isinstance(v, CheckResult) else CheckResult(**as_dict(v)) for v in self.results]
@@ -72,7 +68,7 @@ class CheckResult(YAMLRoot):
72
68
  An individual check
73
69
  """
74
70
 
75
- _inherited_slots: ClassVar[List[str]] = []
71
+ _inherited_slots: ClassVar[list[str]] = []
76
72
 
77
73
  class_class_uri: ClassVar[URIRef] = REPORTING.CheckResult
78
74
  class_class_curie: ClassVar[str] = "reporting:CheckResult"
@@ -88,7 +84,7 @@ class CheckResult(YAMLRoot):
88
84
  source: Optional[Union[str, NodeIdentifier]] = None
89
85
  info: Optional[str] = None
90
86
 
91
- def __post_init__(self, *_: List[str], **kwargs: Dict[str, Any]):
87
+ def __post_init__(self, *_: list[str], **kwargs: dict[str, Any]):
92
88
  if self.type is not None and not isinstance(self.type, URIorCURIE):
93
89
  self.type = URIorCURIE(self.type)
94
90
 
@@ -117,7 +113,7 @@ class CheckResult(YAMLRoot):
117
113
 
118
114
 
119
115
  class Problem(CheckResult):
120
- _inherited_slots: ClassVar[List[str]] = []
116
+ _inherited_slots: ClassVar[list[str]] = []
121
117
 
122
118
  class_class_uri: ClassVar[URIRef] = REPORTING.Problem
123
119
  class_class_curie: ClassVar[str] = "reporting:Problem"
@@ -130,7 +126,7 @@ class ProblemSlotUndeclared(Problem):
130
126
  A problem in which an undeclared slot is used
131
127
  """
132
128
 
133
- _inherited_slots: ClassVar[List[str]] = []
129
+ _inherited_slots: ClassVar[list[str]] = []
134
130
 
135
131
  class_class_uri: ClassVar[URIRef] = REPORTING.ProblemSlotUndeclared
136
132
  class_class_curie: ClassVar[str] = "reporting:ProblemSlotUndeclared"
@@ -143,7 +139,7 @@ class ProblemSlotInapplicable(Problem):
143
139
  A problem in which a slot is used in an instance of a class where the slot is not applicable for that class
144
140
  """
145
141
 
146
- _inherited_slots: ClassVar[List[str]] = []
142
+ _inherited_slots: ClassVar[list[str]] = []
147
143
 
148
144
  class_class_uri: ClassVar[URIRef] = REPORTING.ProblemSlotInapplicable
149
145
  class_class_curie: ClassVar[str] = "reporting:ProblemSlotInapplicable"
@@ -156,7 +152,7 @@ class ProblemSlotMissing(Problem):
156
152
  A problem in which an instance of a class has a required slot which is not filled in
157
153
  """
158
154
 
159
- _inherited_slots: ClassVar[List[str]] = []
155
+ _inherited_slots: ClassVar[list[str]] = []
160
156
 
161
157
  class_class_uri: ClassVar[URIRef] = REPORTING.ProblemSlotMissing
162
158
  class_class_curie: ClassVar[str] = "reporting:ProblemSlotMissing"
@@ -268,5 +264,5 @@ slots.report__results = Slot(
268
264
  curie=REPORTING.curie("results"),
269
265
  model_uri=REPORTING.report__results,
270
266
  domain=None,
271
- range=Optional[Union[Union[dict, CheckResult], List[Union[dict, CheckResult]]]],
267
+ range=Optional[Union[Union[dict, CheckResult], list[Union[dict, CheckResult]]]],
272
268
  )
@@ -57,9 +57,10 @@ See logictools.py for the symbolic reasoning engine.
57
57
  """
58
58
 
59
59
  import logging
60
+ from collections.abc import Iterator
60
61
  from copy import deepcopy
61
62
  from dataclasses import dataclass
62
- from typing import Any, Callable, Dict, Iterator, List, Optional, Union
63
+ from typing import Any, Callable, Optional, Union
63
64
 
64
65
  from linkml_runtime import SchemaView
65
66
  from linkml_runtime.dumpers import json_dumper
@@ -340,7 +341,7 @@ class LogicalModelTransformer(ModelTransformer):
340
341
  a lack of range assignment.
341
342
  """
342
343
 
343
- reason_over_metamodel_slots: Optional[List[str]] = None
344
+ reason_over_metamodel_slots: Optional[list[str]] = None
344
345
  """
345
346
  If set, only reason over the specified metamodel slots.
346
347
  """
@@ -407,10 +408,10 @@ class LogicalModelTransformer(ModelTransformer):
407
408
  self,
408
409
  target_schema: SchemaDefinition,
409
410
  target_class_name: ClassDefinitionName,
410
- ancestors: List[ClassDefinitionName],
411
+ ancestors: list[ClassDefinitionName],
411
412
  ):
412
413
  anc_classes = [self.schemaview.get_class(ancestor) for ancestor in ancestors]
413
- attributes: Dict[SlotDefinitionName, SlotDefinition] = {}
414
+ attributes: dict[SlotDefinitionName, SlotDefinition] = {}
414
415
  for ancestor_class in anc_classes:
415
416
  top_level_slots = [(s, target_schema.slots[s]) for s in ancestor_class.slots]
416
417
  for slot_name, slot_expr in (
@@ -543,7 +544,7 @@ class LogicalModelTransformer(ModelTransformer):
543
544
  elif isinstance(expr, logictools.Not):
544
545
  self._simplify_member_ofs(expr.operand)
545
546
 
546
- def _remove_redundant(self, elements: List[str]) -> List[str]:
547
+ def _remove_redundant(self, elements: list[str]) -> list[str]:
547
548
  sv = self.schemaview
548
549
  redundant = set()
549
550
  if not self.preserve_class_mixins:
@@ -568,7 +569,7 @@ class LogicalModelTransformer(ModelTransformer):
568
569
  logger.warning(f"Unknown class {x} in {elements}")
569
570
  return [x for x in elements if x not in redundant]
570
571
 
571
- def _type_descendants(self, type_name: str, imports=True, reflexive=True, depth_first=True) -> List[str]:
572
+ def _type_descendants(self, type_name: str, imports=True, reflexive=True, depth_first=True) -> list[str]:
572
573
  # TODO: move this to schemaview
573
574
  sv = self.schemaview
574
575
  from linkml_runtime.utils.schemaview import _closure
@@ -584,7 +585,7 @@ class LogicalModelTransformer(ModelTransformer):
584
585
  depth_first=depth_first,
585
586
  )
586
587
 
587
- def _enum_descendants(self, enum_name: str, imports=True, reflexive=True, depth_first=True) -> List[str]:
588
+ def _enum_descendants(self, enum_name: str, imports=True, reflexive=True, depth_first=True) -> list[str]:
588
589
  # TODO: move this to schemaview
589
590
  sv = self.schemaview
590
591
  from linkml_runtime.utils.schemaview import _closure
@@ -754,7 +755,7 @@ class LogicalModelTransformer(ModelTransformer):
754
755
  self,
755
756
  attribute: Union[SlotDefinition, AnonymousSlotExpression],
756
757
  root_slot: SlotDefinition = None,
757
- stack: List = None,
758
+ stack: list = None,
758
759
  ) -> str:
759
760
  # Note: in future versions of the metamodel, multivalued may move to the expression
760
761
  if stack is None:
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from copy import copy
3
3
  from dataclasses import dataclass, field
4
- from typing import Dict, List, Optional
4
+ from typing import Optional
5
5
 
6
6
  from linkml_runtime.linkml_model import (
7
7
  Annotation,
@@ -105,7 +105,7 @@ class MultivaluedScalar(RelationalMapping):
105
105
  mapping_type: str = "MultivaluedScalar"
106
106
 
107
107
 
108
- def add_attribute(attributes: Dict[str, SlotDefinition], tgt_slot: SlotDefinition) -> None:
108
+ def add_attribute(attributes: dict[str, SlotDefinition], tgt_slot: SlotDefinition) -> None:
109
109
  attributes[tgt_slot.name] = tgt_slot
110
110
 
111
111
 
@@ -114,11 +114,11 @@ def add_annotation(element: Definition, tag: str, value: str) -> None:
114
114
  element.annotations[ann.tag] = ann
115
115
 
116
116
 
117
- def get_primary_key_attributes(cls: ClassDefinition) -> List[SlotDefinitionName]:
117
+ def get_primary_key_attributes(cls: ClassDefinition) -> list[SlotDefinitionName]:
118
118
  return [a.name for a in cls.attributes.values() if RelationalAnnotations.PRIMARY_KEY in a.annotations]
119
119
 
120
120
 
121
- def get_foreign_key_map(cls: ClassDefinition) -> Dict[SlotDefinitionName, str]:
121
+ def get_foreign_key_map(cls: ClassDefinition) -> dict[SlotDefinitionName, str]:
122
122
  return {
123
123
  a.name: a.annotations[RelationalAnnotations.FOREIGN_KEY].value
124
124
  for a in cls.attributes.values()
@@ -133,7 +133,7 @@ class TransformationResult:
133
133
  """
134
134
 
135
135
  schema: SchemaDefinition
136
- mappings: List[RelationalMapping]
136
+ mappings: list[RelationalMapping]
137
137
 
138
138
 
139
139
  @dataclass
@@ -412,7 +412,7 @@ class RelationalModelTransformer:
412
412
  return a
413
413
  return None
414
414
 
415
- def get_reference_map(self) -> List[Link]:
415
+ def get_reference_map(self) -> list[Link]:
416
416
  """
417
417
  Extract all class-slot-range references
418
418
 
@@ -1,6 +1,6 @@
1
1
  from copy import deepcopy
2
2
  from dataclasses import dataclass, field
3
- from typing import Any, Callable, Dict, Type
3
+ from typing import Any, Callable
4
4
 
5
5
  import click
6
6
  from jsonasobj2 import as_dict
@@ -35,7 +35,7 @@ class SchemaRenamer:
35
35
  Renames schema elements
36
36
  """
37
37
 
38
- rename_function_map: Dict[Type, Callable] = field(default_factory=lambda: {})
38
+ rename_function_map: dict[type, Callable] = field(default_factory=lambda: {})
39
39
  schema: SchemaDefinition = None
40
40
 
41
41
  def rename_elements(self, schema: SchemaDefinition) -> SchemaDefinition:
linkml/utils/converter.py CHANGED
@@ -123,7 +123,7 @@ def cli(
123
123
  prefix_path = pathlib.Path(prefix_file).resolve()
124
124
  if not prefix_path.exists():
125
125
  raise Exception(f"Path {prefix_file} to prefix map does not exists.")
126
- with open(prefix_path, "r") as prefix_stream:
126
+ with open(prefix_path) as prefix_stream:
127
127
  raw_prefix_map = yaml.safe_load(prefix_stream)
128
128
  prefix_file_map = raw_prefix_map.get("prefixes", None)
129
129
  if prefix_file_map is None:
@@ -206,7 +206,7 @@ DEPRECATIONS = (
206
206
  Deprecation(
207
207
  name="pydanticgen-v1",
208
208
  deprecated_in=SemVer.from_str("1.7.5"),
209
- removed_in=SemVer.from_str("1.8.0"),
209
+ removed_in=SemVer.from_str("1.10.0"),
210
210
  message="Support for generating Pydantic v1.*.* models with pydanticgen is deprecated",
211
211
  recommendation="Migrate any existing models to Pydantic v2",
212
212
  issue=1925,
@@ -214,7 +214,7 @@ DEPRECATIONS = (
214
214
  Deprecation(
215
215
  name="pydantic-v1",
216
216
  deprecated_in=SemVer.from_str("1.7.5"),
217
- removed_in=SemVer.from_str("1.9.0"),
217
+ removed_in=SemVer.from_str("1.10.0"),
218
218
  message=(
219
219
  "LinkML will set a dependency of pydantic>=2 and become incompatible "
220
220
  "with packages with pydantic<2 as a runtime dependency"
@@ -225,7 +225,7 @@ DEPRECATIONS = (
225
225
  Deprecation(
226
226
  name="validators",
227
227
  deprecated_in=SemVer.from_str("1.8.6"),
228
- removed_in=SemVer.from_str("1.9.0"),
228
+ removed_in=SemVer.from_str("1.10.0"),
229
229
  message=(
230
230
  "linkml.validators and linkml.utils.validation are the older versions "
231
231
  "of linkml.validator and have unmaintained, duplicated functionality"
@@ -4,7 +4,6 @@ import subprocess
4
4
  import sys
5
5
  from dataclasses import dataclass
6
6
  from pathlib import Path, PurePath
7
- from typing import List
8
7
 
9
8
  import click
10
9
 
@@ -26,8 +25,8 @@ class Block:
26
25
  output: str = None
27
26
  error: str = None
28
27
  expected_fail: bool = None
29
- prior_lines: List[str] = None
30
- annotations: List[str] = None
28
+ prior_lines: list[str] = None
29
+ annotations: list[str] = None
31
30
 
32
31
  def is_file_block(self) -> bool:
33
32
  return self.title and "." in self.title
@@ -39,7 +38,7 @@ class Block:
39
38
  return self.category == "bash"
40
39
 
41
40
 
42
- def execute_blocks(directory: str, blocks: List[Block]) -> List[str]:
41
+ def execute_blocks(directory: str, blocks: list[Block]) -> list[str]:
43
42
  """
44
43
  Execute the code blocks embedded in a tutorial
45
44
 
@@ -117,12 +116,12 @@ def execute_blocks(directory: str, blocks: List[Block]) -> List[str]:
117
116
  return errs
118
117
 
119
118
 
120
- def write_lines(lines: List[str]) -> None:
119
+ def write_lines(lines: list[str]) -> None:
121
120
  for line in lines:
122
121
  print(f"+++ {line}")
123
122
 
124
123
 
125
- def parse_file_to_blocks(input) -> List[Block]:
124
+ def parse_file_to_blocks(input) -> list[Block]:
126
125
  """
127
126
  Parses a markdown tutorial file to code blacks to be executed
128
127