linkml 1.7.10__py3-none-any.whl → 1.8.0__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.
@@ -99,20 +99,6 @@ URI: {{ gen.uri_link(element) }}
99
99
 
100
100
  {% include "common_metadata.md.jinja2" %}
101
101
 
102
-
103
- {% if schemaview.get_mappings(element.name).items() -%}
104
- ## Mappings
105
-
106
- | Mapping Type | Mapped Value |
107
- | --- | --- |
108
- {% for m, mt in schemaview.get_mappings(element.name).items() -%}
109
- {% if mt|length > 0 -%}
110
- | {{ m }} | {{ mt|join(', ') }} |
111
- {% endif -%}
112
- {% endfor %}
113
-
114
- {% endif -%}
115
-
116
102
  {% if gen.example_object_blobs(element.name) -%}
117
103
  ## Examples
118
104
  {% for name, blob in gen.example_object_blobs(element.name) -%}
@@ -75,4 +75,17 @@ Instances of this class *should* have identifiers with one of the following pref
75
75
  {% if element.imported_from %}
76
76
  * imported from: {{ element.imported_from }}
77
77
  {% endif %}
78
- {% endif %}
78
+ {% endif %}
79
+
80
+ {% if schemaview.get_mappings(element.name).items() -%}
81
+ ## Mappings
82
+
83
+ | Mapping Type | Mapped Value |
84
+ | --- | --- |
85
+ {% for m, mt in schemaview.get_mappings(element.name).items() -%}
86
+ {% if mt|length > 0 -%}
87
+ | {{ m }} | {{ mt|join(', ') }} |
88
+ {% endif -%}
89
+ {% endfor %}
90
+
91
+ {% endif -%}
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from dataclasses import dataclass
3
3
  from enum import Enum
4
- from typing import List, Optional, Union
4
+ from typing import List, Optional, Set, Union
5
5
 
6
6
  import click
7
7
  import pydantic
@@ -163,6 +163,7 @@ class ERDiagramGenerator(Generator):
163
163
  class_names: List[Union[str, ClassDefinitionName]],
164
164
  follow_references=False,
165
165
  max_hops: int = None,
166
+ include_upstream: bool = False,
166
167
  ) -> MERMAID_SERIALIZATION:
167
168
  """
168
169
  Serialize a list of classes as an ER Diagram.
@@ -195,6 +196,15 @@ class ERDiagramGenerator(Generator):
195
196
  if follow_references or sv.is_inlined(slot):
196
197
  if rng not in visited:
197
198
  stack.append((rng, depth + 1))
199
+
200
+ # Now Add upstream classes if needed
201
+ if include_upstream:
202
+ for sn in sv.all_slots():
203
+ slot = sv.schema.slots.get(sn)
204
+ if slot and slot.range in set(class_names):
205
+ for cl in sv.all_classes():
206
+ if slot.name in sv.get_class(cl).slots and cl not in visited:
207
+ self.add_upstream_class(cl, set(class_names), diagram)
198
208
  return self.serialize_diagram(diagram)
199
209
 
200
210
  def serialize_diagram(self, diagram: ERDiagram) -> str:
@@ -210,6 +220,15 @@ class ERDiagramGenerator(Generator):
210
220
  else:
211
221
  return er
212
222
 
223
+ def add_upstream_class(self, class_name: ClassDefinitionName, targets: Set[str], diagram: ERDiagram) -> None:
224
+ sv = self.schemaview
225
+ cls = sv.get_class(class_name)
226
+ entity = Entity(name=camelcase(cls.name))
227
+ diagram.entities.append(entity)
228
+ for slot in sv.class_induced_slots(class_name):
229
+ if slot.range in targets:
230
+ self.add_relationship(entity, slot, diagram)
231
+
213
232
  def add_class(self, class_name: ClassDefinitionName, diagram: ERDiagram) -> None:
214
233
  """
215
234
  Add a class to the ER Diagram.
@@ -291,9 +310,17 @@ class ERDiagramGenerator(Generator):
291
310
  )
292
311
  @click.option("--max-hops", default=None, type=click.INT, help="Maximum number of hops")
293
312
  @click.option("--classes", "-c", multiple=True, help="List of classes to serialize")
313
+ @click.option("--include-upstream", is_flag=True, help="Include upstream classes")
294
314
  @click.version_option(__version__, "-V", "--version")
295
315
  @click.command()
296
- def cli(yamlfile, classes: List[str], max_hops: Optional[int], follow_references: bool, **args):
316
+ def cli(
317
+ yamlfile,
318
+ classes: List[str],
319
+ max_hops: Optional[int],
320
+ follow_references: bool,
321
+ include_upstream: bool = False,
322
+ **args,
323
+ ):
297
324
  """Generate a mermaid ER diagram from a schema.
298
325
 
299
326
  By default, all entities traversable from the tree_root are included. If no tree_root is
@@ -306,7 +333,14 @@ def cli(yamlfile, classes: List[str], max_hops: Optional[int], follow_references
306
333
  **args,
307
334
  )
308
335
  if classes:
309
- print(gen.serialize_classes(classes, follow_references=follow_references, max_hops=max_hops))
336
+ print(
337
+ gen.serialize_classes(
338
+ classes,
339
+ follow_references=follow_references,
340
+ max_hops=max_hops,
341
+ include_upstream=include_upstream,
342
+ )
343
+ )
310
344
  else:
311
345
  print(gen.serialize())
312
346
 
@@ -5,12 +5,7 @@ from typing import List, Optional
5
5
 
6
6
  import click
7
7
  from jinja2 import Template
8
- from linkml_runtime.linkml_model.meta import (
9
- ClassDefinition,
10
- ClassDefinitionName,
11
- Element,
12
- SlotDefinition,
13
- )
8
+ from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionName, Element, SlotDefinition
14
9
  from linkml_runtime.utils.formatutils import camelcase, underscore
15
10
 
16
11
  from linkml._version import __version__
@@ -12,11 +12,7 @@ from typing import Callable, List, Optional, Set, cast
12
12
 
13
13
  import click
14
14
  import requests
15
- from linkml_runtime.linkml_model.meta import (
16
- ClassDefinition,
17
- ClassDefinitionName,
18
- SlotDefinition,
19
- )
15
+ from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionName, SlotDefinition
20
16
  from linkml_runtime.utils.formatutils import camelcase, underscore
21
17
 
22
18
  from linkml import REQUESTS_TIMEOUT
@@ -1,18 +1,7 @@
1
1
  import sys
2
2
  from abc import ABC, abstractmethod
3
3
  from enum import Enum
4
- from typing import (
5
- Any,
6
- ClassVar,
7
- Generic,
8
- Iterable,
9
- List,
10
- Optional,
11
- Type,
12
- TypeVar,
13
- Union,
14
- get_args,
15
- )
4
+ from typing import Any, ClassVar, Generic, Iterable, List, Optional, Type, TypeVar, Union, get_args
16
5
 
17
6
  from linkml_runtime.linkml_model import Element
18
7
  from linkml_runtime.linkml_model.meta import ArrayExpression, DimensionExpression
@@ -16,9 +16,7 @@ except ImportError:
16
16
 
17
17
 
18
18
  def _default_mode() -> "Mode":
19
- return Mode(
20
- target_versions={TargetVersion.PY311},
21
- )
19
+ return Mode(target_versions={TargetVersion.PY311}, line_length=120)
22
20
 
23
21
 
24
22
  def format_black(code: str, mode: Optional["Mode"] = None) -> str:
@@ -0,0 +1,46 @@
1
+ """
2
+ Classes to inject in generated pydantic models
3
+ """
4
+
5
+ from pydantic.version import VERSION
6
+
7
+ PYDANTIC_VERSION = int(VERSION[0])
8
+
9
+
10
+ LinkMLMeta_v1 = """
11
+ class LinkMLMeta(BaseModel):
12
+ __root__: Dict[str, Any] = {}
13
+
14
+ def __getattr__(self, key:str):
15
+ return getattr(self.__root__, key)
16
+
17
+ def __getitem__(self, key:str):
18
+ return self.__root__[key]
19
+
20
+ def __setitem__(self, key:str, value):
21
+ self.__root__[key] = value
22
+
23
+ class Config:
24
+ allow_mutation = False
25
+ """
26
+
27
+ LinkMLMeta_v2 = """
28
+ class LinkMLMeta(RootModel):
29
+ root: Dict[str, Any] = {}
30
+ model_config = ConfigDict(frozen=True)
31
+
32
+ def __getattr__(self, key:str):
33
+ return getattr(self.root, key)
34
+
35
+ def __getitem__(self, key:str):
36
+ return self.root[key]
37
+
38
+ def __setitem__(self, key:str, value):
39
+ self.root[key] = value
40
+
41
+ """
42
+
43
+ # if PYDANTIC_VERSION >= 2:
44
+ # LinkMLMeta = eval(LinkMLMeta_v2)
45
+ # else:
46
+ # LinkMLMeta = eval(LinkMLMeta_v1)
@@ -3,19 +3,12 @@ import logging
3
3
  import os
4
4
  import textwrap
5
5
  from collections import defaultdict
6
- from copy import deepcopy
6
+ from copy import copy, deepcopy
7
7
  from dataclasses import dataclass, field
8
+ from enum import Enum
8
9
  from pathlib import Path
9
10
  from types import ModuleType
10
- from typing import (
11
- Dict,
12
- List,
13
- Literal,
14
- Optional,
15
- Set,
16
- Type,
17
- Union,
18
- )
11
+ from typing import Dict, List, Literal, Optional, Set, Type, TypeVar, Union, overload
19
12
 
20
13
  import click
21
14
  from jinja2 import ChoiceLoader, Environment, FileSystemLoader
@@ -27,16 +20,14 @@ from linkml_runtime.linkml_model.meta import (
27
20
  TypeDefinition,
28
21
  )
29
22
  from linkml_runtime.utils.compile_python import compile_python
30
- from linkml_runtime.utils.formatutils import camelcase, underscore
23
+ from linkml_runtime.utils.formatutils import camelcase, remove_empty_items, underscore
31
24
  from linkml_runtime.utils.schemaview import SchemaView
32
25
  from pydantic.version import VERSION as PYDANTIC_VERSION
33
26
 
34
27
  from linkml._version import __version__
35
- from linkml.generators.common.type_designators import (
36
- get_accepted_type_designator_values,
37
- get_type_designator_value,
38
- )
28
+ from linkml.generators.common.type_designators import get_accepted_type_designator_values, get_type_designator_value
39
29
  from linkml.generators.oocodegen import OOCodeGenerator
30
+ from linkml.generators.pydanticgen import includes
40
31
  from linkml.generators.pydanticgen.array import ArrayRangeGenerator, ArrayRepresentation
41
32
  from linkml.generators.pydanticgen.build import SlotResult
42
33
  from linkml.generators.pydanticgen.template import (
@@ -85,6 +76,7 @@ DEFAULT_IMPORTS = (
85
76
  module="typing",
86
77
  objects=[
87
78
  ObjectImport(name="Any"),
79
+ ObjectImport(name="ClassVar"),
88
80
  ObjectImport(name="List"),
89
81
  ObjectImport(name="Literal"),
90
82
  ObjectImport(name="Dict"),
@@ -100,6 +92,7 @@ DEFAULT_IMPORTS = (
100
92
  ObjectImport(name="BaseModel"),
101
93
  ObjectImport(name="ConfigDict"),
102
94
  ObjectImport(name="Field"),
95
+ ObjectImport(name="RootModel"),
103
96
  ObjectImport(name="field_validator"),
104
97
  ],
105
98
  alternative=Import(
@@ -109,6 +102,33 @@ DEFAULT_IMPORTS = (
109
102
  )
110
103
  )
111
104
 
105
+ DEFAULT_INJECTS = {1: [includes.LinkMLMeta_v1], 2: [includes.LinkMLMeta_v2]}
106
+
107
+
108
+ class MetadataMode(str, Enum):
109
+ FULL = "full"
110
+ """
111
+ all metadata from the source schema will be included, even if it is represented by the template classes,
112
+ and even if it is represented by some child class (eg. "classes" will be included with schema metadata
113
+ """
114
+ EXCEPT_CHILDREN = "except_children"
115
+ """
116
+ all metadata from the source schema will be included, even if it is represented by the template classes,
117
+ except if it is represented by some child template class (eg. "classes" will be excluded from schema metadata)
118
+ """
119
+ AUTO = "auto"
120
+ """
121
+ Only the metadata that isn't represented by the template classes or excluded with ``meta_exclude`` will be included
122
+ """
123
+ NONE = None
124
+ """
125
+ No metadata will be included.
126
+ """
127
+
128
+
129
+ DefinitionType = TypeVar("DefinitionType", bound=Union[SchemaDefinition, ClassDefinition, SlotDefinition])
130
+ TemplateType = TypeVar("TemplateType", bound=Union[PydanticModule, PydanticClass, PydanticAttribute])
131
+
112
132
 
113
133
  @dataclass
114
134
  class PydanticGenerator(OOCodeGenerator):
@@ -212,6 +232,12 @@ class PydanticGenerator(OOCodeGenerator):
212
232
  from typing_extensions import Literal
213
233
 
214
234
  """
235
+ metadata_mode: Union[MetadataMode, str, None] = MetadataMode.AUTO
236
+ """
237
+ How to include schema metadata in generated pydantic models.
238
+
239
+ See :class:`.MetadataMode` for mode documentation
240
+ """
215
241
 
216
242
  # ObjectVars (identical to pythongen)
217
243
  gen_classvars: bool = True
@@ -530,6 +556,56 @@ class PydanticGenerator(OOCodeGenerator):
530
556
 
531
557
  return array_reps
532
558
 
559
+ @overload
560
+ def include_metadata(self, model: PydanticModule, source: SchemaDefinition) -> PydanticModule: ...
561
+
562
+ @overload
563
+ def include_metadata(self, model: PydanticClass, source: ClassDefinition) -> PydanticClass: ...
564
+
565
+ @overload
566
+ def include_metadata(self, model: PydanticAttribute, source: SlotDefinition) -> PydanticAttribute: ...
567
+
568
+ def include_metadata(self, model: TemplateType, source: DefinitionType) -> TemplateType:
569
+ """
570
+ Include metadata from the source schema that is otherwise not represented in the pydantic template models.
571
+
572
+ Metadata inclusion mode is dependent on :attr:`.metadata_mode` - see:
573
+
574
+ - :class:`.MetadataMode`
575
+ - :meth:`.TemplateModel.exclude_from_meta`
576
+
577
+ """
578
+ if self.metadata_mode is None or self.metadata_mode == MetadataMode.NONE:
579
+ return model
580
+ elif self.metadata_mode in (MetadataMode.AUTO, MetadataMode.AUTO.value):
581
+ meta = {k: v for k, v in remove_empty_items(source).items() if k not in model.exclude_from_meta()}
582
+ elif self.metadata_mode in (MetadataMode.EXCEPT_CHILDREN, MetadataMode.EXCEPT_CHILDREN.value):
583
+ meta = {}
584
+ for k, v in remove_empty_items(source).items():
585
+ if not hasattr(model, k):
586
+ meta[k] = v
587
+ elif isinstance(getattr(model, k), list) and not any(
588
+ [isinstance(item, TemplateModel) for item in getattr(model, k)]
589
+ ):
590
+ meta[k] = v
591
+ elif isinstance(getattr(model, k), dict) and not any(
592
+ [isinstance(item, TemplateModel) for item in getattr(model, k).values()]
593
+ ):
594
+ meta[k] = v
595
+ elif not isinstance(getattr(model, k), TemplateModel):
596
+ meta[k] = v
597
+
598
+ elif self.metadata_mode in (MetadataMode.FULL, MetadataMode.FULL.value):
599
+ meta = remove_empty_items(source)
600
+ else:
601
+ raise ValueError(
602
+ f"Unknown metadata mode '{self.metadata_mode}', needs to be one of "
603
+ f"{[mode.value for mode in MetadataMode]}"
604
+ )
605
+
606
+ model.meta = meta
607
+ return model
608
+
533
609
  def render(self) -> PydanticModule:
534
610
  sv: SchemaView
535
611
  sv = self.schemaview
@@ -540,7 +616,7 @@ class PydanticGenerator(OOCodeGenerator):
540
616
  description=schema.description.replace('"', '\\"') if schema.description else None,
541
617
  )
542
618
  enums = self.generate_enums(sv.all_enums())
543
- injected_classes = []
619
+ injected_classes = copy(DEFAULT_INJECTS[self.pydantic_version])
544
620
  if self.injected_classes is not None:
545
621
  injected_classes += self.injected_classes
546
622
 
@@ -665,15 +741,22 @@ class PydanticGenerator(OOCodeGenerator):
665
741
  predef_slot = str(predef_slot)
666
742
  new_fields["predefined"] = predef_slot
667
743
  new_fields["name"] = attr_name
744
+
668
745
  attrs[attr_name] = PydanticAttribute(**new_fields, pydantic_ver=self.pydantic_version)
746
+ attrs[attr_name] = self.include_metadata(attrs[attr_name], src_attr)
669
747
 
670
748
  new_class = PydanticClass(
671
749
  name=k, attributes=attrs, description=c.description, pydantic_ver=self.pydantic_version
672
750
  )
751
+ new_class = self.include_metadata(new_class, c)
673
752
  if k in bases:
674
753
  new_class.bases = bases[k]
675
754
  classes[k] = new_class
676
755
 
756
+ schema_meta = {
757
+ k: v for k, v in remove_empty_items(schema).items() if k not in PydanticModule.exclude_from_meta()
758
+ }
759
+
677
760
  module = PydanticModule(
678
761
  pydantic_ver=self.pydantic_version,
679
762
  metamodel_version=self.schema.metamodel_version,
@@ -683,7 +766,9 @@ class PydanticGenerator(OOCodeGenerator):
683
766
  injected_classes=injected_classes,
684
767
  enums=enums,
685
768
  classes=classes,
769
+ meta=schema_meta,
686
770
  )
771
+ module = self.include_metadata(module, pyschema)
687
772
  return module
688
773
 
689
774
  def serialize(self) -> str:
@@ -739,6 +824,12 @@ Available templates to override:
739
824
  default="forbid",
740
825
  help="How to handle extra fields in BaseModel.",
741
826
  )
827
+ @click.option(
828
+ "--black",
829
+ is_flag=True,
830
+ default=False,
831
+ help="Format generated models with black (must be present in the environment)",
832
+ )
742
833
  @click.version_option(__version__, "-V", "--version")
743
834
  @click.command()
744
835
  def cli(
@@ -752,6 +843,7 @@ def cli(
752
843
  array_representations=list("list"),
753
844
  pydantic_version=int(PYDANTIC_VERSION[0]),
754
845
  extra_fields: Literal["allow", "forbid", "ignore"] = "forbid",
846
+ black: bool = False,
755
847
  **args,
756
848
  ):
757
849
  """Generate pydantic classes to represent a LinkML model"""
@@ -777,6 +869,7 @@ def cli(
777
869
  gen_classvars=classvars,
778
870
  gen_slots=slots,
779
871
  template_dir=template_dir,
872
+ black=black,
780
873
  **args,
781
874
  )
782
875
  print(gen.serialize())
@@ -60,6 +60,7 @@ class TemplateModel(BaseModel):
60
60
  )
61
61
 
62
62
  pydantic_ver: int = int(PYDANTIC_VERSION[0])
63
+ meta_exclude: ClassVar[List[str]] = None
63
64
 
64
65
  def render(self, environment: Optional[Environment] = None, black: bool = False) -> str:
65
66
  """
@@ -132,6 +133,16 @@ class TemplateModel(BaseModel):
132
133
  return self.json(**kwargs)
133
134
  return self.dict(**kwargs)
134
135
 
136
+ @classmethod
137
+ def exclude_from_meta(cls: "TemplateModel") -> List[str]:
138
+ """
139
+ Attributes in the source definition to exclude from linkml_meta
140
+ """
141
+ ret = [*cls.model_fields.keys()]
142
+ if cls.meta_exclude is not None:
143
+ ret = ret + cls.meta_exclude
144
+ return ret
145
+
135
146
 
136
147
  def _render(
137
148
  item: Union[TemplateModel, Any, List[Union[Any, TemplateModel]], Dict[str, Union[Any, TemplateModel]]],
@@ -213,6 +224,7 @@ class PydanticAttribute(TemplateModel):
213
224
  """
214
225
 
215
226
  template: ClassVar[str] = "attribute.py.jinja"
227
+ meta_exclude: ClassVar[List[str]] = ["from_schema", "owner", "range", "multivalued", "inlined", "inlined_as_list"]
216
228
 
217
229
  name: str
218
230
  required: bool = False
@@ -237,6 +249,10 @@ class PydanticAttribute(TemplateModel):
237
249
  minimum_value: Optional[Union[int, float]] = None
238
250
  maximum_value: Optional[Union[int, float]] = None
239
251
  pattern: Optional[str] = None
252
+ meta: Optional[Dict[str, Any]] = None
253
+ """
254
+ Metadata for the slot to be included in a Field annotation
255
+ """
240
256
 
241
257
  if int(PYDANTIC_VERSION[0]) >= 2:
242
258
 
@@ -283,11 +299,16 @@ class PydanticClass(TemplateModel):
283
299
  """
284
300
 
285
301
  template: ClassVar[str] = "class.py.jinja"
302
+ meta_exclude: ClassVar[List[str]] = ["slots", "is_a"]
286
303
 
287
304
  name: str
288
305
  bases: Union[List[str], str] = PydanticBaseModel.default_name
289
306
  description: Optional[str] = None
290
307
  attributes: Optional[Dict[str, PydanticAttribute]] = None
308
+ meta: Optional[Dict[str, Any]] = None
309
+ """
310
+ Metadata for the class to be included in a linkml_meta class attribute
311
+ """
291
312
 
292
313
  def _validators(self) -> Optional[Dict[str, PydanticValidator]]:
293
314
  if self.attributes is None:
@@ -548,6 +569,7 @@ class PydanticModule(TemplateModel):
548
569
  """
549
570
 
550
571
  template: ClassVar[str] = "module.py.jinja"
572
+ meta_exclude: ClassVar[str] = ["slots"]
551
573
 
552
574
  metamodel_version: Optional[str] = None
553
575
  version: Optional[str] = None
@@ -556,6 +578,10 @@ class PydanticModule(TemplateModel):
556
578
  imports: List[Union[Import, ConditionalImport]] = Field(default_factory=list)
557
579
  enums: Dict[str, PydanticEnum] = Field(default_factory=dict)
558
580
  classes: Dict[str, PydanticClass] = Field(default_factory=dict)
581
+ meta: Optional[Dict[str, Any]] = None
582
+ """
583
+ Metadata for the schema to be included in a linkml_meta module-level instance of LinkMLMeta
584
+ """
559
585
 
560
586
  if int(PYDANTIC_VERSION[0]) >= 2:
561
587
 
@@ -7,4 +7,10 @@
7
7
  {%- if minimum_value != None %}, ge={{minimum_value}}{% endif -%}
8
8
  {%- if maximum_value != None %}, le={{maximum_value}}{% endif -%}
9
9
  {%- endif -%}
10
- )
10
+ {%- if meta != None -%}
11
+ {%- if pydantic_ver == 1 -%}
12
+ , linkml_meta = {{ meta | pprint | indent(width=8) }}
13
+ {% else -%}
14
+ , json_schema_extra = { "linkml_meta": {{ meta | pprint | indent(width=8) }} }
15
+ {%- endif -%}
16
+ {%- endif -%})
@@ -4,6 +4,10 @@ class {{ name }}({% if bases is string %}{{ bases }}{% else %}{{ bases | join(',
4
4
  {{ description | indent(width=4) }}
5
5
  """
6
6
  {% endif -%}
7
+ {% if meta != None %}
8
+ linkml_meta: ClassVar[LinkMLMeta] = LinkMLMeta({% if pydantic_ver == 1 %}__root__={% endif %}{{ meta | pprint | indent(width=8) }})
9
+
10
+ {% endif %}
7
11
  {% if attributes or validators %}
8
12
  {% if attributes %}
9
13
  {% for attr in attributes.values() %}
@@ -7,18 +7,25 @@ version = "{{version if version else None}}"
7
7
 
8
8
 
9
9
  {{ base_model }}
10
- {% if enums %}
11
- {% for e in enums.values() %}
12
10
 
13
- {{ e }}
14
- {% endfor %}
15
- {% endif %}
16
11
  {% if injected_classes %}
17
12
  {% for c in injected_classes%}
18
13
 
19
14
  {{ c }}
20
15
  {% endfor %}
21
16
  {% endif %}
17
+ {% if meta != None %}
18
+ linkml_meta = LinkMLMeta({% if pydantic_ver == 1 %}__root__={% endif %}{{ meta | pprint | indent(width=4) }} )
19
+ {% else %}
20
+ linkml_meta = None
21
+ {% endif %}
22
+ {% if enums %}
23
+ {% for e in enums.values() %}
24
+
25
+ {{ e }}
26
+ {% endfor %}
27
+ {% endif %}
28
+
22
29
  {% for c in classes.values() %}
23
30
 
24
31
  {{ c }}
@@ -23,14 +23,7 @@ from linkml_runtime.linkml_model.meta import (
23
23
  TypeDefinition,
24
24
  )
25
25
  from linkml_runtime.utils.compile_python import compile_python
26
- from linkml_runtime.utils.formatutils import (
27
- be,
28
- camelcase,
29
- sfx,
30
- split_col,
31
- underscore,
32
- wrapped_annotation,
33
- )
26
+ from linkml_runtime.utils.formatutils import be, camelcase, sfx, split_col, underscore, wrapped_annotation
34
27
  from linkml_runtime.utils.metamodelcore import builtinnames
35
28
  from rdflib import URIRef
36
29
 
@@ -1,15 +1,17 @@
1
1
  import logging
2
2
  import os
3
3
  from dataclasses import dataclass
4
- from typing import Callable
4
+ from typing import Callable, List
5
5
 
6
6
  import click
7
+ from jsonasobj2 import JsonObj, as_dict
7
8
  from linkml_runtime.linkml_model.meta import ElementName
8
9
  from linkml_runtime.utils.formatutils import underscore
9
10
  from linkml_runtime.utils.schemaview import SchemaView
11
+ from linkml_runtime.utils.yamlutils import TypedNode, extended_float, extended_int, extended_str
10
12
  from rdflib import BNode, Graph, Literal, URIRef
11
13
  from rdflib.collection import Collection
12
- from rdflib.namespace import RDF, SH
14
+ from rdflib.namespace import RDF, SH, XSD
13
15
 
14
16
  from linkml._version import __version__
15
17
  from linkml.generators.shacl.ifabsent_processor import IfAbsentProcessor
@@ -24,6 +26,8 @@ class ShaclGenerator(Generator):
24
26
  """True means add 'sh:closed=true' to all shapes, except of mixin shapes and shapes, that have parents"""
25
27
  suffix: str = None
26
28
  """parameterized suffix to be appended. No suffix per default."""
29
+ include_annotations: bool = False
30
+ """True means include all class / slot / type annotations in generated Node or Property shapes"""
27
31
  generatorname = os.path.basename(__file__)
28
32
  generatorversion = "0.0.1"
29
33
  valid_formats = ["ttl"]
@@ -83,6 +87,8 @@ class ShaclGenerator(Generator):
83
87
  list_node = BNode()
84
88
  Collection(g, list_node, [RDF.type])
85
89
  shape_pv(SH.ignoredProperties, list_node)
90
+ if c.annotations and self.include_annotations:
91
+ self._add_annotations(shape_pv, c)
86
92
  order = 0
87
93
  for s in sv.class_induced_slots(c.name):
88
94
  # fixed in linkml-runtime 1.1.3
@@ -116,6 +122,12 @@ class ShaclGenerator(Generator):
116
122
 
117
123
  all_classes = sv.all_classes()
118
124
  if s.any_of:
125
+ # It is not allowed to use any of and equals_string or equals_string_in in one
126
+ # slot definition, as both are mapped to sh:in in SHACL
127
+ if s.equals_string or s.equals_string_in:
128
+ error = "'equals_string'/'equals_string_in' and 'any_of' are mutually exclusive"
129
+ raise ValueError(f'{TypedNode.yaml_loc(s, suffix="")} {error}')
130
+
119
131
  or_node = BNode()
120
132
  prop_pv(SH["or"], or_node)
121
133
  range_list = []
@@ -158,10 +170,17 @@ class ShaclGenerator(Generator):
158
170
  add_simple_data_type(st_node_pv, r)
159
171
  range_list.append(st_node)
160
172
  Collection(g, or_node, range_list)
161
-
162
173
  else:
163
174
  prop_pv_literal(SH.hasValue, s.equals_number)
164
175
  r = s.range
176
+ if s.equals_string or s.equals_string_in:
177
+ # Check if range is "string" as this is mandatory for "equals_string" and "equals_string_in"
178
+ if r != "string":
179
+ raise ValueError(
180
+ f"slot: \"{slot_uri}\" - 'equals_string' and 'equals_string_in'"
181
+ f" require range 'string' and not '{r}'"
182
+ )
183
+
165
184
  if r in all_classes:
166
185
  self._add_class(prop_pv, r)
167
186
  if sv.get_identifier_slot(r) is not None:
@@ -176,6 +195,14 @@ class ShaclGenerator(Generator):
176
195
  add_simple_data_type(prop_pv, r)
177
196
  if s.pattern:
178
197
  prop_pv(SH.pattern, Literal(s.pattern))
198
+ if s.annotations and self.include_annotations:
199
+ self._add_annotations(prop_pv, s)
200
+ if s.equals_string:
201
+ # Map equal_string and equal_string_in to sh:in
202
+ self._and_equals_string(g, prop_pv, [s.equals_string])
203
+ if s.equals_string_in:
204
+ # Map equal_string and equal_string_in to sh:in
205
+ self._and_equals_string(g, prop_pv, s.equals_string_in)
179
206
 
180
207
  ifabsent_processor.process_slot(prop_pv, s, class_uri)
181
208
 
@@ -206,9 +233,68 @@ class ShaclGenerator(Generator):
206
233
  rt = sv.get_type(r)
207
234
  if rt.uri:
208
235
  func(SH.datatype, URIRef(sv.get_uri(rt, expand=True)))
236
+ if rt.pattern:
237
+ func(SH.pattern, Literal(rt.pattern))
238
+ if rt.annotations and self.include_annotations:
239
+ self._add_annotations(func, rt)
209
240
  else:
210
241
  logging.error(f"No URI for type {rt.name}")
211
242
 
243
+ def _and_equals_string(self, g: Graph, func: Callable, values: List) -> None:
244
+ pv_node = BNode()
245
+ Collection(
246
+ g,
247
+ pv_node,
248
+ [Literal(v) for v in values],
249
+ )
250
+ func(SH["in"], pv_node)
251
+
252
+ def _add_annotations(self, func: Callable, item) -> None:
253
+ # TODO: migrate some of this logic to SchemaView
254
+ sv = self.schemaview
255
+ annotations = item.annotations
256
+ # item could be a class, slot or type
257
+ # annotation type could be dict (on types) or JsonObj (on slots)
258
+ if type(annotations) == JsonObj:
259
+ annotations = as_dict(annotations)
260
+ for a in annotations.values():
261
+ # If ':' is in the tag, treat it as a CURIE, otherwise string Literal
262
+ if ":" in a["tag"]:
263
+ N_predicate = URIRef(sv.expand_curie(a["tag"]))
264
+ else:
265
+ N_predicate = Literal(a["tag"], datatype=XSD.string)
266
+ # If the value is a string and ':' is in the value, treat it as a CURIE,
267
+ # otherwise treat as Literal with derived XSD datatype
268
+ if type(a["value"]) == extended_str and ":" in a["value"]:
269
+ N_object = URIRef(sv.expand_curie(a["value"]))
270
+ else:
271
+ N_object = Literal(a["value"], datatype=self._getXSDtype(a["value"]))
272
+
273
+ func(N_predicate, N_object)
274
+
275
+ def _getXSDtype(self, value):
276
+ value_type = type(value)
277
+ if value_type == bool:
278
+ return XSD.boolean
279
+ elif value_type == extended_str:
280
+ return XSD.string
281
+ elif value_type == extended_int:
282
+ return XSD.integer
283
+ elif value_type == extended_float:
284
+ # TODO: distinguish between xsd:decimal and xsd:double?
285
+ return XSD.decimal
286
+ else:
287
+ return None
288
+
289
+ def _and_equals_string(self, g: Graph, func: Callable, values: List) -> None:
290
+ pv_node = BNode()
291
+ Collection(
292
+ g,
293
+ pv_node,
294
+ [Literal(v) for v in values],
295
+ )
296
+ func(SH["in"], pv_node)
297
+
212
298
 
213
299
  def add_simple_data_type(func: Callable, r: ElementName) -> None:
214
300
  for datatype in list(ShaclDataType):
@@ -231,6 +317,12 @@ def add_simple_data_type(func: Callable, r: ElementName) -> None:
231
317
  show_default=True,
232
318
  help="Use --suffix to append given string to SHACL class name (e. g. --suffix Shape: Person becomes PersonShape).",
233
319
  )
320
+ @click.option(
321
+ "--include-annotations/--exclude-annotations",
322
+ default=False,
323
+ show_default=True,
324
+ help="Use --include-annotations to include annotations of slots, types, and classes in the generated SHACL shapes.",
325
+ )
234
326
  @click.version_option(__version__, "-V", "--version")
235
327
  def cli(yamlfile, **args):
236
328
  """Generate SHACL turtle from a LinkML model"""
@@ -7,12 +7,7 @@ from typing import List, Optional, Union
7
7
 
8
8
  import click
9
9
  from jinja2 import Template
10
- from linkml_runtime.linkml_model import (
11
- Annotation,
12
- ClassDefinition,
13
- ClassDefinitionName,
14
- SchemaDefinition,
15
- )
10
+ from linkml_runtime.linkml_model import Annotation, ClassDefinition, ClassDefinitionName, SchemaDefinition
16
11
  from linkml_runtime.utils.compile_python import compile_python
17
12
  from linkml_runtime.utils.formatutils import camelcase, underscore
18
13
  from linkml_runtime.utils.schemaview import SchemaView
@@ -21,10 +16,7 @@ from sqlalchemy import Enum
21
16
  from linkml._version import __version__
22
17
  from linkml.generators.pydanticgen import PydanticGenerator
23
18
  from linkml.generators.pythongen import PythonGenerator
24
- from linkml.generators.sqlalchemy import (
25
- sqlalchemy_declarative_template_str,
26
- sqlalchemy_imperative_template_str,
27
- )
19
+ from linkml.generators.sqlalchemy import sqlalchemy_declarative_template_str, sqlalchemy_imperative_template_str
28
20
  from linkml.generators.sqltablegen import SQLTableGenerator
29
21
  from linkml.transformers.relmodel_transformer import ForeignKeyPolicy, RelationalModelTransformer
30
22
  from linkml.utils.generator import Generator, shared_arguments
linkml/linter/rules.py CHANGED
@@ -3,12 +3,7 @@ from abc import ABC, abstractmethod
3
3
  from functools import lru_cache
4
4
  from typing import Callable, Iterable, List
5
5
 
6
- from linkml_runtime.linkml_model import (
7
- ClassDefinition,
8
- ClassDefinitionName,
9
- Element,
10
- SlotDefinition,
11
- )
6
+ from linkml_runtime.linkml_model import ClassDefinition, ClassDefinitionName, Element, SlotDefinition
12
7
  from linkml_runtime.utils.schemaview import SchemaView
13
8
  from prefixmaps.io.parser import load_multi_context
14
9
 
@@ -32,6 +32,7 @@ from linkml.transformers.model_transformer import ModelTransformer
32
32
  from linkml.utils import logictools
33
33
 
34
34
  HERITABLE_METASLOT = [
35
+ # "multivalued",
35
36
  "range",
36
37
  "range_expression",
37
38
  "minimum_value",
@@ -102,7 +103,7 @@ class LogicalModelTransformer(ModelTransformer):
102
103
  >>> _ = sb.add_class("Person", slots={"age": {"range": "integer"}}, is_a="Thing")
103
104
  >>> _ = sb.add_class("Organization", slots={"category": {"range": "OrganizationType"}}, is_a="Thing")
104
105
  >>> _ = sb.add_enum("OrganizationType", ["commercial", "non-profit"])
105
- >>> from linkml.transformers import LogicalModelTransformer
106
+ >>> from linkml.transformers.logical_model_transformer import LogicalModelTransformer
106
107
  >>> tr = LogicalModelTransformer()
107
108
  >>> tr.set_schema(sb.schema)
108
109
  >>> flat_schema = tr.transform()
@@ -153,8 +154,8 @@ class LogicalModelTransformer(ModelTransformer):
153
154
  attributes:
154
155
  entities:
155
156
  name: entities
156
- multivalued: true
157
157
  range: Thing
158
+ multivalued: true
158
159
 
159
160
  ...
160
161
 
@@ -443,6 +444,9 @@ class LogicalModelTransformer(ModelTransformer):
443
444
  logger.debug(f"Simplified member of: {x}")
444
445
  simplified_att = self._from_logical_expression(x)
445
446
  for k, v in simplified_att.__dict__.items():
447
+ if v is None or v is False:
448
+ if k in ["multivalued"]:
449
+ continue
446
450
  setattr(att, k, v)
447
451
 
448
452
  def _simplify_member_ofs(self, expr: logictools.Expression):
@@ -235,6 +235,9 @@ class SchemaLoader:
235
235
  ):
236
236
  self.raise_value_error(f"slot: {slot.name} - unrecognized range ({slot.range})", slot.range)
237
237
 
238
+ # check constraints for usage of equals_string and equals_string_in
239
+ self._check_equals_string(slot)
240
+
238
241
  # apply to --> mixins
239
242
  for cls in self.schema.classes.values():
240
243
  for apply_to_cls in cls.apply_to:
@@ -372,6 +375,9 @@ class SchemaLoader:
372
375
  ):
373
376
  self.raise_value_error(f"slot: {slot.name} - unrecognized range ({slot.range})", slot.range)
374
377
 
378
+ # check constraints for usage of equals_string and equals_string_in
379
+ self._check_equals_string(slot)
380
+
375
381
  # Massage classes, propagating class slots entries domain back to the target slots
376
382
  for cls in self.schema.classes.values():
377
383
  if not isinstance(cls, ClassDefinition):
@@ -964,3 +970,24 @@ class SchemaLoader:
964
970
  return rval
965
971
  else:
966
972
  return None
973
+
974
+ def _check_equals_string(self, slot: SlotDefinition):
975
+ if slot.equals_string or slot.equals_string_in:
976
+ # Range "string" mandatory for "equals_string" and "equals_string_in"
977
+ range = slot.range
978
+ if not range:
979
+ # range is not defined --> check default range
980
+ range = self.schema.default_range
981
+ if range != "string":
982
+ self.raise_value_error(
983
+ f"slot: {slot.name} - 'equals_string' and 'equals_string_in' requires range "
984
+ f"'string' and not range '{range}'",
985
+ slot.range,
986
+ )
987
+ if slot.any_of:
988
+ # It is not allowed to use any of and equals_string or equals_string_in in one slot definition,
989
+ # as both are mapped to sh:in in SHACL
990
+ self.raise_value_error(
991
+ f"slot: {slot.name} - 'equals_string'/'equals_string_in' and 'any_of' are mutually exclusive",
992
+ slot.name,
993
+ )
@@ -21,15 +21,7 @@ from linkml_runtime.utils.metamodelcore import empty_dict
21
21
  from linkml_runtime.utils.yamlutils import TypedNode
22
22
  from rdflib import URIRef
23
23
 
24
- from linkml.utils.typereferences import (
25
- ClassType,
26
- EnumType,
27
- References,
28
- RefType,
29
- SlotType,
30
- SubsetType,
31
- TypeType,
32
- )
24
+ from linkml.utils.typereferences import ClassType, EnumType, References, RefType, SlotType, SubsetType, TypeType
33
25
 
34
26
 
35
27
  def empty_references() -> field:
@@ -11,9 +11,7 @@ from typing import Any, Optional, Union
11
11
  from linkml_runtime.linkml_model import SchemaDefinition
12
12
  from linkml_runtime.loaders import yaml_loader
13
13
 
14
- from linkml.validator.loaders import (
15
- default_loader_for_file,
16
- )
14
+ from linkml.validator.loaders import default_loader_for_file
17
15
  from linkml.validator.plugins import JsonschemaValidationPlugin
18
16
  from linkml.validator.report import ValidationReport
19
17
  from linkml.validator.validator import Validator
@@ -4,9 +4,7 @@ on data instances. Instances of these classes should be provided when constructi
4
4
  :class:`linkml.validator.Validator` instance.
5
5
  """
6
6
 
7
- from linkml.validator.plugins.jsonschema_validation_plugin import (
8
- JsonschemaValidationPlugin,
9
- )
7
+ from linkml.validator.plugins.jsonschema_validation_plugin import JsonschemaValidationPlugin
10
8
  from linkml.validator.plugins.pydantic_validation_plugin import PydanticValidationPlugin
11
9
  from linkml.validator.plugins.recommended_slots_plugin import RecommendedSlotsPlugin
12
10
  from linkml.validator.plugins.validation_plugin import ValidationPlugin
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkml
3
- Version: 1.7.10
3
+ Version: 1.8.0
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
@@ -36,7 +36,7 @@ Requires-Dist: jinja2 (>=3.1.0)
36
36
  Requires-Dist: jsonasobj2 (>=1.0.3,<2.0.0)
37
37
  Requires-Dist: jsonschema[format] (>=4.0.0)
38
38
  Requires-Dist: linkml-dataops
39
- Requires-Dist: linkml-runtime (>=1.7.4)
39
+ Requires-Dist: linkml-runtime (==1.8.0)
40
40
  Requires-Dist: openpyxl
41
41
  Requires-Dist: parse
42
42
  Requires-Dist: prefixcommons (>=0.1.7)
@@ -6,9 +6,9 @@ linkml/generators/__init__.py,sha256=dQ2EUKy_MctEVEzbC3XzEJL5YmYwjYfsa44mG2zKn7g
6
6
  linkml/generators/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  linkml/generators/common/type_designators.py,sha256=lgVcIRJJ-yCvVGeP9U_gQZpm77UmJBQo9Bh3lGJITno,1956
8
8
  linkml/generators/csvgen.py,sha256=R8VQdWXj43LNf5isJElo3MStsiNBSSF4ywIRS1c3_v0,3243
9
- linkml/generators/docgen/class.md.jinja2,sha256=bz5A46HOIPkUVbzPGorg64NNhr66zK0hCCekSfRPErY,3787
9
+ linkml/generators/docgen/class.md.jinja2,sha256=-JmjYHgYOaaBYd5r-Tr5dkk0CLM_lX0kHdocPQtRsjU,3504
10
10
  linkml/generators/docgen/class_diagram.md.jinja2,sha256=gzskx4hOpU_s6BqOXdYZ9DwKxuClnsEgDzPurm30PeY,3469
11
- linkml/generators/docgen/common_metadata.md.jinja2,sha256=zy8Ua3gDtAAq8VA3e3O3ft9W7eJopVZaq5efP8LU_hU,1321
11
+ linkml/generators/docgen/common_metadata.md.jinja2,sha256=gy9J8rghBfKDKimwtHj_XuHY4PJRRYHLXVlBHqWrUzU,1604
12
12
  linkml/generators/docgen/enum.md.jinja2,sha256=mXnUrRkleY2bOTEyAZ5c4pcUnqhs6BNa8a-4LVve-eo,1014
13
13
  linkml/generators/docgen/index.md.jinja2,sha256=wXUYTmayPLFltC0vbGE_Mf6m3GkkWav7FOEjCvEpHp4,1466
14
14
  linkml/generators/docgen/index.tex.jinja2,sha256=Go_EA-_N4JUpbOYbk3OY11mz5yV70VF2l2sMtgIPWw4,501
@@ -18,9 +18,9 @@ linkml/generators/docgen/subset.md.jinja2,sha256=EPln_fjlhlkmwEGEp2iPX-9Xm2vVodP
18
18
  linkml/generators/docgen/type.md.jinja2,sha256=QmCMJZrFwP33eHkggBVtypbyrxTb-XZn9vHOYojVaYk,635
19
19
  linkml/generators/docgen.py,sha256=QECBmOAiVr-DsUYOLmqapESSB_CiNoiHt_3vjiZCrUs,36396
20
20
  linkml/generators/dotgen.py,sha256=kzp1EYtF8bBqOuycJokDmsvHVDVkkW-J-6-MiUhwJH0,5013
21
- linkml/generators/erdiagramgen.py,sha256=xCnxIldDYZ7xnQ-vLaXlH3FH8MH3cxu-E0j8it-lyJE,10153
21
+ linkml/generators/erdiagramgen.py,sha256=7W010ngoHrk-BjhCEmpHyySPImLXIOTEBGO70hOUOH8,11341
22
22
  linkml/generators/excelgen.py,sha256=3ILAeIHeYngNpPf3Ad7CXoHOLQ9KSiYcX5HdwHhQeQE,7696
23
- linkml/generators/golanggen.py,sha256=1seIQiKq-ASZoHTf7xoPd0zUQ4YCPkxoKnUwgAIttPo,5811
23
+ linkml/generators/golanggen.py,sha256=rDiDFyZBZ6_JygCEdpbKrohQCScvBlWi17AcoR6Qi3g,5790
24
24
  linkml/generators/golrgen.py,sha256=OUBYRWicP7G7lrPu1VrxumbVpx3CBJal-o2imyeP05M,3437
25
25
  linkml/generators/graphqlgen.py,sha256=ClJdD6fVjBI8rsIJ3DIuwdQScAJG0gYYKwS8SrFqVZk,2149
26
26
  linkml/generators/javagen/example_template.java.jinja2,sha256=ec4CVTv_0zS7V5Y-1E6H4lRraya10gfX7BEMBlu38X4,444
@@ -35,37 +35,38 @@ linkml/generators/markdowngen.py,sha256=mwydWkrF-WzsTiKwJqqe9NUya5VaTj7ywKqodP85
35
35
  linkml/generators/namespacegen.py,sha256=vVcIyM0zlKd7XRvtdzwTwHjG4Pg49801gy4FUmjJlqQ,6450
36
36
  linkml/generators/oocodegen.py,sha256=r73QI08ajbTZTobc9OIG6BMWZft3zdu76vKVR33pyYg,7774
37
37
  linkml/generators/owlgen.py,sha256=NHIcL1d79WoeqfiZRj6kRk5aTXcQ6JDNXV_VAtH6Vt0,57554
38
- linkml/generators/plantumlgen.py,sha256=8fQG_IQSn_KdRG-vaQPXHpU9rvRWBggymdu-uK_7Oqo,14936
38
+ linkml/generators/plantumlgen.py,sha256=2e4ejw0B72Sl_-mipgpKz743LVMs0kRZc8E0MK7gxFY,14919
39
39
  linkml/generators/prefixmapgen.py,sha256=w8gMCFOI0DmZsNvo9IkbhOqVWqqWYEN6SXnAP3BgFSk,4240
40
40
  linkml/generators/projectgen.py,sha256=OuT_AneoZFNMCn50GllfZafadUHt50u61JcftM2eed4,9750
41
41
  linkml/generators/protogen.py,sha256=i4sEhNdAiFFP12fwfRdype1MX8yU-E5fF7XzkcpBCd0,2512
42
42
  linkml/generators/pydanticgen/__init__.py,sha256=uKGaaQSaeKqinHImXGFE448i-t8Oi0No8suIO76sep8,629
43
- linkml/generators/pydanticgen/array.py,sha256=1QWWgz46yVmWkdNauI6Kjkbx3kexp-l210nOILoHJ18,19506
44
- linkml/generators/pydanticgen/black.py,sha256=c-Hgaao9hd4nPMU9w0Hmg2j4Wc81IcY0zAfppQPr1cM,721
43
+ linkml/generators/pydanticgen/array.py,sha256=EYqAkT2_wE82kZ-niUWAC5U3V8EvjjyfSH7tz5GYKWo,19461
44
+ linkml/generators/pydanticgen/black.py,sha256=BaJ7b-kMUbIN_cKRT3yCaMEbFwxzj1_U7w4fKQnkL44,723
45
45
  linkml/generators/pydanticgen/build.py,sha256=Ia8qy4C16b-KqO_fw4tGQW_Eo4grCVyX7RsuJ3uRTtk,2681
46
- linkml/generators/pydanticgen/pydanticgen.py,sha256=7X56SDTEzWt8irqdWOmYUfiBcAlOlfRUbTK3JhYX_JU,30184
47
- linkml/generators/pydanticgen/template.py,sha256=fAqRofLm7N94xUqXjkStdmugcxGQfiioGkxdIhLByik,19990
48
- linkml/generators/pydanticgen/templates/attribute.py.jinja,sha256=AlH_QFJJkONpzXQRGqnW4ufmjp9s9E7Q9W5r8ykNGeQ,443
46
+ linkml/generators/pydanticgen/includes.py,sha256=PIVbACrtqQS6LFrXqQsJC6dQUcGBM3uY4E4qLQWJrnk,998
47
+ linkml/generators/pydanticgen/pydanticgen.py,sha256=WZxFfLvXhHXVtDQpLjMf63eoBMUxcW0oEMS14jbDOWo,34458
48
+ linkml/generators/pydanticgen/template.py,sha256=HESLY1Rd7N_e92dqrh_fif_yp3oDl0n1UAghklMyphA,20982
49
+ linkml/generators/pydanticgen/templates/attribute.py.jinja,sha256=S_T-M7n_eeM3LW5gQUuTPH1-Oc1CEtL7Bve7qAFouYQ,688
49
50
  linkml/generators/pydanticgen/templates/base_model.py.jinja,sha256=48y64MnC9rjNSV-nKLMeDuHN4gm15UsInhnKxh65zoM,834
50
- linkml/generators/pydanticgen/templates/class.py.jinja,sha256=RIdkqdZS9rDILUuVqDIAWK_vATGkirLbPhdHSyHDAbY,565
51
+ linkml/generators/pydanticgen/templates/class.py.jinja,sha256=V_lyvFcZ9QhlKZi2bL5iff8RjHir2SQTTypOzQMOfmk,744
51
52
  linkml/generators/pydanticgen/templates/conditional_import.py.jinja,sha256=YheknDrxvepiJUzeItSL5aSbAkCdR1k0a6m6aTA4qNM,240
52
53
  linkml/generators/pydanticgen/templates/enum.py.jinja,sha256=572XFQyEMZfL-G_Cj68T-NI_mUnDoFOAVJOGIKu2Hb8,338
53
54
  linkml/generators/pydanticgen/templates/footer.py.jinja,sha256=WuWGJjkWDQcEPL2bGk5fdGuhO0gQRUJzpo4CQHHxQNQ,385
54
55
  linkml/generators/pydanticgen/templates/imports.py.jinja,sha256=d1XFna2eOpkH8cgJML3vXwqGcocczvOcrbg6jjd4kP0,945
55
- linkml/generators/pydanticgen/templates/module.py.jinja,sha256=SkmtWtQS7D-xBiZI-sFiYC3WYPKi3VJCj_KtaMVxexM,438
56
+ linkml/generators/pydanticgen/templates/module.py.jinja,sha256=nymjtSX4jqV9deSsXrsh1HWR90ygECHE4CV9MCyNrTY,615
56
57
  linkml/generators/pydanticgen/templates/validator.py.jinja,sha256=Yo4dubQal-HwEoJKztQkLYM5qCz1I8na2oaDlXuEpwU,532
57
- linkml/generators/pythongen.py,sha256=IVloJ6v7QE7mdHygz0kZmcJ6D61usKffeyBmZjkArng,52879
58
+ linkml/generators/pythongen.py,sha256=CiLmc964siGeJWZC_bOffsqrSnJ5qzn7Eu961C47xgo,52850
58
59
  linkml/generators/rdfgen.py,sha256=eQi3XXjWk6xliTLncQ4G0VYzGCJwCU_FFG-O7tA8DSA,2959
59
60
  linkml/generators/shacl/__init__.py,sha256=O-M-wndKw8rMW-U8X3QCNHal-ErXP6uXZqxiQSa77l4,108
60
61
  linkml/generators/shacl/ifabsent_processor.py,sha256=kV9BGA2ZPXLRfaFuW0o4jpkATvGggvrqpAo9c1UqWNE,2193
61
62
  linkml/generators/shacl/shacl_data_type.py,sha256=BT3C9tdFyBQnuucPN7YQiFAKEa9yuzy-Q26X6dmOXgo,1827
62
- linkml/generators/shaclgen.py,sha256=B9BkCzOQULjpCN10jbvazY6_WEkeVGO8lxEhr6pQ3_A,8849
63
+ linkml/generators/shaclgen.py,sha256=kgJ3VaVM0_7XBr5cvqgob6wjEarNINZzpC4FK61sC9M,13157
63
64
  linkml/generators/shexgen.py,sha256=MhB1HidCREMCJcDGBqutFQ0gWKKz7aSVw-0s-IHUMm4,9930
64
65
  linkml/generators/sparqlgen.py,sha256=c7x8GFChKWprBx4rToSnu9qN8OleWTCenVUdZ8XSTWM,6138
65
66
  linkml/generators/sqlalchemy/__init__.py,sha256=mb9AC1rIFkSiNZhhG0TAk45ol9PjS1XvsrvCjgfVUpQ,249
66
67
  linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py,sha256=X_Ws1NUBikMI5HuNgEhl_PIeWM-B-c2B0W9KUBH4QTg,2542
67
68
  linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py,sha256=u4ZpponG1h6XROrOHGOf_0H2e6xL1_s8twAOA-gx94A,1622
68
- linkml/generators/sqlalchemygen.py,sha256=5J9eQhTz7Ug-7WhZPv6zIaAbf7xlLi-0xMequ67pvgA,9320
69
+ linkml/generators/sqlalchemygen.py,sha256=boXn_tlkbZ_a5TJYoXvdlKzABNwD-Jn5ld9IAbtzWm4,9286
69
70
  linkml/generators/sqltablegen.py,sha256=87057FJi9EUVPXOjRfHuSqY0lKmepXRNQsose2fGts4,12343
70
71
  linkml/generators/sssomgen.py,sha256=yur3q7so9uwIELWZaZRzkJwNbz_ppBL7IQki9XLIM3k,6879
71
72
  linkml/generators/string_template.md,sha256=kRcfic6entgIaJdpSg6GF3jcjC9wbKsCVM6wVT2qipc,1788
@@ -89,11 +90,11 @@ linkml/linter/formatters/markdown_formatter.py,sha256=sumF2MNJYL5oipLwCftCr3AiaC
89
90
  linkml/linter/formatters/terminal_formatter.py,sha256=xmNwlRieVCssRt3fpnNP5WWw_YXGmaBsbxFoMWufy5M,2085
90
91
  linkml/linter/formatters/tsv_formatter.py,sha256=1VW-1Tv16mwhIDpHdExYpJJR3z42K5_XK2C-4mmYYdE,871
91
92
  linkml/linter/linter.py,sha256=qfVV-vFT7bUJ2BmmDQteD7Jz8HZ-CNDSvnkyhJ-54H0,5113
92
- linkml/linter/rules.py,sha256=EuZTHtrU9YndAf2vw6QknGZSVFgsbydStsQmrUCwTKk,11502
93
+ linkml/linter/rules.py,sha256=Eg_-lIX1KPsCp3PHdPcBiHmSS5qAVZkHbw5LURfkfXk,11481
93
94
  linkml/reporting/__init__.py,sha256=Jo0V_nyEcnWhMukMW-bqW9dlbgCfaRlWm3CO-XzgU84,92
94
95
  linkml/reporting/model.py,sha256=-10yNfk8wuRC48ZI-akrWvtlJ9a6RYWET2TzlZV3XXo,8622
95
96
  linkml/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
- linkml/transformers/logical_model_transformer.py,sha256=Luc8cKWIGrRAXQ9DSLA03fgpIolLpsTT19OV9Coolvk,26522
97
+ linkml/transformers/logical_model_transformer.py,sha256=z-1nyD0d8LYJeAPWRn29p-S4Hgmvjocfcj0VrHTAs2c,26703
97
98
  linkml/transformers/model_transformer.py,sha256=tK_MpRDI-q2qfe8KHT6qJHP8ZruKjYx1FcM-Fnjse-E,678
98
99
  linkml/transformers/relmodel_transformer.py,sha256=aiSI2xaqRz4f0Z_0WFaBP5bknzX0pTnvxsR5mESFysg,18857
99
100
  linkml/transformers/schema_renamer.py,sha256=DYRbgL9j41M9FdbHYLY3u4YIdDM98laD3cv_lHcgWHQ,5275
@@ -112,12 +113,12 @@ linkml/utils/mergeutils.py,sha256=QVm2iQB4v_L2rSvPBsPe9C865R03BgV3TzlPoTTTwWQ,90
112
113
  linkml/utils/rawloader.py,sha256=nUB8Gfn8yEVwyo6bx0TtB2mBGkilC-fybi0xvQ73Gks,4417
113
114
  linkml/utils/schema_builder.py,sha256=4qhrur8O0xRZnPm7H1h2BZmTkut5R4q-IE_1KKiHy_c,9937
114
115
  linkml/utils/schema_fixer.py,sha256=Uz8M3AOQ_BputJr1f6lbfk1iyvmANUNG80-0B3BQKJ8,16761
115
- linkml/utils/schemaloader.py,sha256=5fLM99v6RZ0OW4JHA0UAd_mtS_2HNubXAjlF5v8vHcw,46093
116
- linkml/utils/schemasynopsis.py,sha256=jKf5ZJxpNgSZ5x9oAcdGO3m1IwzcIU2Ni1ugm0SQq1g,18447
116
+ linkml/utils/schemaloader.py,sha256=dWZO044p_UcUWnrd8HZ-NsbLXQ9cA6c8HKfNI9-qH2A,47388
117
+ linkml/utils/schemasynopsis.py,sha256=j7sNt6j-E3rmf-1qEo351Kth2kltt6crQV-dxJAGCUE,18414
117
118
  linkml/utils/sqlutils.py,sha256=Cwoaz44MLcvAGUEBshT4jtn0Z3w7jVOp85zGkd6FTHY,17071
118
119
  linkml/utils/typereferences.py,sha256=8Yfuz9-HAwOPoJLbIcO_sY9zf32hvPRzGeSOzECfMWA,2232
119
120
  linkml/utils/validation.py,sha256=eLw1-d8x3N1V14bSc6H_mJJXo59ryKvvUIBcOJ1dVMw,1438
120
- linkml/validator/__init__.py,sha256=djKc1IyxGKvVYaX5jSxsqjfcEYaw3rFgKbFJxI2wDNk,5002
121
+ linkml/validator/__init__.py,sha256=u0CeorIw50Qqwa60-lIFsJXg-sOdfo90hqvLpyvvwo4,4993
121
122
  linkml/validator/cli.py,sha256=uVe_tbBzsK-4BNboE5zRyohS_dEs5Nl1gbhklrzOEpw,7605
122
123
  linkml/validator/loaders/__init__.py,sha256=FjUqEfBHeT5PEMBEZ9XwpclyQOysr4OCI1M0w_MYPVc,1165
123
124
  linkml/validator/loaders/delimited_file_loader.py,sha256=fdh61ZMPTfH29_DM93f5dY0jLP7KQPNh_QAHZppsdNw,2616
@@ -125,7 +126,7 @@ linkml/validator/loaders/json_loader.py,sha256=Qy42naS2clb0fNXbUushckRu5AIX32b3U
125
126
  linkml/validator/loaders/loader.py,sha256=YKQXmSZhCymvvb2Dbr4lVCKVDt-lOIayzRD7CWrdsJI,559
126
127
  linkml/validator/loaders/passthrough_loader.py,sha256=fQvBZqzGnpdwpZio4Mbehmsb6ePpzcacHPuR1QWuhFM,525
127
128
  linkml/validator/loaders/yaml_loader.py,sha256=ZsMz-oGDkX9oPEOVcKnFRGhU9q0fKoHcL6BLOkCeB4c,914
128
- linkml/validator/plugins/__init__.py,sha256=F7Un7bfdpSRXvk8LTb7Z4Q22rCtJJKjNkqUfIVLFtT8,702
129
+ linkml/validator/plugins/__init__.py,sha256=0ifiDqpcXVy4X7OJFm7FMYi1-6E06avNIIk9R0c6nD8,693
129
130
  linkml/validator/plugins/jsonschema_validation_plugin.py,sha256=c3OjvLR5m83vppsDfkrS9nMXma_ogUxXpZuM_JIUVM4,2634
130
131
  linkml/validator/plugins/pydantic_validation_plugin.py,sha256=C-Vp74bz5oqp5V-iuhXW8p0PPDoFY8NCU5x36Ur5Og4,1985
131
132
  linkml/validator/plugins/recommended_slots_plugin.py,sha256=kOdoYQyye47nLA7BjorVmydS84nGpiVy3MoCbPq1Ymo,2308
@@ -142,8 +143,8 @@ linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
142
143
  linkml/workspaces/datamodel/workspaces.py,sha256=4HdkqweGNfMPqnB1_Onc9DcTfkhoagTRcqruh08nRoI,14905
143
144
  linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
144
145
  linkml/workspaces/example_runner.py,sha256=hDk2RGxRE5-WYNriWknugtbm3Mhn8bFcAcXGMlkYxVk,11705
145
- linkml-1.7.10.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
146
- linkml-1.7.10.dist-info/METADATA,sha256=yPm-MeDgZDVgX_q3NF46RfunUoxWV2Mc5W6-ZkE6x_Y,3725
147
- linkml-1.7.10.dist-info/entry_points.txt,sha256=7haDkIbyC7ZLhm5z-e3BhrLJpY2xoW1yuD8Y7QPNtVg,2093
148
- linkml-1.7.10.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
149
- linkml-1.7.10.dist-info/RECORD,,
146
+ linkml-1.8.0.dist-info/entry_points.txt,sha256=7haDkIbyC7ZLhm5z-e3BhrLJpY2xoW1yuD8Y7QPNtVg,2093
147
+ linkml-1.8.0.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
148
+ linkml-1.8.0.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
149
+ linkml-1.8.0.dist-info/METADATA,sha256=ImZiqQezJfM8leU0WgCimYjcJXydh1XO8T22tlC9zpw,3724
150
+ linkml-1.8.0.dist-info/RECORD,,