linkml 1.7.3__tar.gz → 1.7.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. {linkml-1.7.3 → linkml-1.7.4}/PKG-INFO +1 -1
  2. {linkml-1.7.3 → linkml-1.7.4}/linkml/__init__.py +7 -0
  3. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/jsonldcontextgen.py +2 -1
  4. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/owlgen.py +30 -16
  5. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/plantumlgen.py +2 -1
  6. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/pydanticgen.py +108 -6
  7. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/yumlgen.py +3 -2
  8. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/converter.py +3 -2
  9. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/generator.py +2 -2
  10. {linkml-1.7.3 → linkml-1.7.4}/pyproject.toml +1 -1
  11. {linkml-1.7.3 → linkml-1.7.4}/setup.py +1 -1
  12. {linkml-1.7.3 → linkml-1.7.4}/LICENSE +0 -0
  13. {linkml-1.7.3 → linkml-1.7.4}/README.md +0 -0
  14. {linkml-1.7.3 → linkml-1.7.4}/linkml/_version.py +0 -0
  15. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/PythonGenNotes.md +0 -0
  16. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/README.md +0 -0
  17. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/__init__.py +0 -0
  18. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/common/__init__.py +0 -0
  19. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/common/type_designators.py +0 -0
  20. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/csvgen.py +0 -0
  21. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/class.md.jinja2 +0 -0
  22. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/class_diagram.md.jinja2 +0 -0
  23. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/common_metadata.md.jinja2 +0 -0
  24. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/enum.md.jinja2 +0 -0
  25. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/index.md.jinja2 +0 -0
  26. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/index.tex.jinja2 +0 -0
  27. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/schema.md.jinja2 +0 -0
  28. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/slot.md.jinja2 +0 -0
  29. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/subset.md.jinja2 +0 -0
  30. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen/type.md.jinja2 +0 -0
  31. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/docgen.py +0 -0
  32. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/dotgen.py +0 -0
  33. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/erdiagramgen.py +0 -0
  34. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/excelgen.py +0 -0
  35. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/golanggen.py +0 -0
  36. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/golrgen.py +0 -0
  37. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/graphqlgen.py +0 -0
  38. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/javagen/example_template.java.jinja2 +0 -0
  39. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/javagen/java_record_template.jinja2 +0 -0
  40. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/javagen.py +0 -0
  41. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/jsonldgen.py +0 -0
  42. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/jsonschemagen.py +0 -0
  43. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/legacy/__init__.py +0 -0
  44. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/linkmlgen.py +0 -0
  45. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/markdowngen.py +0 -0
  46. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/namespacegen.py +0 -0
  47. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/oocodegen.py +0 -0
  48. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/prefixmapgen.py +0 -0
  49. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/projectgen.py +0 -0
  50. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/protogen.py +0 -0
  51. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/pythongen.py +0 -0
  52. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/rdfgen.py +0 -0
  53. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/shaclgen.py +0 -0
  54. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/shexgen.py +0 -0
  55. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sparqlgen.py +0 -0
  56. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sqlalchemy/__init__.py +0 -0
  57. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +0 -0
  58. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +0 -0
  59. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sqlalchemygen.py +0 -0
  60. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sqlddlgen.py +0 -0
  61. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sqltablegen.py +0 -0
  62. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/sssomgen.py +0 -0
  63. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/string_template.md +0 -0
  64. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/summarygen.py +0 -0
  65. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/terminusdbgen.py +0 -0
  66. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/typescriptgen.py +0 -0
  67. {linkml-1.7.3 → linkml-1.7.4}/linkml/generators/yamlgen.py +0 -0
  68. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/__init__.py +0 -0
  69. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/cli.py +0 -0
  70. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/config/datamodel/.linkmllint.yaml +0 -0
  71. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/config/datamodel/__init__.py +0 -0
  72. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/config/datamodel/config.py +0 -0
  73. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/config/datamodel/config.yaml +0 -0
  74. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/config/default.yaml +0 -0
  75. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/config/recommended.yaml +0 -0
  76. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/formatters/__init__.py +0 -0
  77. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/formatters/formatter.py +0 -0
  78. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/formatters/json_formatter.py +0 -0
  79. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/formatters/markdown_formatter.py +0 -0
  80. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/formatters/terminal_formatter.py +0 -0
  81. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/formatters/tsv_formatter.py +0 -0
  82. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/linter.py +0 -0
  83. {linkml-1.7.3 → linkml-1.7.4}/linkml/linter/rules.py +0 -0
  84. {linkml-1.7.3 → linkml-1.7.4}/linkml/reporting/__init__.py +0 -0
  85. {linkml-1.7.3 → linkml-1.7.4}/linkml/reporting/model.py +0 -0
  86. {linkml-1.7.3 → linkml-1.7.4}/linkml/transformers/__init__.py +0 -0
  87. {linkml-1.7.3 → linkml-1.7.4}/linkml/transformers/logical_model_transformer.py +0 -0
  88. {linkml-1.7.3 → linkml-1.7.4}/linkml/transformers/model_transformer.py +0 -0
  89. {linkml-1.7.3 → linkml-1.7.4}/linkml/transformers/relmodel_transformer.py +0 -0
  90. {linkml-1.7.3 → linkml-1.7.4}/linkml/transformers/schema_renamer.py +0 -0
  91. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/__init__.py +0 -0
  92. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/cli_utils.py +0 -0
  93. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/datautils.py +0 -0
  94. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/datavalidator.py +0 -0
  95. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/execute_tutorial.py +0 -0
  96. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/helpers.py +0 -0
  97. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/ifabsent_functions.py +0 -0
  98. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/logictools.py +0 -0
  99. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/mergeutils.py +0 -0
  100. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/rawloader.py +0 -0
  101. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/schema_builder.py +0 -0
  102. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/schema_fixer.py +0 -0
  103. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/schemaloader.py +0 -0
  104. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/schemasynopsis.py +0 -0
  105. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/sqlutils.py +0 -0
  106. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/typereferences.py +0 -0
  107. {linkml-1.7.3 → linkml-1.7.4}/linkml/utils/validation.py +0 -0
  108. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/__init__.py +0 -0
  109. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/cli.py +0 -0
  110. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/loaders/__init__.py +0 -0
  111. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/loaders/delimited_file_loader.py +0 -0
  112. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/loaders/json_loader.py +0 -0
  113. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/loaders/loader.py +0 -0
  114. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/loaders/passthrough_loader.py +0 -0
  115. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/loaders/yaml_loader.py +0 -0
  116. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/plugins/__init__.py +0 -0
  117. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/plugins/jsonschema_validation_plugin.py +0 -0
  118. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/plugins/pydantic_validation_plugin.py +0 -0
  119. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/plugins/recommended_slots_plugin.py +0 -0
  120. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/plugins/shacl_validation_plugin.py +0 -0
  121. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/plugins/validation_plugin.py +0 -0
  122. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/report.py +0 -0
  123. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/validation_context.py +0 -0
  124. {linkml-1.7.3 → linkml-1.7.4}/linkml/validator/validator.py +0 -0
  125. {linkml-1.7.3 → linkml-1.7.4}/linkml/validators/__init__.py +0 -0
  126. {linkml-1.7.3 → linkml-1.7.4}/linkml/validators/jsonschemavalidator.py +0 -0
  127. {linkml-1.7.3 → linkml-1.7.4}/linkml/validators/sparqlvalidator.py +0 -0
  128. {linkml-1.7.3 → linkml-1.7.4}/linkml/workspaces/__init__.py +0 -0
  129. {linkml-1.7.3 → linkml-1.7.4}/linkml/workspaces/datamodel/__init__.py +0 -0
  130. {linkml-1.7.3 → linkml-1.7.4}/linkml/workspaces/datamodel/workspaces.py +0 -0
  131. {linkml-1.7.3 → linkml-1.7.4}/linkml/workspaces/datamodel/workspaces.yaml +0 -0
  132. {linkml-1.7.3 → linkml-1.7.4}/linkml/workspaces/example_runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkml
3
- Version: 1.7.3
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
@@ -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
+ """
@@ -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
@@ -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:
@@ -598,11 +601,19 @@ class OwlSchemaGenerator(Generator):
598
601
  )
599
602
  )
600
603
  if slot.exactly_one_of:
601
- owl_exprs.append(
602
- self._exactly_one_of(
603
- [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,
604
610
  )
605
- )
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))
606
617
  range = slot.range
607
618
  # if not range and not owl_exprs:
608
619
  # range = sv.schema.default_range
@@ -975,11 +986,14 @@ class OwlSchemaGenerator(Generator):
975
986
  def _metaslot_uri(self, name: str) -> URIRef:
976
987
  return URIRef("https://w3id.org/linkml/" + name)
977
988
 
978
- 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]]:
979
992
  if not exprs:
980
993
  raise ValueError("Must pass at least one")
981
994
  neg_expr = BNode()
982
- owl_types = self._get_owltypes(set(), exprs)
995
+ if not owl_types:
996
+ owl_types = self._get_owltypes(set(), exprs)
983
997
  complement_predicate = OWL.complementOf
984
998
  if len(owl_types) == 1:
985
999
  if RDFS.Literal in owl_types:
@@ -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
 
@@ -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,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 = """
@@ -62,7 +65,26 @@ if sys.version_info >= (3, 8):
62
65
  else:
63
66
  from typing_extensions import Literal
64
67
 
65
-
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 %}
66
88
  metamodel_version = "{{metamodel_version}}"
67
89
  version = "{{version if version else None}}"
68
90
  """
@@ -79,7 +101,6 @@ class ConfiguredBaseModel(WeakRefShimBaseModel,
79
101
  extra = '{extra_fields}',
80
102
  arbitrary_types_allowed = True,
81
103
  use_enum_values = True):
82
- pass
83
104
  """
84
105
  else:
85
106
  template += f"""
@@ -90,9 +111,27 @@ class ConfiguredBaseModel(BaseModel):
90
111
  extra = '{extra_fields}',
91
112
  arbitrary_types_allowed=True,
92
113
  use_enum_values = True)
93
- pass
94
114
  """
95
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
+
96
135
  ### ENUMS ###
97
136
  template += """
98
137
  {% for e in enums.values() %}
@@ -273,6 +312,67 @@ class PydanticGenerator(OOCodeGenerator):
273
312
  template_file: str = None
274
313
  extra_fields: str = "forbid"
275
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
+ """
276
376
 
277
377
  # ObjectVars (identical to pythongen)
278
378
  gen_classvars: bool = True
@@ -567,7 +667,7 @@ class PydanticGenerator(OOCodeGenerator):
567
667
  with open(self.template_file) as template_file:
568
668
  template_obj = Template(template_file.read())
569
669
  else:
570
- 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))
571
671
 
572
672
  sv: SchemaView
573
673
  sv = self.schemaview
@@ -668,6 +768,8 @@ class PydanticGenerator(OOCodeGenerator):
668
768
  metamodel_version=self.schema.metamodel_version,
669
769
  version=self.schema.version,
670
770
  class_isa_plus_mixins=self.get_class_isa_plus_mixins(),
771
+ imports=self.imports,
772
+ injected_fields=self.injected_fields,
671
773
  uses_numpy=uses_numpy,
672
774
  )
673
775
  return code
@@ -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 = "^-"
@@ -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)
@@ -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")
@@ -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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "linkml"
3
- version = "1.7.3"
3
+ version = "1.7.4"
4
4
  description = "Linked Open Data Modeling Language"
5
5
  authors = [
6
6
  "Chris Mungall <cjmungall@lbl.gov>",
@@ -109,7 +109,7 @@ entry_points = \
109
109
 
110
110
  setup_kwargs = {
111
111
  'name': 'linkml',
112
- 'version': '1.7.3',
112
+ 'version': '1.7.4',
113
113
  'description': 'Linked Open Data Modeling Language',
114
114
  'long_description': '[![Pyversions](https://img.shields.io/pypi/pyversions/linkml.svg)](https://pypi.python.org/pypi/linkml)\n![](https://github.com/linkml/linkml/workflows/Build/badge.svg)\n[![PyPi](https://img.shields.io/pypi/v/linkml.svg)](https://pypi.python.org/pypi/linkml)\n[![badge](https://img.shields.io/badge/launch-binder-579ACA.svg)](https://mybinder.org/v2/gh/linkml/linkml/main?filepath=notebooks)\n[![DOI](https://zenodo.org/badge/13996/linkml/linkml.svg)](https://zenodo.org/badge/latestdoi/13996/linkml/linkml)\n[![PyPIDownloadsTotal](https://pepy.tech/badge/linkml)](https://pepy.tech/project/linkml)\n[![PyPIDownloadsMonth](https://img.shields.io/pypi/dm/linkml?logo=PyPI&color=blue)](https://pypi.org/project/linkml)\n[![codecov](https://codecov.io/gh/linkml/linkml/branch/main/graph/badge.svg?token=WNQNG986UN)](https://codecov.io/gh/linkml/linkml)\n\n\n# LinkML - Linked Data Modeling Language\n\nLinkML is a linked data modeling language following object-oriented and ontological principles. LinkML models are typically authored in YAML, and can be converted to other schema representation formats such as JSON or RDF.\n\nThis repo holds the tools for generating and working with LinkML. For the LinkML schema (metamodel), please see https://github.com/linkml/linkml-model\n\nThe complete documentation for LinkML can be found here:\n\n - [linkml.io/linkml](https://linkml.io/linkml)\n',
115
115
  'author': 'Chris Mungall',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes