linkml 1.8.7__py3-none-any.whl → 1.9.1rc2__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 (90) 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/class.md.jinja2 +1 -1
  9. linkml/generators/docgen/enum.md.jinja2 +1 -1
  10. linkml/generators/docgen/schema.md.jinja2 +1 -1
  11. linkml/generators/docgen/slot.md.jinja2 +4 -1
  12. linkml/generators/docgen/subset.md.jinja2 +1 -1
  13. linkml/generators/docgen/type.md.jinja2 +1 -1
  14. linkml/generators/docgen.py +20 -25
  15. linkml/generators/dotgen.py +4 -4
  16. linkml/generators/erdiagramgen.py +7 -7
  17. linkml/generators/excelgen.py +2 -3
  18. linkml/generators/golanggen.py +2 -2
  19. linkml/generators/golrgen.py +3 -3
  20. linkml/generators/jsonldcontextgen.py +4 -4
  21. linkml/generators/jsonschemagen.py +5 -5
  22. linkml/generators/linkmlgen.py +10 -2
  23. linkml/generators/markdowngen.py +8 -10
  24. linkml/generators/mermaidclassdiagramgen.py +2 -2
  25. linkml/generators/oocodegen.py +10 -10
  26. linkml/generators/owlgen.py +19 -18
  27. linkml/generators/plantumlgen.py +15 -15
  28. linkml/generators/prefixmapgen.py +5 -5
  29. linkml/generators/projectgen.py +10 -10
  30. linkml/generators/pydanticgen/array.py +15 -21
  31. linkml/generators/pydanticgen/build.py +4 -4
  32. linkml/generators/pydanticgen/includes.py +1 -1
  33. linkml/generators/pydanticgen/pydanticgen.py +24 -28
  34. linkml/generators/pydanticgen/template.py +36 -36
  35. linkml/generators/pythongen.py +21 -29
  36. linkml/generators/rdfgen.py +2 -2
  37. linkml/generators/shaclgen.py +19 -10
  38. linkml/generators/shexgen.py +3 -3
  39. linkml/generators/sparqlgen.py +3 -3
  40. linkml/generators/sqlalchemygen.py +2 -2
  41. linkml/generators/terminusdbgen.py +2 -3
  42. linkml/generators/typescriptgen.py +3 -3
  43. linkml/generators/yumlgen.py +13 -13
  44. linkml/linter/cli.py +1 -1
  45. linkml/linter/config/datamodel/config.py +207 -213
  46. linkml/linter/config/datamodel/config.yaml +51 -3
  47. linkml/linter/config/default.yaml +3 -0
  48. linkml/linter/formatters/markdown_formatter.py +2 -2
  49. linkml/linter/linter.py +4 -3
  50. linkml/linter/rules.py +38 -19
  51. linkml/reporting/model.py +11 -15
  52. linkml/transformers/logical_model_transformer.py +9 -8
  53. linkml/transformers/relmodel_transformer.py +6 -6
  54. linkml/transformers/schema_renamer.py +2 -2
  55. linkml/utils/converter.py +1 -1
  56. linkml/utils/deprecation.py +3 -3
  57. linkml/utils/execute_tutorial.py +5 -6
  58. linkml/utils/generator.py +17 -16
  59. linkml/utils/helpers.py +2 -2
  60. linkml/utils/logictools.py +5 -4
  61. linkml/utils/mergeutils.py +51 -5
  62. linkml/utils/schema_builder.py +8 -8
  63. linkml/utils/schema_fixer.py +8 -8
  64. linkml/utils/schemaloader.py +16 -15
  65. linkml/utils/schemasynopsis.py +29 -29
  66. linkml/utils/sqlutils.py +5 -5
  67. linkml/utils/typereferences.py +5 -6
  68. linkml/utils/validation.py +2 -2
  69. linkml/validator/cli.py +7 -6
  70. linkml/validator/loaders/delimited_file_loader.py +2 -1
  71. linkml/validator/loaders/json_loader.py +2 -1
  72. linkml/validator/loaders/loader.py +2 -1
  73. linkml/validator/loaders/passthrough_loader.py +2 -1
  74. linkml/validator/loaders/yaml_loader.py +2 -1
  75. linkml/validator/plugins/jsonschema_validation_plugin.py +2 -1
  76. linkml/validator/plugins/pydantic_validation_plugin.py +2 -1
  77. linkml/validator/plugins/recommended_slots_plugin.py +3 -2
  78. linkml/validator/plugins/shacl_validation_plugin.py +2 -1
  79. linkml/validator/plugins/validation_plugin.py +1 -1
  80. linkml/validator/report.py +3 -3
  81. linkml/validator/validator.py +3 -2
  82. linkml/validators/jsonschemavalidator.py +6 -5
  83. linkml/workspaces/datamodel/workspaces.py +21 -26
  84. linkml/workspaces/example_runner.py +7 -6
  85. {linkml-1.8.7.dist-info → linkml-1.9.1rc2.dist-info}/METADATA +6 -9
  86. linkml-1.9.1rc2.dist-info/RECORD +162 -0
  87. {linkml-1.8.7.dist-info → linkml-1.9.1rc2.dist-info}/WHEEL +1 -1
  88. linkml-1.8.7.dist-info/RECORD +0 -162
  89. {linkml-1.8.7.dist-info → linkml-1.9.1rc2.dist-info}/LICENSE +0 -0
  90. {linkml-1.8.7.dist-info → linkml-1.9.1rc2.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import Callable, List
4
+ from typing import Callable
5
5
 
6
6
  import click
7
7
  from jsonasobj2 import JsonObj, as_dict
@@ -30,6 +30,8 @@ class ShaclGenerator(Generator):
30
30
  """parameterized suffix to be appended. No suffix per default."""
31
31
  include_annotations: bool = False
32
32
  """True means include all class / slot / type annotations in generated Node or Property shapes"""
33
+ exclude_imports: bool = False
34
+ """If True, elements from imported ontologies won't be included in the generator's output"""
33
35
  generatorname = os.path.basename(__file__)
34
36
  generatorversion = "0.0.1"
35
37
  valid_formats = ["ttl"]
@@ -63,7 +65,7 @@ class ShaclGenerator(Generator):
63
65
  for pfx in self.schema.prefixes.values():
64
66
  g.bind(str(pfx.prefix_prefix), pfx.prefix_reference)
65
67
 
66
- for c in sv.all_classes().values():
68
+ for c in sv.all_classes(imports=not self.exclude_imports).values():
67
69
 
68
70
  def shape_pv(p, v):
69
71
  if v is not None:
@@ -256,7 +258,7 @@ class ShaclGenerator(Generator):
256
258
  else:
257
259
  logger.error(f"No URI for type {rt.name}")
258
260
 
259
- def _and_equals_string(self, g: Graph, func: Callable, values: List) -> None:
261
+ def _and_equals_string(self, g: Graph, func: Callable, values: list) -> None:
260
262
  pv_node = BNode()
261
263
  Collection(
262
264
  g,
@@ -271,7 +273,7 @@ class ShaclGenerator(Generator):
271
273
  annotations = item.annotations
272
274
  # item could be a class, slot or type
273
275
  # annotation type could be dict (on types) or JsonObj (on slots)
274
- if type(annotations) == JsonObj:
276
+ if type(annotations) is JsonObj:
275
277
  annotations = as_dict(annotations)
276
278
  for a in annotations.values():
277
279
  # If ':' is in the tag, treat it as a CURIE, otherwise string Literal
@@ -281,7 +283,7 @@ class ShaclGenerator(Generator):
281
283
  N_predicate = Literal(a["tag"], datatype=XSD.string)
282
284
  # If the value is a string and ':' is in the value, treat it as a CURIE,
283
285
  # otherwise treat as Literal with derived XSD datatype
284
- if type(a["value"]) == extended_str and ":" in a["value"]:
286
+ if type(a["value"]) is extended_str and ":" in a["value"]:
285
287
  N_object = URIRef(sv.expand_curie(a["value"]))
286
288
  else:
287
289
  N_object = Literal(a["value"], datatype=self._getXSDtype(a["value"]))
@@ -290,19 +292,19 @@ class ShaclGenerator(Generator):
290
292
 
291
293
  def _getXSDtype(self, value):
292
294
  value_type = type(value)
293
- if value_type == bool:
295
+ if value_type is bool:
294
296
  return XSD.boolean
295
- elif value_type == extended_str:
297
+ elif value_type is extended_str:
296
298
  return XSD.string
297
- elif value_type == extended_int:
299
+ elif value_type is extended_int:
298
300
  return XSD.integer
299
- elif value_type == extended_float:
301
+ elif value_type is extended_float:
300
302
  # TODO: distinguish between xsd:decimal and xsd:double?
301
303
  return XSD.decimal
302
304
  else:
303
305
  return None
304
306
 
305
- def _and_equals_string(self, g: Graph, func: Callable, values: List) -> None:
307
+ def _and_equals_string(self, g: Graph, func: Callable, values: list) -> None:
306
308
  pv_node = BNode()
307
309
  Collection(
308
310
  g,
@@ -364,6 +366,13 @@ def add_simple_data_type(func: Callable, r: ElementName) -> None:
364
366
  show_default=True,
365
367
  help="Use --include-annotations to include annotations of slots, types, and classes in the generated SHACL shapes.",
366
368
  )
369
+ @click.option(
370
+ "--exclude-imports/--include-imports",
371
+ default=False,
372
+ show_default=True,
373
+ help="Use --exclude-imports to exclude imported elements from the generated SHACL shapes. This is useful when "
374
+ "extending a substantial ontology to avoid large output files.",
375
+ )
367
376
  @click.version_option(__version__, "-V", "--version")
368
377
  def cli(yamlfile, **args):
369
378
  """Generate SHACL turtle from a LinkML model"""
@@ -3,7 +3,7 @@
3
3
  import os
4
4
  import urllib.parse as urlparse
5
5
  from dataclasses import dataclass, field
6
- from typing import List, Optional, Union
6
+ from typing import Optional, Union
7
7
 
8
8
  import click
9
9
  from jsonasobj import as_json as as_json_1
@@ -40,9 +40,9 @@ class ShExGenerator(Generator):
40
40
 
41
41
  # ObjectVars
42
42
  shex: Schema = field(default_factory=lambda: Schema()) # ShEx Schema being generated
43
- shapes: List = field(default_factory=lambda: [])
43
+ shapes: list = field(default_factory=lambda: [])
44
44
  shape: Optional[Shape] = None # Current shape being defined
45
- list_shapes: List[IRIREF] = field(default_factory=lambda: []) # Shapes that have been defined as lists
45
+ list_shapes: list[IRIREF] = field(default_factory=lambda: []) # Shapes that have been defined as lists
46
46
 
47
47
  def __post_init__(self):
48
48
  super().__post_init__()
@@ -3,7 +3,7 @@ import os
3
3
  from collections import defaultdict
4
4
  from dataclasses import dataclass
5
5
  from pathlib import Path
6
- from typing import Dict, List, Optional
6
+ from typing import Optional
7
7
 
8
8
  import click
9
9
  from jinja2 import Template
@@ -137,7 +137,7 @@ class SparqlGenerator(Generator):
137
137
  uses_schemaloader = False
138
138
 
139
139
  # ObjectVars
140
- named_graphs: Optional[List[str]] = None
140
+ named_graphs: Optional[list[str]] = None
141
141
  limit: Optional[int] = None
142
142
  sparql: Optional[str] = None
143
143
 
@@ -172,7 +172,7 @@ class SparqlGenerator(Generator):
172
172
  return self.sparql
173
173
 
174
174
  @staticmethod
175
- def split_sparql(sparql: str) -> Dict[str, str]:
175
+ def split_sparql(sparql: str) -> dict[str, str]:
176
176
  lines = sparql.split("\n")
177
177
  prolog = ""
178
178
  queries = defaultdict(str)
@@ -3,7 +3,7 @@ import os
3
3
  from collections import defaultdict
4
4
  from dataclasses import dataclass
5
5
  from types import ModuleType
6
- from typing import List, Optional, Union
6
+ from typing import Optional, Union
7
7
 
8
8
  import click
9
9
  from jinja2 import Template
@@ -180,7 +180,7 @@ class SQLAlchemyGenerator(Generator):
180
180
 
181
181
  # TODO: move this
182
182
  @staticmethod
183
- def order_classes_by_hierarchy(sv: SchemaView) -> List[ClassDefinitionName]:
183
+ def order_classes_by_hierarchy(sv: SchemaView) -> list[ClassDefinitionName]:
184
184
  olist = sv.class_roots()
185
185
  unprocessed = [cn for cn in sv.all_classes() if cn not in olist]
186
186
  while len(unprocessed) > 0:
@@ -2,7 +2,6 @@ import json
2
2
  import os
3
3
  import warnings
4
4
  from dataclasses import dataclass
5
- from typing import List
6
5
 
7
6
  import click
8
7
  from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
@@ -62,8 +61,8 @@ class TerminusdbGenerator(Generator):
62
61
  uses_schemaloader = True
63
62
 
64
63
  # ObjectVars
65
- classes: List = None
66
- raw_additions: List = None
64
+ classes: list = None
65
+ raw_additions: list = None
67
66
  clswq: str = None
68
67
 
69
68
  def __post_init__(self):
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import List, Optional
4
+ from typing import Optional
5
5
 
6
6
  import click
7
7
  from jinja2 import Template
@@ -252,7 +252,7 @@ class TypescriptGenerator(OOCodeGenerator):
252
252
  return "null"
253
253
 
254
254
  @staticmethod
255
- def parents(cls: ClassDefinition) -> List[ClassDefinitionName]:
255
+ def parents(cls: ClassDefinition) -> list[ClassDefinitionName]:
256
256
  if cls.is_a:
257
257
  parents = [cls.is_a]
258
258
  else:
@@ -262,7 +262,7 @@ class TypescriptGenerator(OOCodeGenerator):
262
262
  def default_value_for_type(self, typ: str) -> str:
263
263
  pass
264
264
 
265
- def required_slots(self, cls: ClassDefinition) -> List[SlotDefinitionName]:
265
+ def required_slots(self, cls: ClassDefinition) -> list[SlotDefinitionName]:
266
266
  return [s for s in self.schemaview.class_slots(cls.name) if self.schemaview.induced_slot(s, cls.name).required]
267
267
 
268
268
 
@@ -6,7 +6,7 @@ https://yuml.me/diagram/scruffy/class/samples
6
6
 
7
7
  import os
8
8
  from dataclasses import dataclass
9
- from typing import Callable, List, Optional, Set, cast
9
+ from typing import Callable, Optional, cast
10
10
 
11
11
  import click
12
12
  import requests
@@ -39,22 +39,22 @@ class YumlGenerator(Generator):
39
39
  valid_formats = ["yuml", "png", "pdf", "jpg", "json", "svg"]
40
40
  visit_all_class_slots = False
41
41
 
42
- referenced: Optional[Set[ClassDefinitionName]] = None # List of classes that have to be emitted
43
- generated: Optional[Set[ClassDefinitionName]] = None # List of classes that have been emitted
44
- box_generated: Optional[Set[ClassDefinitionName]] = None # Class boxes that have been emitted
45
- associations_generated: Optional[Set[ClassDefinitionName]] = None # Classes with associations generated
46
- focus_classes: Optional[Set[ClassDefinitionName]] = None # Classes to be completely filled
47
- gen_classes: Optional[Set[ClassDefinitionName]] = None # Classes to be generated
42
+ referenced: Optional[set[ClassDefinitionName]] = None # List of classes that have to be emitted
43
+ generated: Optional[set[ClassDefinitionName]] = None # List of classes that have been emitted
44
+ box_generated: Optional[set[ClassDefinitionName]] = None # Class boxes that have been emitted
45
+ associations_generated: Optional[set[ClassDefinitionName]] = None # Classes with associations generated
46
+ focus_classes: Optional[set[ClassDefinitionName]] = None # Classes to be completely filled
47
+ gen_classes: Optional[set[ClassDefinitionName]] = None # Classes to be generated
48
48
  output_file_name: Optional[str] = None # Location of output file if directory used
49
49
 
50
- classes: Set[ClassDefinitionName] = None
50
+ classes: set[ClassDefinitionName] = None
51
51
  directory: Optional[str] = None
52
52
  diagram_name: Optional[str] = None
53
53
  load_image: bool = True
54
54
 
55
55
  def visit_schema(
56
56
  self,
57
- classes: Set[ClassDefinitionName] = None,
57
+ classes: set[ClassDefinitionName] = None,
58
58
  directory: Optional[str] = None,
59
59
  diagram_name: Optional[str] = None,
60
60
  load_image: bool = True,
@@ -75,7 +75,7 @@ class YumlGenerator(Generator):
75
75
  self.gen_classes = self.synopsis.roots.classrefs
76
76
  self.referenced = self.gen_classes
77
77
  self.generated = set()
78
- yumlclassdef: List[str] = []
78
+ yumlclassdef: list[str] = []
79
79
  while self.referenced.difference(self.generated):
80
80
  cn = sorted(list(self.referenced.difference(self.generated)), reverse=True)[0]
81
81
  self.generated.add(cn)
@@ -115,7 +115,7 @@ class YumlGenerator(Generator):
115
115
  @param cn:
116
116
  @return:
117
117
  """
118
- slot_defs: List[str] = []
118
+ slot_defs: list[str] = []
119
119
  if cn not in self.box_generated and (not self.focus_classes or cn in self.focus_classes):
120
120
  cls = self.schema.classes[cn]
121
121
  for slot in self.filtered_cls_slots(cn, all_slots=True, filtr=lambda s: s.range not in self.schema.classes):
@@ -142,7 +142,7 @@ class YumlGenerator(Generator):
142
142
 
143
143
  # NOTE: YUML diagrams draw in the opposite order in which they are created, so we work from bottom to top and
144
144
  # from right to left
145
- assocs: List[str] = []
145
+ assocs: list[str] = []
146
146
  if cn not in self.associations_generated and (not self.focus_classes or cn in self.focus_classes):
147
147
  cls = self.schema.classes[cn]
148
148
 
@@ -222,7 +222,7 @@ class YumlGenerator(Generator):
222
222
  cn: ClassDefinitionName,
223
223
  all_slots: bool = True,
224
224
  filtr: Callable[[SlotDefinition], bool] = lambda: True,
225
- ) -> List[SlotDefinition]:
225
+ ) -> list[SlotDefinition]:
226
226
  """Return the set of slots associated with the class that meet the filter criteria. Slots will be returned
227
227
  in defining order, with class slots returned last
228
228
 
linkml/linter/cli.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import sys
3
+ from collections.abc import Iterable
3
4
  from pathlib import Path
4
- from typing import Iterable
5
5
 
6
6
  import click
7
7
  import yaml