linkml 1.7.2__py3-none-any.whl → 1.7.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
linkml/__init__.py CHANGED
@@ -71,3 +71,10 @@ BIOLINK_MODEL_URI = "https://w3id.org/biolink/biolink-model"
71
71
  BIOLINK_MODEL_PYTHON_LOC = "biolink.model"
72
72
 
73
73
  TurtleSerializer.roundtrip_prefixes = [""]
74
+
75
+ REQUESTS_TIMEOUT = 10
76
+ """
77
+ Time (in seconds) to wait before failing a network request
78
+
79
+ See: https://docs.python-requests.org/en/latest/user/advanced/#timeouts
80
+ """
@@ -126,7 +126,7 @@ class DocGenerator(Generator):
126
126
  # ObjectVars
127
127
  dialect: Optional[Union[DIALECT, str]] = None
128
128
  """markdown dialect (e.g MyST, Python)"""
129
- sort_by: str = field(default_factory=lambda: "name")
129
+ sort_by: str = "name"
130
130
  visit_all_class_slots = False
131
131
  template_mappings: Dict[str, str] = None
132
132
  directory: str = None
@@ -141,19 +141,19 @@ class DocGenerator(Generator):
141
141
  diagram_type: Optional[Union[DiagramType, str]] = None
142
142
  """style of diagram (ER, UML)"""
143
143
 
144
- include_top_level_diagram: bool = field(default_factory=lambda: False)
144
+ include_top_level_diagram: bool = False
145
145
  """Whether the index page should include a schema diagram"""
146
146
 
147
147
  example_directory: Optional[str] = None
148
148
  example_runner: ExampleRunner = field(default_factory=lambda: ExampleRunner())
149
149
 
150
- genmeta: bool = field(default_factory=lambda: False)
151
- gen_classvars: bool = field(default_factory=lambda: True)
152
- gen_slots: bool = field(default_factory=lambda: True)
153
- no_types_dir: bool = field(default_factory=lambda: False)
154
- use_slot_uris: bool = field(default_factory=lambda: False)
155
- use_class_uris: bool = field(default_factory=lambda: False)
156
- hierarchical_class_view: bool = field(default_factory=lambda: False)
150
+ genmeta: bool = False
151
+ gen_classvars: bool = True
152
+ gen_slots: bool = True
153
+ no_types_dir: bool = False
154
+ use_slot_uris: bool = False
155
+ use_class_uris: bool = False
156
+ hierarchical_class_view: bool = False
157
157
 
158
158
  def __post_init__(self):
159
159
  dialect = self.dialect
@@ -1,5 +1,5 @@
1
1
  import os
2
- from dataclasses import dataclass, field
2
+ from dataclasses import dataclass
3
3
  from enum import Enum
4
4
  from typing import List, Optional, Union
5
5
 
@@ -129,11 +129,11 @@ class ERDiagramGenerator(Generator):
129
129
  exclude_attributes: bool = False
130
130
  """If True, do not include attributes in entities"""
131
131
 
132
- genmeta: bool = field(default_factory=lambda: False)
133
- gen_classvars: bool = field(default_factory=lambda: True)
134
- gen_slots: bool = field(default_factory=lambda: True)
135
- no_types_dir: bool = field(default_factory=lambda: False)
136
- use_slot_uris: bool = field(default_factory=lambda: False)
132
+ genmeta: bool = False
133
+ gen_classvars: bool = True
134
+ gen_slots: bool = True
135
+ no_types_dir: bool = False
136
+ use_slot_uris: bool = False
137
137
 
138
138
  def __post_init__(self):
139
139
  self.schemaview = SchemaView(self.schema)
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from dataclasses import dataclass, field
2
+ from dataclasses import dataclass
3
3
  from pathlib import Path
4
4
  from typing import List
5
5
 
@@ -22,8 +22,8 @@ class ExcelGenerator(Generator):
22
22
  uses_schemaloader = False
23
23
  requires_metamodel = False
24
24
 
25
- split_workbook_by_class: bool = field(default_factory=lambda: False)
26
- include_mixins: bool = field(default_factory=lambda: False)
25
+ split_workbook_by_class: bool = False
26
+ include_mixins: bool = False
27
27
 
28
28
  def __post_init__(self) -> None:
29
29
  super().__post_init__()
@@ -160,7 +160,7 @@ class GolangGenerator(Generator):
160
160
  rc_name = self.name(rc)
161
161
  id_slot = self.get_identifier_or_key_slot(r)
162
162
  if slot.multivalued:
163
- if not id_slot or slot.inlined:
163
+ if not id_slot or slot.inlined or slot.inlined_as_list:
164
164
  if slot.inlined_as_list or not id_slot:
165
165
  return f"[]{rc_name}"
166
166
  else:
@@ -1,6 +1,6 @@
1
1
  import importlib.util
2
2
  import os
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
  from typing import Optional
5
5
 
6
6
  import click
@@ -78,10 +78,10 @@ class JavaGenerator(OOCodeGenerator):
78
78
 
79
79
  template_file: Optional[str] = None
80
80
 
81
- gen_classvars: bool = field(default_factory=lambda: True)
82
- gen_slots: bool = field(default_factory=lambda: True)
83
- genmeta: bool = field(default_factory=lambda: False)
84
- emit_metadata: bool = field(default_factory=lambda: True)
81
+ gen_classvars: bool = True
82
+ gen_slots: bool = True
83
+ genmeta: bool = False
84
+ emit_metadata: bool = True
85
85
 
86
86
  def default_value_for_type(self, typ: str) -> str:
87
87
  return TYPE_DEFAULTS.get(typ, "null")
@@ -45,12 +45,12 @@ class ContextGenerator(Generator):
45
45
  default_ns: str = None
46
46
  context_body: Dict = field(default_factory=lambda: dict())
47
47
  slot_class_maps: Dict = field(default_factory=lambda: dict())
48
- emit_metadata: bool = field(default_factory=lambda: False)
49
- model: Optional[bool] = field(default_factory=lambda: True)
48
+ emit_metadata: bool = False
49
+ model: Optional[bool] = True
50
50
  base: Optional[str] = None
51
51
  output: Optional[str] = None
52
- prefixes: Optional[bool] = field(default_factory=lambda: True)
53
- flatprefixes: Optional[bool] = field(default_factory=lambda: False)
52
+ prefixes: Optional[bool] = True
53
+ flatprefixes: Optional[bool] = False
54
54
 
55
55
  def __post_init__(self) -> None:
56
56
  super().__post_init__()
@@ -150,7 +150,8 @@ class ContextGenerator(Generator):
150
150
  else:
151
151
  slot_def = {}
152
152
  if not slot.usage_slot_name:
153
- if slot.range in self.schema.classes:
153
+ any_of_ranges = [any_of_el.range for any_of_el in slot.any_of]
154
+ if slot.range in self.schema.classes or any(rng in self.schema.classes for rng in any_of_ranges):
154
155
  slot_def["@type"] = "@id"
155
156
  elif slot.range in self.schema.enums:
156
157
  slot_def["@context"] = ENUM_CONTEXT
@@ -2,7 +2,7 @@ import json
2
2
  import logging
3
3
  import os
4
4
  from copy import deepcopy
5
- from dataclasses import dataclass, field
5
+ from dataclasses import dataclass
6
6
  from typing import Any, Dict, List, Optional, Tuple, Union
7
7
 
8
8
  import click
@@ -179,7 +179,7 @@ class JsonSchemaGenerator(Generator):
179
179
  # @deprecated("Use top_class")
180
180
  topClass: Optional[str] = None
181
181
 
182
- not_closed: Optional[bool] = field(default_factory=lambda: True)
182
+ not_closed: Optional[bool] = True
183
183
  """If not closed, then an open-ended set of attributes can be instantiated for any object"""
184
184
 
185
185
  indent: int = 4
@@ -188,7 +188,7 @@ class JsonSchemaGenerator(Generator):
188
188
  top_class: Optional[Union[ClassDefinitionName, str]] = None # JSON object is one instance of this
189
189
  """Class instantiated by the root node of the document tree"""
190
190
 
191
- include_range_class_descendants: bool = field(default_factory=lambda: False)
191
+ include_range_class_descendants: bool = False
192
192
  """If set, use an open world assumption and allow the range of a slot to be any descendant of the declared range.
193
193
  Note that if the range of a slot has a type designator, descendants will always be included.
194
194
  """
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import os
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
  from typing import Union
5
5
 
6
6
  import click
@@ -30,8 +30,8 @@ class LinkmlGenerator(Generator):
30
30
  uses_schemaloader = False
31
31
  requires_metamodel = False
32
32
 
33
- materialize_attributes: bool = field(default_factory=lambda: False)
34
- materialize_patterns: bool = field(default_factory=lambda: False)
33
+ materialize_attributes: bool = False
34
+ materialize_patterns: bool = False
35
35
 
36
36
  def __post_init__(self):
37
37
  # TODO: consider moving up a level
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from contextlib import redirect_stdout
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
  from io import StringIO
5
5
  from typing import Any, Callable, Dict, List, Optional, Set, Union
6
6
 
@@ -47,7 +47,7 @@ class MarkdownGenerator(Generator):
47
47
  image_directory: Optional[str] = None
48
48
  classes: Set[ClassDefinitionName] = None
49
49
  image_dir: bool = False
50
- index_file: str = field(default_factory=lambda: "index.md")
50
+ index_file: str = "index.md"
51
51
  noimages: bool = False
52
52
  noyuml: bool = False
53
53
  no_types_dir: bool = False
@@ -141,7 +141,10 @@ class OOCodeGenerator(Generator):
141
141
  enum["description"] = enum_original.description
142
142
 
143
143
  for pv in enum_original.permissible_values.values():
144
- label = self.generate_enum_label(pv.text)
144
+ if pv.title:
145
+ label = self.generate_enum_label(pv.title)
146
+ else:
147
+ label = self.generate_enum_label(pv.text)
145
148
  val = {"label": label, "value": pv.text.replace('"', '\\"')}
146
149
  if hasattr(pv, "description"):
147
150
  val["description"] = pv.description
@@ -118,29 +118,29 @@ class OwlSchemaGenerator(Generator):
118
118
  """By default, use the linkml metadata profile,
119
119
  this allows for overrides."""
120
120
 
121
- metaclasses: bool = field(default_factory=lambda: True)
121
+ metaclasses: bool = True
122
122
  """if True, include OWL representations of ClassDefinition, SlotDefinition, etc. Introduces punning"""
123
123
 
124
- add_root_classes: bool = field(default_factory=lambda: False)
124
+ add_root_classes: bool = False
125
125
 
126
- add_ols_annotations: bool = field(default_factory=lambda: True)
126
+ add_ols_annotations: bool = True
127
127
  graph: Optional[Graph] = None
128
128
  """Mutable graph that is being built up during OWL generation."""
129
129
 
130
130
  top_value_uri: Optional[URIRef] = None
131
131
  """If metaclasses=True, then this property is used to connect object shadows to literals"""
132
132
 
133
- type_objects: bool = field(default_factory=lambda: True)
133
+ type_objects: bool = True
134
134
  """if True, represents types as classes (and thus all slots are object properties);
135
135
  typed object classes effectively shadow the main xsd literal types.
136
136
  The purpose of this is to allow a uniform ObjectProperty representation for all slots,
137
137
  without having to commit to being either Data or Object property (OWL-DL does not
138
138
  allow a property to be both."""
139
139
 
140
- assert_equivalent_classes: bool = field(default_factory=lambda: False)
140
+ assert_equivalent_classes: bool = False
141
141
  """If True, assert equivalence between definition_uris and class_uris"""
142
142
 
143
- use_native_uris: bool = field(default_factory=lambda: True)
143
+ use_native_uris: bool = True
144
144
  """If True, use the definition_uris, otherwise use class_uris."""
145
145
 
146
146
  mixins_as_expressions: bool = None
@@ -152,10 +152,10 @@ class OwlSchemaGenerator(Generator):
152
152
  node_owltypes: Mapping[Union[BNode, URIRef], Set[OWL_TYPE]] = field(default_factory=lambda: defaultdict(set))
153
153
  """rdfs:Datatype, owl:Thing"""
154
154
 
155
- simplify: bool = field(default_factory=lambda: True)
155
+ simplify: bool = True
156
156
  """Reduce complex expressions to simpler forms"""
157
157
 
158
- use_swrl: bool = field(default_factory=lambda: False)
158
+ use_swrl: bool = False
159
159
  """Use of SWRL is experimental"""
160
160
 
161
161
  target_profile: OWLProfile = field(default_factory=lambda: OWLProfile.dl)
@@ -378,8 +378,12 @@ class OwlSchemaGenerator(Generator):
378
378
  # rules yield OWL GCI subClassOf axioms
379
379
  for rule in cls.rules:
380
380
  pre_node = condition_to_bnode(rule.preconditions)
381
+ if not pre_node:
382
+ continue
381
383
  pre_node = self._intersection_of([pre_node, subject_expr])
382
384
  post_node = condition_to_bnode(rule.postconditions)
385
+ if not post_node:
386
+ continue
383
387
  self.graph.add((pre_node, RDFS.subClassOf, post_node))
384
388
  # classification rules yield OWL GCI subClassOf axioms
385
389
  for expr in cls.classification_rules:
@@ -433,15 +437,10 @@ class OwlSchemaGenerator(Generator):
433
437
  if slot.name in slot_map:
434
438
  for k, v in slot.__dict__.items():
435
439
  curr = slot_map[slot.name].get(k, None)
436
- # print(f"MERGE={slot.name}.{k} = {v} // CURR={curr}")
437
440
  if v and not curr:
438
441
  slot_map[slot.name][k] = v
439
- # print(f"OVERRIDE={slot.name}, k={k}, v={v}")
440
442
  else:
441
443
  slot_map[slot.name] = copy(slot.__dict__)
442
- # print(f"INIT={slot.name}, vals={slot_map[slot.name]}")
443
-
444
- # print(f"SN={slot.name}, vals={slot_map[slot.name]}")
445
444
  own_slots = [SlotDefinition(**v) for v in slot_map.values()]
446
445
  # sort by name
447
446
  own_slots.sort(key=lambda x: x.name)
@@ -462,6 +461,8 @@ class OwlSchemaGenerator(Generator):
462
461
  :param cls: LinkML class expression (anonymous if called recursively)
463
462
  :return: blank node representing the OWL expression
464
463
  """
464
+ if cls is None:
465
+ cls = AnonymousClassExpression()
465
466
  graph = self.graph
466
467
  sv = self.schemaview
467
468
  own_slots = self.get_own_slots(cls)
@@ -477,11 +478,13 @@ class OwlSchemaGenerator(Generator):
477
478
  graph.add((cls_uri, OWL.disjointUnionOf, listnode))
478
479
  else:
479
480
  sub_sub_exprs = []
480
- for i, x in enumerate(sub_exprs):
481
- rest = sub_exprs[0:i] + sub_exprs[i + 1 :]
482
- neg_expr = self._complement_of_union_of(rest)
483
- sub_sub_exprs.append(self._intersection_of([x, neg_expr]))
484
- sub_exprs.append(self._union_of(sub_sub_exprs))
481
+ for i, x in enumerate(cls.exactly_one_of):
482
+ rest = cls.exactly_one_of[0:i] + cls.exactly_one_of[i + 1 :]
483
+ neg_expr = self._complement_of_union_of([self.transform_class_expression(nx) for nx in rest])
484
+ pos_expr = self._intersection_of([self.transform_class_expression(x), neg_expr])
485
+ sub_sub_exprs.append(pos_expr)
486
+ owl_exprs.append(self._union_of(sub_sub_exprs))
487
+ # owl_exprs.extend(sub_exprs)
485
488
  if cls.all_of:
486
489
  owl_exprs.append(self._intersection_of([self.transform_class_expression(x) for x in cls.all_of]))
487
490
  if cls.none_of:
@@ -533,7 +536,8 @@ class OwlSchemaGenerator(Generator):
533
536
  graph.add((max_card_expr, OWL.onProperty, slot_uri))
534
537
  if slot.has_member:
535
538
  has_member_expr = self.transform_class_slot_expression(cls, slot.has_member, slot)
536
- owl_exprs.append(self._some_values_from(slot_uri, has_member_expr))
539
+ if has_member_expr:
540
+ owl_exprs.append(self._some_values_from(slot_uri, has_member_expr))
537
541
  return self._intersection_of(owl_exprs)
538
542
 
539
543
  def slot_node_owltypes(self, slot: Union[SlotDefinition, AnonymousSlotExpression]) -> Set[URIRef]:
@@ -558,7 +562,7 @@ class OwlSchemaGenerator(Generator):
558
562
  slot: Union[SlotDefinition, AnonymousSlotExpression],
559
563
  main_slot: SlotDefinition = None,
560
564
  owl_types: Set[OWL_TYPE] = None,
561
- ) -> Union[BNode, URIRef]:
565
+ ) -> Optional[Union[BNode, URIRef]]:
562
566
  """
563
567
  Take a ClassExpression and SlotExpression combination and transform to a node.
564
568
 
@@ -597,11 +601,19 @@ class OwlSchemaGenerator(Generator):
597
601
  )
598
602
  )
599
603
  if slot.exactly_one_of:
600
- owl_exprs.append(
601
- self._exactly_one_of(
602
- [self.transform_class_slot_expression(cls, x, main_slot, owl_types) for x in slot.exactly_one_of]
604
+ disj_exprs = []
605
+ for i, operand in enumerate(slot.exactly_one_of):
606
+ rest = slot.exactly_one_of[0:i] + slot.exactly_one_of[i + 1 :]
607
+ neg_expr = self._complement_of_union_of(
608
+ [self.transform_class_slot_expression(cls, x, main_slot, owl_types) for x in rest],
609
+ owl_types=owl_types,
603
610
  )
604
- )
611
+ pos_expr = self._intersection_of(
612
+ [self.transform_class_slot_expression(cls, operand, main_slot, owl_types), neg_expr],
613
+ owl_types=owl_types,
614
+ )
615
+ disj_exprs.append(pos_expr)
616
+ owl_exprs.append(self._union_of(disj_exprs, owl_types=owl_types))
605
617
  range = slot.range
606
618
  # if not range and not owl_exprs:
607
619
  # range = sv.schema.default_range
@@ -929,6 +941,10 @@ class OwlSchemaGenerator(Generator):
929
941
  triples.extend(graph.triples((obj, None, None)))
930
942
 
931
943
  def _some_values_from(self, property: URIRef, filler: Union[URIRef, BNode]) -> BNode:
944
+ if not property:
945
+ raise ValueError(f"Property is required, filler: {filler}")
946
+ if not filler:
947
+ raise ValueError(f"Filler is required, property: {property}")
932
948
  node = BNode()
933
949
  self.graph.add((node, RDF.type, OWL.Restriction))
934
950
  self.graph.add((node, OWL.onProperty, property))
@@ -970,11 +986,14 @@ class OwlSchemaGenerator(Generator):
970
986
  def _metaslot_uri(self, name: str) -> URIRef:
971
987
  return URIRef("https://w3id.org/linkml/" + name)
972
988
 
973
- def _complement_of_union_of(self, exprs: List[Union[BNode, URIRef]], **kwargs) -> Optional[Union[BNode, URIRef]]:
989
+ def _complement_of_union_of(
990
+ self, exprs: List[Union[BNode, URIRef]], owl_types: Set[OWL_TYPE] = None, **kwargs
991
+ ) -> Optional[Union[BNode, URIRef]]:
974
992
  if not exprs:
975
993
  raise ValueError("Must pass at least one")
976
994
  neg_expr = BNode()
977
- owl_types = self._get_owltypes(set(), exprs)
995
+ if not owl_types:
996
+ owl_types = self._get_owltypes(set(), exprs)
978
997
  complement_predicate = OWL.complementOf
979
998
  if len(owl_types) == 1:
980
999
  if RDFS.Literal in owl_types:
@@ -7,7 +7,7 @@ https://plantuml.com/
7
7
  import base64
8
8
  import os
9
9
  import zlib
10
- from dataclasses import dataclass, field
10
+ from dataclasses import dataclass
11
11
  from typing import Callable, List, Optional, Set, cast
12
12
 
13
13
  import click
@@ -19,6 +19,7 @@ from linkml_runtime.linkml_model.meta import (
19
19
  )
20
20
  from linkml_runtime.utils.formatutils import camelcase, underscore
21
21
 
22
+ from linkml import REQUESTS_TIMEOUT
22
23
  from linkml._version import __version__
23
24
  from linkml.utils.generator import Generator, shared_arguments
24
25
 
@@ -48,7 +49,7 @@ class PlantumlGenerator(Generator):
48
49
  classes: Set[ClassDefinitionName] = None
49
50
  directory: Optional[str] = None
50
51
  kroki_server: Optional[str] = "https://kroki.io"
51
- load_image: bool = field(default_factory=lambda: True)
52
+ load_image: bool = True
52
53
 
53
54
  def visit_schema(
54
55
  self,
@@ -101,7 +102,7 @@ class PlantumlGenerator(Generator):
101
102
  camelcase(sorted(classes)[0] if classes else self.schema.name) + file_suffix,
102
103
  )
103
104
  if load_image:
104
- resp = requests.get(plantuml_url, stream=True)
105
+ resp = requests.get(plantuml_url, stream=True, timeout=REQUESTS_TIMEOUT)
105
106
  if resp.ok:
106
107
  with open(self.output_file_name, "wb") as f:
107
108
  for chunk in resp.iter_content(chunk_size=2048):
@@ -1,5 +1,5 @@
1
1
  import os
2
- from dataclasses import dataclass, field
2
+ from dataclasses import dataclass
3
3
 
4
4
  import click
5
5
  from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
@@ -24,7 +24,7 @@ class ProtoGenerator(Generator):
24
24
  uses_schemaloader = True
25
25
 
26
26
  # ObjectVars
27
- relative_slot_num: int = field(default_factory=lambda: 0)
27
+ relative_slot_num: int = 0
28
28
 
29
29
  def __post_init__(self):
30
30
  super().__post_init__()
@@ -1,10 +1,11 @@
1
+ import inspect
1
2
  import logging
2
3
  import os
3
4
  from collections import defaultdict
4
5
  from copy import deepcopy
5
6
  from dataclasses import dataclass, field
6
7
  from types import ModuleType
7
- from typing import Dict, List, Optional, Set
8
+ from typing import Dict, List, Optional, Set, Type, Union
8
9
 
9
10
  import click
10
11
  from jinja2 import Template
@@ -32,7 +33,9 @@ from linkml.utils.generator import shared_arguments
32
33
  from linkml.utils.ifabsent_functions import ifabsent_value_declaration
33
34
 
34
35
 
35
- def default_template(pydantic_ver: str = "1", extra_fields: str = "forbid") -> str:
36
+ def default_template(
37
+ pydantic_ver: str = "1", extra_fields: str = "forbid", injected_classes: Optional[List[Union[Type, str]]] = None
38
+ ) -> str:
36
39
  """Constructs a default template for pydantic classes based on the version of pydantic"""
37
40
  ### HEADER ###
38
41
  template = """
@@ -46,6 +49,7 @@ from enum import Enum
46
49
  {% if uses_numpy -%}
47
50
  import numpy as np
48
51
  {%- endif %}
52
+ from decimal import Decimal
49
53
  from typing import List, Dict, Optional, Any, Union"""
50
54
  if pydantic_ver == "1":
51
55
  template += """
@@ -61,7 +65,26 @@ if sys.version_info >= (3, 8):
61
65
  else:
62
66
  from typing_extensions import Literal
63
67
 
64
-
68
+ {% if imports is not none %}
69
+ {%- for import_module, import_classes in imports.items() -%}
70
+ {% if import_classes is none -%}
71
+ import {{ import_module }}
72
+ {% elif import_classes is mapping -%}
73
+ import {{ import_module }} as {{ import_classes['as'] }}
74
+ {% else -%}
75
+ from {{ import_module }} import (
76
+ {% for imported_class in import_classes %}
77
+ {%- if imported_class is string -%}
78
+ {{ imported_class }}
79
+ {%- else -%}
80
+ {{ imported_class['name'] }} as {{ imported_class['as'] }}
81
+ {%- endif -%}
82
+ {%- if not loop.last %},{{ '\n ' }}{% else %}{{ '\n' }}{%- endif -%}
83
+ {% endfor -%}
84
+ )
85
+ {% endif -%}
86
+ {% endfor -%}
87
+ {% endif %}
65
88
  metamodel_version = "{{metamodel_version}}"
66
89
  version = "{{version if version else None}}"
67
90
  """
@@ -78,7 +101,6 @@ class ConfiguredBaseModel(WeakRefShimBaseModel,
78
101
  extra = '{extra_fields}',
79
102
  arbitrary_types_allowed = True,
80
103
  use_enum_values = True):
81
- pass
82
104
  """
83
105
  else:
84
106
  template += f"""
@@ -89,9 +111,27 @@ class ConfiguredBaseModel(BaseModel):
89
111
  extra = '{extra_fields}',
90
112
  arbitrary_types_allowed=True,
91
113
  use_enum_values = True)
92
- pass
93
114
  """
94
115
 
116
+ ### Fields injected into base model
117
+ template += """{% if injected_fields is not none %}
118
+ {% for field in injected_fields -%}
119
+ {{ field }}
120
+ {% endfor %}
121
+ {% else %}
122
+ pass
123
+ {% endif %}
124
+ """
125
+
126
+ ### Extra classes
127
+ if injected_classes is not None and len(injected_classes) > 0:
128
+ template += """{{ '\n\n' }}"""
129
+ for cls in injected_classes:
130
+ if isinstance(cls, str):
131
+ template += cls + "\n\n"
132
+ else:
133
+ template += inspect.getsource(cls) + "\n\n"
134
+
95
135
  ### ENUMS ###
96
136
  template += """
97
137
  {% for e in enums.values() %}
@@ -270,14 +310,75 @@ class PydanticGenerator(OOCodeGenerator):
270
310
  # ObjectVars
271
311
  pydantic_version: str = field(default_factory=lambda: PYDANTIC_VERSION[0])
272
312
  template_file: str = None
273
- extra_fields: str = field(default_factory=lambda: "forbid")
274
- gen_mixin_inheritance: bool = field(default_factory=lambda: True)
313
+ extra_fields: str = "forbid"
314
+ gen_mixin_inheritance: bool = True
315
+ injected_classes: Optional[List[Union[Type, str]]] = None
316
+ """
317
+ A list/tuple of classes to inject into the generated module.
318
+
319
+ Accepts either live classes or strings. Live classes will have their source code
320
+ extracted with inspect.get - so they need to be standard python classes declared in a
321
+ source file (ie. the module they are contained in needs a ``__file__`` attr,
322
+ see: :func:`inspect.getsource` )
323
+ """
324
+ injected_fields: Optional[List[str]] = None
325
+ """
326
+ A list/tuple of field strings to inject into the base class.
327
+
328
+ Examples:
329
+
330
+ .. code-block:: python
331
+
332
+ injected_fields = (
333
+ 'object_id: Optional[str] = Field(None, description="Unique UUID for each object")',
334
+ )
335
+
336
+ """
337
+ imports: Optional[Dict[str, Union[None, Dict[str, str], List[Union[str, Dict[str, str]]]]]] = None
338
+ """
339
+ Additional imports to inject into generated module.
340
+
341
+ A dictionary mapping a module to a list of objects to import.
342
+ If the value of an entry is ``None`` , import the whole module.
343
+
344
+ Import Aliases:
345
+ If the value of a module import is a dictionary with a key "as",
346
+ or a class is specified as a dictionary with a "name" and "as",
347
+ then the import is renamed like "from module import class as renamedClass".
348
+
349
+ Examples:
350
+
351
+ .. code-block:: python
352
+
353
+ imports = {
354
+ 'typing': ['Dict', 'List', 'Union'],
355
+ 'types': None,
356
+ 'numpy': {'as': 'np'},
357
+ 'collections': [{'name': 'OrderedDict', 'as': 'odict'}]
358
+ }
359
+
360
+ becomes:
361
+
362
+ .. code-block:: python
363
+
364
+ from typing import (
365
+ Dict,
366
+ List,
367
+ Union
368
+ )
369
+ import types
370
+ import numpy as np
371
+ from collections import (
372
+ OrderedDict as odict
373
+ )
374
+
375
+ """
275
376
 
276
377
  # ObjectVars (identical to pythongen)
277
- gen_classvars: bool = field(default_factory=lambda: True)
278
- gen_slots: bool = field(default_factory=lambda: True)
279
- genmeta: bool = field(default_factory=lambda: False)
280
- emit_metadata: bool = field(default_factory=lambda: True)
378
+ gen_classvars: bool = True
379
+ gen_slots: bool = True
380
+ genmeta: bool = False
381
+ emit_metadata: bool = True
281
382
 
282
383
  def compile_module(self, **kwargs) -> ModuleType:
283
384
  """
@@ -525,12 +626,48 @@ class PydanticGenerator(OOCodeGenerator):
525
626
  return list(collection_keys)[0]
526
627
  return None
527
628
 
629
+ def _inline_as_simple_dict_with_value(self, slot_def: SlotDefinition, sv: SchemaView) -> Optional[str]:
630
+ """
631
+ Determine if a slot should be inlined as a simple dict with a value.
632
+
633
+ For example, if we have a class such as Prefix, with two slots prefix and expansion,
634
+ then an inlined list of prefixes can be serialized as:
635
+
636
+ .. code-block:: yaml
637
+
638
+ prefixes:
639
+ prefix1: expansion1
640
+ prefix2: expansion2
641
+ ...
642
+
643
+ Provided that the prefix slot is the identifier slot for the Prefix class.
644
+
645
+ TODO: move this to SchemaView
646
+
647
+ :param slot_def: SlotDefinition
648
+ :param sv: SchemaView
649
+ :return: str
650
+ """
651
+ if slot_def.inlined and not slot_def.inlined_as_list:
652
+ if slot_def.range in sv.all_classes():
653
+ id_slot = sv.get_identifier_slot(slot_def.range, use_key=True)
654
+ if id_slot is not None:
655
+ range_cls_slots = sv.class_induced_slots(slot_def.range)
656
+ if len(range_cls_slots) == 2:
657
+ non_id_slots = [slot for slot in range_cls_slots if slot.name != id_slot.name]
658
+ if len(non_id_slots) == 1:
659
+ value_slot = non_id_slots[0]
660
+ value_slot_range_type = sv.get_type(value_slot.range)
661
+ if value_slot_range_type is not None:
662
+ return _get_pyrange(value_slot_range_type, sv)
663
+ return None
664
+
528
665
  def serialize(self) -> str:
529
666
  if self.template_file is not None:
530
667
  with open(self.template_file) as template_file:
531
668
  template_obj = Template(template_file.read())
532
669
  else:
533
- template_obj = Template(default_template(self.pydantic_version, self.extra_fields))
670
+ template_obj = Template(default_template(self.pydantic_version, self.extra_fields, self.injected_classes))
534
671
 
535
672
  sv: SchemaView
536
673
  sv = self.schemaview
@@ -610,7 +747,14 @@ class PydanticGenerator(OOCodeGenerator):
610
747
  if s.inlined is False or collection_key is None or s.inlined_as_list is True:
611
748
  pyrange = f"List[{pyrange}]"
612
749
  else:
613
- pyrange = f"Dict[{collection_key}, {pyrange}]"
750
+ simple_dict_value = None
751
+ if len(slot_ranges) == 1:
752
+ simple_dict_value = self._inline_as_simple_dict_with_value(s, sv)
753
+ if simple_dict_value:
754
+ # inlining as simple dict
755
+ pyrange = f"Dict[str, {simple_dict_value}]"
756
+ else:
757
+ pyrange = f"Dict[{collection_key}, {pyrange}]"
614
758
  if not (s.required or s.identifier or s.key) and not s.designates_type:
615
759
  pyrange = f"Optional[{pyrange}]"
616
760
  ann = Annotation("python_range", pyrange)
@@ -624,6 +768,8 @@ class PydanticGenerator(OOCodeGenerator):
624
768
  metamodel_version=self.schema.metamodel_version,
625
769
  version=self.schema.version,
626
770
  class_isa_plus_mixins=self.get_class_isa_plus_mixins(),
771
+ imports=self.imports,
772
+ injected_fields=self.injected_fields,
627
773
  uses_numpy=uses_numpy,
628
774
  )
629
775
  return code
@@ -3,7 +3,7 @@ import logging
3
3
  import os
4
4
  import re
5
5
  from copy import copy
6
- from dataclasses import dataclass, field
6
+ from dataclasses import dataclass
7
7
  from types import ModuleType
8
8
  from typing import Callable, Dict, Iterator, List, Optional, Set, Tuple, Union
9
9
 
@@ -60,10 +60,10 @@ class PythonGenerator(Generator):
60
60
  uses_schemaloader = True
61
61
 
62
62
  # ObjectVars
63
- gen_classvars: bool = field(default_factory=lambda: True)
64
- gen_slots: bool = field(default_factory=lambda: True)
65
- genmeta: bool = field(default_factory=lambda: False)
66
- emit_metadata: bool = field(default_factory=lambda: True)
63
+ gen_classvars: bool = True
64
+ gen_slots: bool = True
65
+ genmeta: bool = False
66
+ emit_metadata: bool = True
67
67
 
68
68
  def __post_init__(self) -> None:
69
69
  self.sourcefile = self.schema
@@ -7,7 +7,7 @@ Generate a JSON LD representation of the model
7
7
 
8
8
  import os
9
9
  import urllib.parse as urlparse
10
- from dataclasses import dataclass, field
10
+ from dataclasses import dataclass
11
11
  from typing import List, Optional
12
12
 
13
13
  import click
@@ -33,7 +33,7 @@ class RDFGenerator(Generator):
33
33
  uses_schemaloader = True
34
34
 
35
35
  # ObjectVars
36
- emit_metadata: bool = field(default_factory=lambda: False)
36
+ emit_metadata: bool = False
37
37
  context: List[str] = None
38
38
 
39
39
  def _data(self, g: Graph) -> str:
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import os
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
 
5
5
  import click
6
6
  from linkml_runtime.utils.formatutils import underscore
@@ -31,7 +31,7 @@ LINK_ML_TYPES_NODE_ID = URIRef("http://www.w3.org/ns/shex#nonLiteral")
31
31
  @dataclass
32
32
  class ShaclGenerator(Generator):
33
33
  # ClassVars
34
- closed: bool = field(default_factory=lambda: True)
34
+ closed: bool = True
35
35
  """True means add 'sh:closed=true' to all shapes, except of mixin shapes and shapes, that have parents"""
36
36
 
37
37
  generatorname = os.path.basename(__file__)
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  import os
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
  from typing import Optional
5
5
 
6
6
  import click
@@ -123,12 +123,12 @@ class SQLTableGenerator(Generator):
123
123
 
124
124
  # ObjectVars
125
125
  use_inherits: bool = False # postgresql supports inheritance
126
- dialect: str = field(default_factory=lambda: "sqlite")
127
- inject_primary_keys: bool = field(default_factory=lambda: True)
128
- use_foreign_keys: bool = field(default_factory=lambda: True)
129
- rename_foreign_keys: bool = field(default_factory=lambda: False)
130
- direct_mapping: bool = field(default_factory=lambda: False)
131
- relative_slot_num: bool = field(default_factory=lambda: 0)
126
+ dialect: str = "sqlite"
127
+ inject_primary_keys: bool = True
128
+ use_foreign_keys: bool = True
129
+ rename_foreign_keys: bool = False
130
+ direct_mapping: bool = False
131
+ relative_slot_num: bool = False
132
132
 
133
133
  def serialize(self, **kwargs) -> str:
134
134
  return self.generate_ddl(**kwargs)
@@ -220,8 +220,12 @@ class SQLTableGenerator(Generator):
220
220
  schema = SchemaLoader(data=self.schema).resolve()
221
221
 
222
222
  if range in schema.classes:
223
- # FKs treated as Text
224
- return Text()
223
+ # FK type should be the same as the identifier of the foreign key
224
+ fk = SchemaView(schema).get_identifier_slot(range)
225
+ if fk:
226
+ return self.get_sql_range(fk, schema)
227
+ else:
228
+ return Text()
225
229
  if range in schema.enums:
226
230
  e = schema.enums[range]
227
231
  if e.permissible_values is not None:
@@ -5,7 +5,7 @@
5
5
  import os
6
6
  import sys
7
7
  from csv import DictWriter
8
- from dataclasses import dataclass, field
8
+ from dataclasses import dataclass
9
9
  from typing import Optional
10
10
 
11
11
  import click
@@ -26,7 +26,7 @@ class SummaryGenerator(Generator):
26
26
  dirname: str = None
27
27
  classtab: Optional[DictWriter] = None
28
28
  slottab: Optional[DictWriter] = None
29
- dialect: str = field(default_factory=lambda: "excel-tab")
29
+ dialect: str = "excel-tab"
30
30
 
31
31
  def visit_schema(self, **_) -> None:
32
32
  self.classtab = DictWriter(
@@ -3,7 +3,7 @@
3
3
  """
4
4
 
5
5
  import os
6
- from dataclasses import dataclass, field
6
+ from dataclasses import dataclass
7
7
 
8
8
  import click
9
9
  from linkml_runtime.utils.yamlutils import as_yaml
@@ -26,7 +26,7 @@ class YAMLGenerator(Generator):
26
26
  uses_schemaloader = True
27
27
 
28
28
  # ObjectVars
29
- validateonly: bool = field(default_factory=lambda: False)
29
+ validateonly: bool = False
30
30
 
31
31
  def serialize(self, validateonly: bool = False, **kwargs) -> str:
32
32
  if validateonly:
@@ -5,7 +5,7 @@ https://yuml.me/diagram/scruffy/class/samples
5
5
  """
6
6
 
7
7
  import os
8
- from dataclasses import dataclass, field
8
+ from dataclasses import dataclass
9
9
  from typing import Callable, List, Optional, Set, cast
10
10
 
11
11
  import click
@@ -14,6 +14,7 @@ from linkml_runtime.linkml_model.meta import ClassDefinition, ClassDefinitionNam
14
14
  from linkml_runtime.utils.formatutils import camelcase, underscore
15
15
  from rdflib import Namespace
16
16
 
17
+ from linkml import REQUESTS_TIMEOUT
17
18
  from linkml.utils.generator import Generator, shared_arguments
18
19
 
19
20
  yuml_is_a = "^-"
@@ -49,7 +50,7 @@ class YumlGenerator(Generator):
49
50
  classes: Set[ClassDefinitionName] = None
50
51
  directory: Optional[str] = None
51
52
  diagram_name: Optional[str] = None
52
- load_image: bool = field(default_factory=lambda: True)
53
+ load_image: bool = True
53
54
 
54
55
  def visit_schema(
55
56
  self,
@@ -95,10 +96,10 @@ class YumlGenerator(Generator):
95
96
  payload = "dsl_text=" + (",".join(yumlclassdef))
96
97
  payload = payload.replace("%3F", "?").replace("%2B", "+")
97
98
  url = "https://yuml.me/diagram/plain/class/"
98
- resp = requests.post(url, data=payload)
99
+ resp = requests.post(url, data=payload, timeout=REQUESTS_TIMEOUT)
99
100
  if resp.ok:
100
101
  filename = resp.text.strip().replace(".svg", file_suffix)
101
- resp = requests.get(f"https://yuml.me/{filename}", stream=True)
102
+ resp = requests.get(f"https://yuml.me/{filename}", stream=True, timeout=REQUESTS_TIMEOUT)
102
103
  with open(self.output_file_name, "wb") as f:
103
104
  for chunk in resp.iter_content(chunk_size=2048):
104
105
  f.write(chunk)
@@ -140,11 +140,11 @@ class RelationalModelTransformer:
140
140
  """
141
141
 
142
142
  schemaview: SchemaView = None
143
- # dialect: str = field(default_factory=lambda : 'sqlite')
144
- skip_tree_root: bool = field(default_factory=lambda: False)
145
- skip_abstract: bool = field(default_factory=lambda: True)
146
- skip_mixins: bool = field(default_factory=lambda: True)
147
- join_table_separator: str = field(default_factory=lambda: "_")
143
+ # dialect: str = 'sqlite'
144
+ skip_tree_root: bool = False
145
+ skip_abstract: bool = True
146
+ skip_mixins: bool = True
147
+ join_table_separator: str = "_"
148
148
  foreign_key_policy: ForeignKeyPolicy = field(default_factory=lambda: ForeignKeyPolicy.INJECT_FK_FOR_NESTED)
149
149
 
150
150
  def transform(self, tgt_schema_name: str = None, top_class: ClassDefinitionName = None) -> TransformationResult:
linkml/utils/converter.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import logging
2
2
  import os
3
3
  import sys
4
- from typing import List
5
4
 
6
5
  import click
7
6
  from linkml_runtime.linkml_model import Prefix
@@ -77,7 +76,7 @@ def cli(
77
76
  output=None,
78
77
  input_format=None,
79
78
  output_format=None,
80
- prefix: List = [],
79
+ prefix=None,
81
80
  target_class_from_path=None,
82
81
  schema=None,
83
82
  validate=None,
@@ -98,6 +97,8 @@ def cli(
98
97
 
99
98
  For more information, see https://linkml.io/linkml/data/index.html
100
99
  """
100
+ if prefix is None:
101
+ prefix = []
101
102
  if module is None:
102
103
  if schema is None:
103
104
  raise Exception("must pass one of module OR schema")
linkml/utils/generator.py CHANGED
@@ -124,7 +124,7 @@ class Generator(metaclass=abc.ABCMeta):
124
124
 
125
125
  file_extension: ClassVar[str] = None
126
126
 
127
- metadata: bool = field(default_factory=lambda: True)
127
+ metadata: bool = True
128
128
  """True means include date, generator, etc. information in source header if appropriate"""
129
129
 
130
130
  useuris: Optional[bool] = None
@@ -133,7 +133,7 @@ class Generator(metaclass=abc.ABCMeta):
133
133
  log_level: int = DEFAULT_LOG_LEVEL_INT
134
134
  """Logging level, 0 is minimum"""
135
135
 
136
- mergeimports: Optional[bool] = field(default_factory=lambda: True)
136
+ mergeimports: Optional[bool] = True
137
137
  """True means merge non-linkml sources into importing package. False means separate packages"""
138
138
 
139
139
  source_file_date: Optional[str] = None
@@ -465,7 +465,7 @@ class Generator(metaclass=abc.ABCMeta):
465
465
  """Return an ordered list of ancestor names for the supplied slot or class
466
466
 
467
467
  @param element: Slot or class name or definition
468
- @return: Ordered list of of ancestor names
468
+ @return: Ordered list of ancestor names
469
469
  """
470
470
  return [element.name] + ([] if element.is_a is None else self.ancestors(self.parent(element)))
471
471
 
@@ -620,7 +620,7 @@ class Generator(metaclass=abc.ABCMeta):
620
620
 
621
621
  def slot_range_path(self, slot_or_name: Union[str, SlotDefinition]) -> List[str]:
622
622
  """
623
- Return a ordered list of slot ranges from distal to proximal
623
+ Return an ordered list of slot ranges from distal to proximal
624
624
 
625
625
  :param slot_or_name: slot whose range is being typed
626
626
  :return: ordered list of types from base type forward
linkml/utils/sqlutils.py CHANGED
@@ -18,10 +18,11 @@ from linkml_runtime.utils.formatutils import underscore
18
18
  from linkml_runtime.utils.introspection import package_schemaview
19
19
  from linkml_runtime.utils.yamlutils import YAMLRoot
20
20
  from pydantic import BaseModel
21
- from sqlalchemy import StaticPool, create_engine
21
+ from sqlalchemy import create_engine
22
22
  from sqlalchemy.engine import Engine
23
23
  from sqlalchemy.ext.associationproxy import _AssociationCollection
24
24
  from sqlalchemy.orm import sessionmaker
25
+ from sqlalchemy.pool import StaticPool
25
26
 
26
27
  from linkml._version import __version__
27
28
  from linkml.generators.pythongen import PythonGenerator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkml
3
- Version: 1.7.2
3
+ Version: 1.7.4
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
@@ -22,7 +22,6 @@ Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.8
23
23
  Classifier: Programming Language :: Python :: 3.9
24
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
- Provides-Extra: docs
26
25
  Requires-Dist: antlr4-python3-runtime (>=4.9.0,<4.10)
27
26
  Requires-Dist: click (>=7.0)
28
27
  Requires-Dist: graphviz (>=0.10.1)
@@ -1,4 +1,4 @@
1
- linkml/__init__.py,sha256=na-VVMb-hXm-6jDPgs-arvkOMx1LAryNDxnnfVwkKe0,3164
1
+ linkml/__init__.py,sha256=jwtUdhwmquj-0fCR6VwPH5_RfSpuG94hLWdre_W_FD4,3327
2
2
  linkml/_version.py,sha256=udxv6OEqcE89DTVMYPtetXYg8IA8Sgc6yW26-6f8C3M,310
3
3
  linkml/generators/PythonGenNotes.md,sha256=wb9BPLLhF6378OKLbwSBAwmniLpwrcT5_bbfCHfLme8,51006
4
4
  linkml/generators/README.md,sha256=RMzT8EblC_GEdPy5WyfXHDBXlFI6k6mz3Cx2sdpcyWI,4438
@@ -16,33 +16,33 @@ linkml/generators/docgen/schema.md.jinja2,sha256=xlENfnzNRYgPT_0tdqNFxgklVM4Qf5B
16
16
  linkml/generators/docgen/slot.md.jinja2,sha256=XVd0M4gKx9Q2fONcsUGBRj_bJivyN4P9jhj9IO496jQ,2817
17
17
  linkml/generators/docgen/subset.md.jinja2,sha256=fTNIpAkml5RKFbbtLore3IAzFN1cISVsyL1ru2-Z4oA,2665
18
18
  linkml/generators/docgen/type.md.jinja2,sha256=QmCMJZrFwP33eHkggBVtypbyrxTb-XZn9vHOYojVaYk,635
19
- linkml/generators/docgen.py,sha256=Kwg4ZIXL2e9G-q-_CUoj8Bgnpyyvvh5fKPnseDcTK04,33755
19
+ linkml/generators/docgen.py,sha256=265bWbIkH4z5Cc7RLmyMTi2YR6hXAPBEdo5t1dqALYk,33476
20
20
  linkml/generators/dotgen.py,sha256=kzp1EYtF8bBqOuycJokDmsvHVDVkkW-J-6-MiUhwJH0,5013
21
- linkml/generators/erdiagramgen.py,sha256=Gu-_nhLuEPTsYYaoV6tNS1V6cZ2dNJdm6YwxC0VGl7g,10315
22
- linkml/generators/excelgen.py,sha256=OhVzuQaDESYpAGR8Zv13hiWlDDJA8ugtSZatBJH0hzA,7737
23
- linkml/generators/golanggen.py,sha256=Dnl7dhmb1AIK3Is7KRaUbxPd3kBTjWuspFqardiBTJ8,5751
21
+ linkml/generators/erdiagramgen.py,sha256=xCnxIldDYZ7xnQ-vLaXlH3FH8MH3cxu-E0j8it-lyJE,10153
22
+ linkml/generators/excelgen.py,sha256=VsvdaGAOcNZ3qPLq-3lycGe_atG6B3hid3WMCV99XZI,7668
23
+ linkml/generators/golanggen.py,sha256=lGP0wDU6QwLjfiUDpTLFvJsnaDGKxOyQLizlz2lGfPc,5775
24
24
  linkml/generators/golrgen.py,sha256=OUBYRWicP7G7lrPu1VrxumbVpx3CBJal-o2imyeP05M,3437
25
25
  linkml/generators/graphqlgen.py,sha256=6qZpI0rwg3ypsv_KrLVzXgdsJfR8LNPqgMwaRwzwnDs,2151
26
26
  linkml/generators/javagen/example_template.java.jinja2,sha256=ec4CVTv_0zS7V5Y-1E6H4lRraya10gfX7BEMBlu38X4,444
27
27
  linkml/generators/javagen/java_record_template.jinja2,sha256=OQZffLSy_xR3FIhQMltvrYyVeut7l2Q-tzK7AOiVmWs,1729
28
- linkml/generators/javagen.py,sha256=l3NUWCQMtJOTOIuao237hLYlILliLilVQXxdlJ5haIQ,5455
29
- linkml/generators/jsonldcontextgen.py,sha256=nLcASMmxoT57dRj1A9W5qqwg-5TDpsGblMb9gt940Zs,7871
28
+ linkml/generators/javagen.py,sha256=KxwupMztyCRHcSsbtTnOovuj1WamsAny0mxbYWvTiDs,5324
29
+ linkml/generators/jsonldcontextgen.py,sha256=RQFBgNjWMdnjf0j8S_k1lyMauI9Ia5Ao0ruuFjLwhdA,7886
30
30
  linkml/generators/jsonldgen.py,sha256=BtPXLYbnXTXorUcoe6y4DL0xa-TPjHOvtXdhv-ppW3I,7656
31
- linkml/generators/jsonschemagen.py,sha256=osol3CJBNB_YgZtvyryWywzpESXHfpDwn_5igvEMBF4,27524
31
+ linkml/generators/jsonschemagen.py,sha256=XOsYIrpA6BwtAcfh8GNGduIjpuPAsF2f_PQ1mghj_WU,27455
32
32
  linkml/generators/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- linkml/generators/linkmlgen.py,sha256=QhIPA1v2g_g5fien3ZKN-L6TkDk3t7puVFrcoEnwkwY,3540
34
- linkml/generators/markdowngen.py,sha256=LU4Z8k9ag6aDURQKZAsEa_p9PEUGWsc_oMLJRx_pamI,32964
33
+ linkml/generators/linkmlgen.py,sha256=1_Kt_7rD42WvCTjq0yaq1Of7jEDZR_uusyzAT-qWMHk,3471
34
+ linkml/generators/markdowngen.py,sha256=dDMyusNXLvM2raIW-_vd2AQBhDHn0P_rMeDq3QFuacs,32926
35
35
  linkml/generators/namespacegen.py,sha256=vVcIyM0zlKd7XRvtdzwTwHjG4Pg49801gy4FUmjJlqQ,6450
36
- linkml/generators/oocodegen.py,sha256=l-5zck_NNAUxJiApJrnDPkqxCv3b6v5s4hC_smelszU,7620
37
- linkml/generators/owlgen.py,sha256=aF7dufP2WqaYmbG8W41_6Dx0j3u654NmuaXvHAY1aj4,52476
38
- linkml/generators/plantumlgen.py,sha256=jN40_1_0_YI6Dir8wbxdVm-Upy6rxIYLFSNW-V0WKFY,14871
36
+ linkml/generators/oocodegen.py,sha256=cWjQSFJmhrnRRsHqOa9dOks0k-QogrP97m5lEkLRxdY,7738
37
+ linkml/generators/owlgen.py,sha256=Oo3ACE5BXRbQU1p4XhyYhP4JQgAW4w2nmNZ591FWkVM,53142
38
+ linkml/generators/plantumlgen.py,sha256=tk-_XJtBA5EqYJSUTc3bdMdCwqlC-rc9VYO9A2V_HpM,14895
39
39
  linkml/generators/prefixmapgen.py,sha256=-IGKre3rRxCdNs0BP3Oo7Wzv8edeUQXkjjwN7od3qjU,4627
40
40
  linkml/generators/projectgen.py,sha256=g3JR2oXPM_QXhWUGukP9ts1P7tqxIeABaRdv130gbo4,9578
41
- linkml/generators/protogen.py,sha256=9YfxBZkQdBWwsUbstxEUR4xRWNuAKSfz9zXPhgIYePU,2328
42
- linkml/generators/pydanticgen.py,sha256=Ak0bpRoQsirnnBd091NiJvMZ-2d0qaQbhxADHy5ocwY,25529
43
- linkml/generators/pythongen.py,sha256=_SGYR_y-k67b91lWLtQcCU2vNRv19hrnRK9vQ_6_sZM,52560
44
- linkml/generators/rdfgen.py,sha256=94SRun1DDJwMiKVJU-BpU0jwhac2GW7gv4Gaug7iJ6o,2694
45
- linkml/generators/shaclgen.py,sha256=H63DCUjTGYdrKRG5j7Ep8sOgFTXqmaEkH8Rne8ANvFo,8724
41
+ linkml/generators/protogen.py,sha256=5UxThsFDVyDTzzTDh77Z0anx4-tLgz8kQQ-e7ywIqwI,2290
42
+ linkml/generators/pydanticgen.py,sha256=syiqMBBiGWwT_ZD5KLstGGMdh4d2fNQ3o2qZRfQLtqs,30539
43
+ linkml/generators/pythongen.py,sha256=JCFuGishyoBx75sGFL2zWlHj-qsyBizyZIc_jqpzdTU,52429
44
+ linkml/generators/rdfgen.py,sha256=L6F08iDUqVemXXrRbJmcOxvJTt14hR0oo8WLoqf4npw,2656
45
+ linkml/generators/shaclgen.py,sha256=jxQjQ-iT2SYpLso3aIyBtqaVVPvZflrVzWaNA7nxQa0,8686
46
46
  linkml/generators/shexgen.py,sha256=VVlSrGCighLf0YSStK_VeMnCK0imAL4BJNDRVTpUFkw,9859
47
47
  linkml/generators/sparqlgen.py,sha256=xIT4abjYTjPvAjczZ2mkqfap5z8-AImK_jaCvgZyRGs,6120
48
48
  linkml/generators/sqlalchemy/__init__.py,sha256=mb9AC1rIFkSiNZhhG0TAk45ol9PjS1XvsrvCjgfVUpQ,249
@@ -50,14 +50,14 @@ linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py,sha256=X_Ws1NUBi
50
50
  linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py,sha256=u4ZpponG1h6XROrOHGOf_0H2e6xL1_s8twAOA-gx94A,1622
51
51
  linkml/generators/sqlalchemygen.py,sha256=XjvyCYr9h0EsFaKy4y-lMXunYw4dnk9vSpwlPjZK8gU,9186
52
52
  linkml/generators/sqlddlgen.py,sha256=ickgQovcWunsBRMpHBDTGxGlZKU9kfExb-XQPBS6qPs,18437
53
- linkml/generators/sqltablegen.py,sha256=h_zVuNC8huRzzTa9nSHNWBxq-4TuLq7nR5nZfpDnWiM,11481
53
+ linkml/generators/sqltablegen.py,sha256=yaGdnl1kbovf9b4Qi6dx5VpRlBfy4PX1dtHsXtvg6qQ,11494
54
54
  linkml/generators/sssomgen.py,sha256=yur3q7so9uwIELWZaZRzkJwNbz_ppBL7IQki9XLIM3k,6879
55
55
  linkml/generators/string_template.md,sha256=kRcfic6entgIaJdpSg6GF3jcjC9wbKsCVM6wVT2qipc,1788
56
- linkml/generators/summarygen.py,sha256=67XKbzM_aCwJXEpgtsffWf7RGljeHJYE8dCIjMHXlH8,2925
56
+ linkml/generators/summarygen.py,sha256=crH_Hegd4Z7G7byUtgyXoP2XtG_4iblzZsu_pE4aQrk,2887
57
57
  linkml/generators/terminusdbgen.py,sha256=_po9KnOz6Uoctb9Y4fJuU_voW4uA5pepvZTmHLQ2_DE,4470
58
58
  linkml/generators/typescriptgen.py,sha256=VDJ-97jk7zqYx6XlnIcxZmY8mCv885T7D2brKJHaihI,8565
59
- linkml/generators/yamlgen.py,sha256=0hYw2hW4A92As9x3k_7T7y05y25unfK2v3NPFfrtdbw,1652
60
- linkml/generators/yumlgen.py,sha256=nIwOYCCBWPnS8xk2y922qGlYSpoHNtMQcdB4L716iqo,12146
59
+ linkml/generators/yamlgen.py,sha256=PKssrY5VHpdbOU54PVwLVLbsRqHwoOgOImlMb6DVcXM,1614
60
+ linkml/generators/yumlgen.py,sha256=lnHcLY0VwlU_i8QporSmwR62CXSV4aOCXKxRDw5AxUk,12196
61
61
  linkml/linter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
62
  linkml/linter/cli.py,sha256=BpQiETcRfQlZsI1-JALyU9wXPgPOm_KE_n11p0iJaC8,4494
63
63
  linkml/linter/config/datamodel/.linkmllint.yaml,sha256=40rNhcL35FXQSjlVBMWnyPgplwEUqFT_sJmeZqUzxMw,292
@@ -79,15 +79,15 @@ linkml/reporting/model.py,sha256=-10yNfk8wuRC48ZI-akrWvtlJ9a6RYWET2TzlZV3XXo,862
79
79
  linkml/transformers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
80
  linkml/transformers/logical_model_transformer.py,sha256=1ZSB-HBoI0E2X2NV9TSgbTghp2GO4HQA27JaK0XiPBE,26510
81
81
  linkml/transformers/model_transformer.py,sha256=tK_MpRDI-q2qfe8KHT6qJHP8ZruKjYx1FcM-Fnjse-E,678
82
- linkml/transformers/relmodel_transformer.py,sha256=hRUVtH4gylDssOXoWvVxTetF9ESbITrAZOFu53b_Eg0,17836
82
+ linkml/transformers/relmodel_transformer.py,sha256=STQ4ALoJpPKW5-soTVcErHof_1kEDJEEZ1EJrzneql4,17680
83
83
  linkml/transformers/schema_renamer.py,sha256=Cr18TyktX64b5iFh5V6R_ILPVzXjbDYVDDZQyqFiAv8,5271
84
84
  linkml/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
85
  linkml/utils/cli_utils.py,sha256=MdVbox1qr6kDUHUCWAmFhV-D6ebs_nn8vVwB8KDQfew,742
86
- linkml/utils/converter.py,sha256=rdhCI7Tsjddr3o1rVBfMq5gQubk_GE6fqlBBmyxI5_M,6270
86
+ linkml/utils/converter.py,sha256=snAF-pgZBSi4ANiaKXxqtZk5w3qonJjTfI4X5OVLmUE,6283
87
87
  linkml/utils/datautils.py,sha256=QlbzwXykh5Fphfe5KxPo6_ekXfniLbHiEGJtLWjUrvY,3742
88
88
  linkml/utils/datavalidator.py,sha256=kBdWaVi8IZT1bOwEJgJYx-wZAb_PTBObB9nHpYORfKA,472
89
89
  linkml/utils/execute_tutorial.py,sha256=T4kHTSyz3ItJGEUZxVjR-3yLVKnOr5Ix4NMGE47-IuE,6912
90
- linkml/utils/generator.py,sha256=fIoBa5zVXXOpW7ibIRCh0FADycdSXcrH98fMuzq6sng,38271
90
+ linkml/utils/generator.py,sha256=YB2HXb9_aJx284xHnVq-glVgTtvWnBaE-yGCJXZ6nFM,38207
91
91
  linkml/utils/helpers.py,sha256=yR8n4zFA5wPcYC7xzRuNF3wO16vG80v6j7DM3qTNmIc,447
92
92
  linkml/utils/ifabsent_functions.py,sha256=C2mllfh7aIZgVqqJjN5nydurVUk0hV62Wy7uVMYfPDg,5801
93
93
  linkml/utils/logictools.py,sha256=GSmBiobC49TcQjE08RtXEE3JwJEOV7eEREio25uJiFs,21184
@@ -97,7 +97,7 @@ linkml/utils/schema_builder.py,sha256=WLSit3J4lTifaFLLWTwjqIRiTru1pqvTIUuC1TrxS6
97
97
  linkml/utils/schema_fixer.py,sha256=ajsxpwD4yMjDk1iDtoKJTsa34SIqGshWxlnSNXVZ52w,16745
98
98
  linkml/utils/schemaloader.py,sha256=bBSTqimMDTFH2FcKtRz99dKNJzV_myPsZSkIFp_6-A0,46421
99
99
  linkml/utils/schemasynopsis.py,sha256=jKf5ZJxpNgSZ5x9oAcdGO3m1IwzcIU2Ni1ugm0SQq1g,18447
100
- linkml/utils/sqlutils.py,sha256=86XeEbfY0Dk-EObw4q5-dxyzSeBtmIhjqqyDcR8ALS0,16591
100
+ linkml/utils/sqlutils.py,sha256=FPUA6Smn3FogE97TZZZtGNhaMK9kpC-qJ5Ylo1mg9l8,16618
101
101
  linkml/utils/typereferences.py,sha256=8Yfuz9-HAwOPoJLbIcO_sY9zf32hvPRzGeSOzECfMWA,2232
102
102
  linkml/utils/validation.py,sha256=eLw1-d8x3N1V14bSc6H_mJJXo59ryKvvUIBcOJ1dVMw,1438
103
103
  linkml/validator/__init__.py,sha256=djKc1IyxGKvVYaX5jSxsqjfcEYaw3rFgKbFJxI2wDNk,5002
@@ -125,8 +125,8 @@ linkml/workspaces/datamodel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
125
125
  linkml/workspaces/datamodel/workspaces.py,sha256=4HdkqweGNfMPqnB1_Onc9DcTfkhoagTRcqruh08nRoI,14905
126
126
  linkml/workspaces/datamodel/workspaces.yaml,sha256=EjVrwPpeRZqJRjuGyyDRxxFzuv55SiLIXPBRUG6HStU,4233
127
127
  linkml/workspaces/example_runner.py,sha256=OmC_yZLIb4KXGQrstBVZL0UAQ9ZAaraguQF0RSf-snk,11611
128
- linkml-1.7.2.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
129
- linkml-1.7.2.dist-info/entry_points.txt,sha256=za8r49Z5gcz3rAYTZLbxw5EPZr1rGuxSe1uiRUpf8R0,2143
130
- linkml-1.7.2.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
131
- linkml-1.7.2.dist-info/METADATA,sha256=2c6xc6B8gzMFAwrOe8soo7lLERpNDNYnCct9OK3-zcQ,3484
132
- linkml-1.7.2.dist-info/RECORD,,
128
+ linkml-1.7.4.dist-info/METADATA,sha256=-EvbTFKzOQZ3HPP2-hd7LmWlELMPIF6ZUWqvGnPGoGs,3463
129
+ linkml-1.7.4.dist-info/WHEEL,sha256=vVCvjcmxuUltf8cYhJ0sJMRDLr1XsPuxEId8YDzbyCY,88
130
+ linkml-1.7.4.dist-info/LICENSE,sha256=kORMoywK6j9_iy0UvLR-a80P1Rvc9AOM4gsKlUNZABg,535
131
+ linkml-1.7.4.dist-info/entry_points.txt,sha256=za8r49Z5gcz3rAYTZLbxw5EPZr1rGuxSe1uiRUpf8R0,2143
132
+ linkml-1.7.4.dist-info/RECORD,,
File without changes