linkml 1.5.6__py3-none-any.whl → 1.5.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. linkml/__init__.py +2 -6
  2. linkml/_version.py +1 -1
  3. linkml/generators/__init__.py +26 -5
  4. linkml/generators/common/type_designators.py +27 -22
  5. linkml/generators/csvgen.py +4 -10
  6. linkml/generators/docgen/class.md.jinja2 +7 -0
  7. linkml/generators/docgen/class_diagram.md.jinja2 +0 -6
  8. linkml/generators/docgen/subset.md.jinja2 +54 -13
  9. linkml/generators/docgen.py +92 -90
  10. linkml/generators/dotgen.py +5 -9
  11. linkml/generators/erdiagramgen.py +56 -51
  12. linkml/generators/excelgen.py +10 -16
  13. linkml/generators/golanggen.py +11 -21
  14. linkml/generators/golrgen.py +4 -13
  15. linkml/generators/graphqlgen.py +3 -11
  16. linkml/generators/javagen.py +8 -15
  17. linkml/generators/jsonldcontextgen.py +7 -36
  18. linkml/generators/jsonldgen.py +14 -12
  19. linkml/generators/jsonschemagen.py +177 -133
  20. linkml/generators/markdowngen.py +40 -89
  21. linkml/generators/namespacegen.py +1 -2
  22. linkml/generators/oocodegen.py +22 -25
  23. linkml/generators/owlgen.py +34 -49
  24. linkml/generators/prefixmapgen.py +5 -13
  25. linkml/generators/projectgen.py +7 -14
  26. linkml/generators/protogen.py +3 -5
  27. linkml/generators/pydanticgen.py +85 -73
  28. linkml/generators/pythongen.py +86 -154
  29. linkml/generators/rdfgen.py +5 -11
  30. linkml/generators/shaclgen.py +32 -18
  31. linkml/generators/shexgen.py +19 -24
  32. linkml/generators/sparqlgen.py +4 -12
  33. linkml/generators/sqlalchemy/__init__.py +3 -2
  34. linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +7 -7
  35. linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +3 -3
  36. linkml/generators/sqlalchemygen.py +29 -27
  37. linkml/generators/sqlddlgen.py +34 -26
  38. linkml/generators/sqltablegen.py +21 -21
  39. linkml/generators/sssomgen.py +11 -13
  40. linkml/generators/summarygen.py +2 -4
  41. linkml/generators/terminusdbgen.py +7 -19
  42. linkml/generators/typescriptgen.py +10 -18
  43. linkml/generators/yamlgen.py +0 -2
  44. linkml/generators/yumlgen.py +23 -71
  45. linkml/linter/cli.py +4 -11
  46. linkml/linter/config/datamodel/config.py +17 -47
  47. linkml/linter/linter.py +2 -4
  48. linkml/linter/rules.py +34 -48
  49. linkml/reporting/__init__.py +2 -0
  50. linkml/reporting/model.py +9 -24
  51. linkml/transformers/relmodel_transformer.py +20 -33
  52. linkml/transformers/schema_renamer.py +14 -10
  53. linkml/utils/converter.py +15 -13
  54. linkml/utils/datautils.py +6 -22
  55. linkml/utils/datavalidator.py +2 -2
  56. linkml/utils/execute_tutorial.py +10 -12
  57. linkml/utils/generator.py +73 -91
  58. linkml/utils/helpers.py +4 -2
  59. linkml/utils/ifabsent_functions.py +23 -15
  60. linkml/utils/mergeutils.py +19 -35
  61. linkml/utils/rawloader.py +2 -6
  62. linkml/utils/schema_builder.py +31 -19
  63. linkml/utils/schema_fixer.py +28 -18
  64. linkml/utils/schemaloader.py +44 -89
  65. linkml/utils/schemasynopsis.py +49 -72
  66. linkml/utils/sqlutils.py +40 -30
  67. linkml/utils/typereferences.py +9 -6
  68. linkml/utils/validation.py +4 -5
  69. linkml/validators/__init__.py +2 -0
  70. linkml/validators/jsonschemavalidator.py +28 -18
  71. linkml/validators/sparqlvalidator.py +5 -15
  72. linkml/workspaces/datamodel/workspaces.py +13 -30
  73. linkml/workspaces/example_runner.py +74 -67
  74. {linkml-1.5.6.dist-info → linkml-1.5.7.dist-info}/METADATA +1 -1
  75. linkml-1.5.7.dist-info/RECORD +109 -0
  76. linkml-1.5.6.dist-info/RECORD +0 -109
  77. {linkml-1.5.6.dist-info → linkml-1.5.7.dist-info}/LICENSE +0 -0
  78. {linkml-1.5.6.dist-info → linkml-1.5.7.dist-info}/WHEEL +0 -0
  79. {linkml-1.5.6.dist-info → linkml-1.5.7.dist-info}/entry_points.txt +0 -0
@@ -2,15 +2,19 @@ import os
2
2
  from contextlib import redirect_stdout
3
3
  from dataclasses import dataclass, field
4
4
  from io import StringIO
5
- from typing import Any, Callable, Dict, List, Optional, Set, TextIO, Union
5
+ from typing import Any, Callable, Dict, List, Optional, Set, Union
6
6
 
7
7
  import click
8
8
  from jsonasobj2 import JsonObj, values
9
- from linkml_runtime.linkml_model.meta import (ClassDefinition,
10
- ClassDefinitionName, Element,
11
- EnumDefinition, SchemaDefinition,
12
- SlotDefinition, SubsetDefinition,
13
- TypeDefinition)
9
+ from linkml_runtime.linkml_model.meta import (
10
+ ClassDefinition,
11
+ ClassDefinitionName,
12
+ Element,
13
+ EnumDefinition,
14
+ SlotDefinition,
15
+ SubsetDefinition,
16
+ TypeDefinition,
17
+ )
14
18
  from linkml_runtime.utils.formatutils import be, camelcase, underscore
15
19
 
16
20
  from linkml._version import __version__
@@ -30,7 +34,7 @@ class MarkdownGenerator(Generator):
30
34
  The markdown is suitable for deployment as a MkDocs or Sphinx site
31
35
  """
32
36
 
33
- #ClassVars
37
+ # ClassVars
34
38
  generatorname = os.path.basename(__file__)
35
39
  generatorversion = "0.2.1"
36
40
  directory_output = True
@@ -71,7 +75,7 @@ class MarkdownGenerator(Generator):
71
75
  if directory:
72
76
  os.makedirs(directory, exist_ok=True)
73
77
  elif image_dir:
74
- raise ValueError(f"Image directory can only be used with '-d' option")
78
+ raise ValueError("Image directory can only be used with '-d' option")
75
79
  if image_dir:
76
80
  self.image_directory = os.path.join(directory, "images")
77
81
  if not noimages:
@@ -80,9 +84,7 @@ class MarkdownGenerator(Generator):
80
84
  if not self.no_types_dir:
81
85
  os.makedirs(os.path.join(directory, "types"), exist_ok=True)
82
86
 
83
- with open(
84
- self.exist_warning(directory, index_file), "w", encoding="UTF-8"
85
- ) as ixfile:
87
+ with open(self.exist_warning(directory, index_file), "w", encoding="UTF-8") as ixfile:
86
88
  with redirect_stdout(ixfile):
87
89
  self.frontmatter(f"{self.schema.name}")
88
90
  self.para(
@@ -92,11 +94,7 @@ class MarkdownGenerator(Generator):
92
94
 
93
95
  self.header(3, "Classes")
94
96
  for cls in sorted(self.schema.classes.values(), key=lambda c: c.name):
95
- if (
96
- not cls.is_a
97
- and not cls.mixin
98
- and self.is_secondary_ref(cls.name)
99
- ):
97
+ if not cls.is_a and not cls.mixin and self.is_secondary_ref(cls.name):
100
98
  self.class_hier(cls)
101
99
 
102
100
  self.header(3, "Mixins")
@@ -114,9 +112,7 @@ class MarkdownGenerator(Generator):
114
112
  self.enum_hier(enu)
115
113
 
116
114
  self.header(3, "Subsets")
117
- for subset in sorted(
118
- self.schema.subsets.values(), key=lambda s: s.name
119
- ):
115
+ for subset in sorted(self.schema.subsets.values(), key=lambda s: s.name):
120
116
  self.bullet(self.subset_link(subset, use_desc=True), 0)
121
117
 
122
118
  self.header(3, "Types")
@@ -131,14 +127,9 @@ class MarkdownGenerator(Generator):
131
127
  else:
132
128
  typ_typ = f"**{typ.base}**"
133
129
 
134
- self.bullet(
135
- self.type_link(
136
- typ, after_link=f" ({typ_typ})", use_desc=True
137
- )
138
- )
130
+ self.bullet(self.type_link(typ, after_link=f" ({typ_typ})", use_desc=True))
139
131
 
140
132
  def visit_class(self, cls: ClassDefinition) -> bool:
141
-
142
133
  # allow client to relabel metamodel
143
134
  mixin_local_name = self.get_metamodel_slot_name("Mixin")
144
135
  class_local_name = self.get_metamodel_slot_name("Class")
@@ -146,9 +137,7 @@ class MarkdownGenerator(Generator):
146
137
  if self.gen_classes and cls.name not in self.gen_classes:
147
138
  return False
148
139
 
149
- with open(
150
- self.exist_warning(self.dir_path(cls)), "w", encoding="UTF-8"
151
- ) as clsfile:
140
+ with open(self.exist_warning(self.dir_path(cls)), "w", encoding="UTF-8") as clsfile:
152
141
  with redirect_stdout(clsfile):
153
142
  class_curi = self.namespaces.uri_or_curie_for(
154
143
  str(self.namespaces._base), camelcase(cls.name)
@@ -164,9 +153,7 @@ class MarkdownGenerator(Generator):
164
153
  directory=self.image_directory,
165
154
  load_image=not self.noimages,
166
155
  )
167
- img_url = os.path.join(
168
- "images", os.path.basename(yg.output_file_name)
169
- )
156
+ img_url = os.path.join("images", os.path.basename(yg.output_file_name))
170
157
  else:
171
158
  yg = YumlGenerator(self)
172
159
  img_url = (
@@ -219,9 +206,7 @@ class MarkdownGenerator(Generator):
219
206
  self.header(2, "Attributes")
220
207
 
221
208
  # List all of the slots that directly belong to the class
222
- slot_list = [
223
- slot for slot in [self.schema.slots[sn] for sn in cls.slots]
224
- ]
209
+ slot_list = [slot for slot in [self.schema.slots[sn] for sn in cls.slots]]
225
210
  own_slots = [slot for slot in slot_list if cls.name in slot.domain_of]
226
211
  if own_slots:
227
212
  self.header(3, "Own")
@@ -232,9 +217,7 @@ class MarkdownGenerator(Generator):
232
217
  # List all of the inherited slots
233
218
  ancestors = set(self.ancestors(cls))
234
219
  inherited_slots = [
235
- slot
236
- for slot in slot_list
237
- if set(slot.domain_of).intersection(ancestors)
220
+ slot for slot in slot_list if set(slot.domain_of).intersection(ancestors)
238
221
  ]
239
222
  if inherited_slots:
240
223
  self.header(3, "Inherited from " + cls.is_a + ":")
@@ -246,9 +229,7 @@ class MarkdownGenerator(Generator):
246
229
  mixed_in_classes = set()
247
230
  for mixin in cls.mixins:
248
231
  mixed_in_classes.add(mixin)
249
- mixed_in_classes.update(
250
- set(self.ancestors(self.schema.classes[mixin]))
251
- )
232
+ mixed_in_classes.update(set(self.ancestors(self.schema.classes[mixin])))
252
233
  for slot in slot_list:
253
234
  mixers = set(slot.domain_of).intersection(mixed_in_classes)
254
235
  for mixer in mixers:
@@ -260,9 +241,7 @@ class MarkdownGenerator(Generator):
260
241
  return False
261
242
 
262
243
  def visit_type(self, typ: TypeDefinition) -> None:
263
- with open(
264
- self.exist_warning(self.dir_path(typ)), "w", encoding="UTF-8"
265
- ) as typefile:
244
+ with open(self.exist_warning(self.dir_path(typ)), "w", encoding="UTF-8") as typefile:
266
245
  with redirect_stdout(typefile):
267
246
  type_uri = typ.definition_uri
268
247
  type_curie = self.namespaces.curie_for(type_uri)
@@ -278,12 +257,8 @@ class MarkdownGenerator(Generator):
278
257
  self.element_properties(typ)
279
258
 
280
259
  def visit_slot(self, aliased_slot_name: str, slot: SlotDefinition) -> None:
281
- with open(
282
- self.exist_warning(self.dir_path(slot)), "w", encoding="UTF-8"
283
- ) as slotfile:
260
+ with open(self.exist_warning(self.dir_path(slot)), "w", encoding="UTF-8") as slotfile:
284
261
  with redirect_stdout(slotfile):
285
- import logging
286
-
287
262
  slot_curie = self.namespaces.uri_or_curie_for(
288
263
  str(self.namespaces._base), underscore(slot.name)
289
264
  )
@@ -312,29 +287,26 @@ class MarkdownGenerator(Generator):
312
287
  self.bullet(f"{self.class_link(rc)}")
313
288
  if aliased_slot_name == "relation":
314
289
  if slot.subproperty_of:
315
- self.bullet(
316
- f" reifies: {self.slot_link(slot.subproperty_of) if slot.subproperty_of in self.schema.slots else slot.subproperty_of}"
290
+ reifies = (
291
+ self.slot_link(slot.subproperty_of)
292
+ if slot.subproperty_of in self.schema.slots
293
+ else slot.subproperty_of
317
294
  )
295
+ self.bullet(f" reifies: {reifies}")
318
296
  self.element_properties(slot)
319
297
 
320
298
  def visit_enum(self, enum: EnumDefinition) -> None:
321
- with open(
322
- self.exist_warning(self.dir_path(enum)), "w", encoding="UTF-8"
323
- ) as enumfile:
299
+ with open(self.exist_warning(self.dir_path(enum)), "w", encoding="UTF-8") as enumfile:
324
300
  with redirect_stdout(enumfile):
325
301
  enum_curie = self.namespaces.uri_or_curie_for(
326
302
  str(self.namespaces._base), underscore(enum.name)
327
303
  )
328
304
  enum_uri = self.namespaces.uri_for(enum_curie)
329
- self.element_header(
330
- obj=enum, name=enum.name, curie=enum_curie, uri=enum_uri
331
- )
305
+ self.element_header(obj=enum, name=enum.name, curie=enum_curie, uri=enum_uri)
332
306
  self.element_properties(enum)
333
307
 
334
308
  def visit_subset(self, subset: SubsetDefinition) -> None:
335
- with open(
336
- self.exist_warning(self.dir_path(subset)), "w", encoding="UTF-8"
337
- ) as subsetfile:
309
+ with open(self.exist_warning(self.dir_path(subset)), "w", encoding="UTF-8") as subsetfile:
338
310
  with redirect_stdout(subsetfile):
339
311
  curie = self.namespaces.uri_or_curie_for(
340
312
  str(self.namespaces._base), underscore(subset.name)
@@ -367,7 +339,6 @@ class MarkdownGenerator(Generator):
367
339
  self.element_properties(subset)
368
340
 
369
341
  def element_header(self, obj: Element, name: str, curie: str, uri: str) -> None:
370
- simple_name = curie.split(":", 1)[1]
371
342
  if isinstance(obj, TypeDefinition):
372
343
  obj_type = "Type"
373
344
  elif isinstance(obj, ClassDefinition):
@@ -382,9 +353,7 @@ class MarkdownGenerator(Generator):
382
353
  obj_type = "Class"
383
354
 
384
355
  header_label = (
385
- f"{obj_type}: ~~{name}~~ _(deprecated)_"
386
- if obj.deprecated
387
- else f"{obj_type}: {name}"
356
+ f"{obj_type}: ~~{name}~~ _(deprecated)_" if obj.deprecated else f"{obj_type}: {name}"
388
357
  )
389
358
  self.header(1, header_label)
390
359
 
@@ -413,7 +382,7 @@ class MarkdownGenerator(Generator):
413
382
  def enum_list(title: str, obj: EnumDefinition) -> None:
414
383
  # This data is from the enum provided in the YAML
415
384
  self.header(2, title)
416
- print(f"| Text | Description | Meaning | Other Information |")
385
+ print("| Text | Description | Meaning | Other Information |")
417
386
  print("| :--- | :---: | :---: | ---: |")
418
387
 
419
388
  for item, item_info in obj.permissible_values.items():
@@ -507,11 +476,7 @@ class MarkdownGenerator(Generator):
507
476
  if isinstance(obj, EnumDefinition)
508
477
  else camelcase(obj.name)
509
478
  )
510
- subdir = (
511
- "/types"
512
- if isinstance(obj, TypeDefinition) and not self.no_types_dir
513
- else ""
514
- )
479
+ subdir = "/types" if isinstance(obj, TypeDefinition) and not self.no_types_dir else ""
515
480
  return f"{self.directory}{subdir}/{filename}.md"
516
481
 
517
482
  def mappings(self, obj: Union[SlotDefinition, ClassDefinition]) -> None:
@@ -641,11 +606,7 @@ class MarkdownGenerator(Generator):
641
606
  parent = self.schema.classes[obj.is_a]
642
607
  else:
643
608
  parent = None
644
- return (
645
- ""
646
- if parent and obj.description == parent.description
647
- else obj.description
648
- )
609
+ return "" if parent and obj.description == parent.description else obj.description
649
610
  return ""
650
611
 
651
612
  def _link(
@@ -668,9 +629,7 @@ class MarkdownGenerator(Generator):
668
629
  if obj is None or not self.is_secondary_ref(obj.name):
669
630
  return self.bbin(obj)
670
631
  if isinstance(obj, SlotDefinition):
671
- link_name = (
672
- (be(obj.domain) + "➞") if obj.alias else ""
673
- ) + self.aliased_slot_name(obj)
632
+ link_name = ((be(obj.domain) + "➞") if obj.alias else "") + self.aliased_slot_name(obj)
674
633
  link_ref = underscore(obj.name)
675
634
  elif isinstance(obj, TypeDefinition):
676
635
  link_name = camelcase(obj.name)
@@ -825,25 +784,17 @@ class MarkdownGenerator(Generator):
825
784
  @click.command()
826
785
  @click.option("--dir", "-d", required=True, help="Output directory")
827
786
  @click.option("--classes", "-c", multiple=True, help="Class(es) to emit")
828
- @click.option(
829
- "--map-fields", "-M", multiple=True, help="Map metamodel fields, e.g. slot=field"
830
- )
831
- @click.option(
832
- "--img", "-i", is_flag=True, help="Download YUML images to 'image' directory"
833
- )
787
+ @click.option("--map-fields", "-M", multiple=True, help="Map metamodel fields, e.g. slot=field")
788
+ @click.option("--img", "-i", is_flag=True, help="Download YUML images to 'image' directory")
834
789
  @click.option("--index-file", "-I", help="Name of markdown file that holds index")
835
790
  @click.option("--noimages", is_flag=True, help="Do not (re-)generate images")
836
791
  @click.option("--noyuml", is_flag=True, help="Do not add yUML figures to pages")
837
- @click.option(
838
- "--notypesdir", is_flag=True, help="Do not create a separate types directory"
839
- )
792
+ @click.option("--notypesdir", is_flag=True, help="Do not create a separate types directory")
840
793
  @click.option("--warnonexist", is_flag=True, help="Warn if output file already exists")
841
794
  @click.version_option(__version__, "-V", "--version")
842
795
  def cli(yamlfile, map_fields, dir, img, index_file, notypesdir, warnonexist, **kwargs):
843
796
  """Generate markdown documentation of a LinkML model"""
844
- gen = MarkdownGenerator(
845
- yamlfile, no_types_dir=notypesdir, warn_on_exist=warnonexist, **kwargs
846
- )
797
+ gen = MarkdownGenerator(yamlfile, no_types_dir=notypesdir, warn_on_exist=warnonexist, **kwargs)
847
798
  if map_fields is not None:
848
799
  gen.metamodel_name_map = {}
849
800
  for mf in map_fields:
@@ -5,7 +5,6 @@ import click
5
5
  from linkml_runtime.utils.formatutils import be, split_line
6
6
 
7
7
  from linkml._version import __version__
8
- from linkml.generators import PYTHON_GEN_VERSION
9
8
  from linkml.generators.pythongen import PythonGenerator
10
9
  from linkml.utils.generator import shared_arguments
11
10
 
@@ -13,7 +12,7 @@ from linkml.utils.generator import shared_arguments
13
12
  @dataclass
14
13
  class NamespaceGenerator(PythonGenerator):
15
14
  generatorname = os.path.basename(__file__)
16
- generatorversion = PYTHON_GEN_VERSION
15
+ generatorversion = "0.0.1"
17
16
  valid_formats = ["py"]
18
17
  visit_all_class_slots = False
19
18
 
@@ -2,12 +2,16 @@ import abc
2
2
  import re
3
3
  import unicodedata
4
4
  from dataclasses import dataclass, field
5
- from typing import List, Optional, Dict
6
-
7
- from linkml_runtime.linkml_model.meta import (ClassDefinition,
8
- EnumDefinition, EnumDefinitionName,
9
- SchemaDefinition, SlotDefinition,
10
- TypeDefinition)
5
+ from typing import Dict, List, Optional
6
+
7
+ from linkml_runtime.linkml_model.meta import (
8
+ ClassDefinition,
9
+ EnumDefinition,
10
+ EnumDefinitionName,
11
+ SchemaDefinition,
12
+ SlotDefinition,
13
+ TypeDefinition,
14
+ )
11
15
  from linkml_runtime.utils.formatutils import camelcase, lcamelcase, underscore
12
16
  from linkml_runtime.utils.schemaview import SchemaView
13
17
 
@@ -67,7 +71,6 @@ class OOClass:
67
71
 
68
72
  @dataclass
69
73
  class OOCodeGenerator(Generator):
70
-
71
74
  # ClassVars
72
75
  java_style = True
73
76
  visit_all_class_slots = False
@@ -120,7 +123,7 @@ class OOCodeGenerator(Generator):
120
123
  return label
121
124
  else:
122
125
  # add an underscore if the value starts with a digit
123
- label = re.sub("(?=^\d)", "number_", label)
126
+ label = re.sub(r"(?=^\d)", "number_", label)
124
127
 
125
128
  safe_label = ""
126
129
  for character in label:
@@ -128,33 +131,25 @@ class OOCodeGenerator(Generator):
128
131
 
129
132
  return safe_label
130
133
 
131
- def generate_enums(
132
- self, all_enums: Dict[EnumDefinitionName, EnumDefinition]
133
- ) -> Dict:
134
+ def generate_enums(self, all_enums: Dict[EnumDefinitionName, EnumDefinition]) -> Dict:
134
135
  # TODO: make an explicit class to represent how an enum is passed to the template
135
136
  enums = {}
136
137
  for enum_name, enum_original in all_enums.items():
137
- enum = {
138
- "name": camelcase(enum_name),
139
- "values": {}
140
- }
138
+ enum = {"name": camelcase(enum_name), "values": {}}
141
139
 
142
140
  if hasattr(enum_original, "description"):
143
141
  enum["description"] = enum_original.description
144
142
 
145
143
  for pv in enum_original.permissible_values.values():
146
144
  label = self.generate_enum_label(pv.text)
147
- val = {
148
- "label": label,
149
- "value": pv.text.replace('"', '\\"')
150
- }
145
+ val = {"label": label, "value": pv.text.replace('"', '\\"')}
151
146
  if hasattr(pv, "description"):
152
147
  val["description"] = pv.description
153
- else :
148
+ else:
154
149
  val["description"] = None
155
150
 
156
151
  enum["values"][label] = val
157
-
152
+
158
153
  enums[enum_name] = enum
159
154
 
160
155
  return enums
@@ -170,12 +165,14 @@ class OOCodeGenerator(Generator):
170
165
  for cn in sv.all_classes(imports=False):
171
166
  c = sv.get_class(cn)
172
167
  safe_cn = camelcase(cn)
173
- oodoc = OODocument(
174
- name=safe_cn, package=self.package, source_schema=sv.schema
175
- )
168
+ oodoc = OODocument(name=safe_cn, package=self.package, source_schema=sv.schema)
176
169
  docs.append(oodoc)
177
170
  ooclass = OOClass(
178
- name=safe_cn, description=c.description, package=self.package, fields=[], source_class=c
171
+ name=safe_cn,
172
+ description=c.description,
173
+ package=self.package,
174
+ fields=[],
175
+ source_class=c,
179
176
  )
180
177
  # currently hardcoded for java style, one class per doc
181
178
  oodoc.classes = [ooclass]
@@ -6,18 +6,23 @@ import logging
6
6
  import os
7
7
  from dataclasses import dataclass, field
8
8
  from enum import Enum, unique
9
- from typing import List, Optional, Set, TextIO, Union
9
+ from typing import Optional, TextIO, Union
10
10
 
11
11
  import click
12
- from linkml_runtime.linkml_model.meta import (ClassDefinition,
13
- ClassDefinitionName, Definition,
14
- Element, ElementName,
15
- EnumDefinition,
16
- EnumDefinitionName,
17
- SchemaDefinition, SlotDefinition,
18
- SlotDefinitionName,
19
- TypeDefinition,
20
- TypeDefinitionName)
12
+ from linkml_runtime.linkml_model.meta import (
13
+ ClassDefinition,
14
+ ClassDefinitionName,
15
+ Definition,
16
+ Element,
17
+ ElementName,
18
+ EnumDefinition,
19
+ EnumDefinitionName,
20
+ SchemaDefinition,
21
+ SlotDefinition,
22
+ SlotDefinitionName,
23
+ TypeDefinition,
24
+ TypeDefinitionName,
25
+ )
21
26
  from linkml_runtime.utils.formatutils import camelcase, underscore
22
27
  from rdflib import OWL, RDF, BNode, Graph, Literal, URIRef
23
28
  from rdflib.collection import Collection
@@ -28,7 +33,6 @@ from rdflib.plugin import plugins as rdflib_plugins
28
33
  from linkml import METAMODEL_NAMESPACE, METAMODEL_NAMESPACE_NAME
29
34
  from linkml._version import __version__
30
35
  from linkml.utils.generator import Generator, shared_arguments
31
- from linkml.utils.schemaloader import SchemaLoader
32
36
 
33
37
 
34
38
  @unique
@@ -70,6 +74,7 @@ class OwlSchemaGenerator(Generator):
70
74
  valid_formats = ["owl", "ttl"] + [
71
75
  x.name for x in rdflib_plugins(None, rdflib_Parser) if "/" not in str(x.name)
72
76
  ]
77
+ file_extension = "owl"
73
78
  visits_are_sorted = True
74
79
  uses_schemaloader = True
75
80
  requires_metamodel = True
@@ -93,9 +98,7 @@ class OwlSchemaGenerator(Generator):
93
98
  for prefix in self.metamodel.schema.emit_prefixes:
94
99
  self.graph.bind(prefix, self.metamodel.namespaces[prefix])
95
100
  for pfx in self.schema.prefixes.values():
96
- self.graph.namespace_manager.bind(
97
- pfx.prefix_prefix, URIRef(pfx.prefix_reference)
98
- )
101
+ self.graph.namespace_manager.bind(pfx.prefix_prefix, URIRef(pfx.prefix_reference))
99
102
 
100
103
  self.graph.add((base, RDF.type, OWL.Ontology))
101
104
  self._add_element_properties(base, self.schema)
@@ -113,9 +116,7 @@ class OwlSchemaGenerator(Generator):
113
116
  # add value placeholder
114
117
  if self.type_objects:
115
118
  # TODO: additional axioms, e.g. String subClassOf hasValue some string
116
- self.top_value_uri = self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME][
117
- "topValue"
118
- ]
119
+ self.top_value_uri = self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME]["topValue"]
119
120
  self.graph.add((self.top_value_uri, RDF.type, OWL.DatatypeProperty))
120
121
  self.graph.add((self.top_value_uri, RDFS.label, Literal("value")))
121
122
 
@@ -199,7 +200,7 @@ class OwlSchemaGenerator(Generator):
199
200
  k_curie = k
200
201
  try:
201
202
  k_uri = self.namespaces.uri_for(k_curie)
202
- except ValueError as e:
203
+ except ValueError:
203
204
  try:
204
205
  k_uri = self.metamodel.namespaces.uri_for(k_curie)
205
206
  except ValueError as me:
@@ -325,7 +326,7 @@ class OwlSchemaGenerator(Generator):
325
326
  slot_uri = self.namespaces.uri_for(slot.slot_uri)
326
327
  if slot_uri == "rdf:type":
327
328
  logging.warning(
328
- f"rdflib may have issues serializing rdf:type with turtle serializer"
329
+ "rdflib may have issues serializing rdf:type with turtle serializer"
329
330
  )
330
331
  if slot.required:
331
332
  if slot.multivalued:
@@ -354,9 +355,7 @@ class OwlSchemaGenerator(Generator):
354
355
  if slot.multivalued:
355
356
  # restriction(slot only type)
356
357
  self.graph.add((slot_node, RDF.type, OWL.Restriction))
357
- self.graph.add(
358
- (slot_node, OWL.allValuesFrom, self._range_uri(slot))
359
- )
358
+ self.graph.add((slot_node, OWL.allValuesFrom, self._range_uri(slot)))
360
359
  self.graph.add((slot_node, OWL.onProperty, slot_uri))
361
360
  else:
362
361
  # intersectionOf(restriction(slot only type) restriction(slot max 1 type))
@@ -378,13 +377,10 @@ class OwlSchemaGenerator(Generator):
378
377
  @param slot:
379
378
  @return:
380
379
  """
381
- # determine if this is a slot that has been induced by slot_usage; if so the meaning of the slot is context-specific
382
- # and should not be used for global properties
383
- if (
384
- slot.alias is not None
385
- and slot.alias != slot.name
386
- and slot.alias in self.schema.slots
387
- ):
380
+ # determine if this is a slot that has been induced by slot_usage; if so
381
+ # the meaning of the slot is context-specific and should not be used for
382
+ # global properties
383
+ if slot.alias is not None and slot.alias != slot.name and slot.alias in self.schema.slots:
388
384
  logging.debug(
389
385
  f"SKIPPING slot induced by slot_usage: {slot.alias} // {slot.name} // {slot}"
390
386
  )
@@ -500,9 +496,7 @@ class OwlSchemaGenerator(Generator):
500
496
  g.add(
501
497
  (
502
498
  enum_uri,
503
- self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME][
504
- "permissible_values"
505
- ],
499
+ self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME]["permissible_values"],
506
500
  pv_uri,
507
501
  )
508
502
  )
@@ -520,8 +514,7 @@ class OwlSchemaGenerator(Generator):
520
514
  if k in metamodel.schema.slots:
521
515
  defining_slot = self.metamodel.schema.slots[k]
522
516
  if v is not None and (
523
- "owl" in defining_slot.in_subset
524
- or "OwlProfile" in defining_slot.in_subset
517
+ "owl" in defining_slot.in_subset or "OwlProfile" in defining_slot.in_subset
525
518
  ):
526
519
  if isinstance(v, list):
527
520
  ve = v
@@ -540,18 +533,12 @@ class OwlSchemaGenerator(Generator):
540
533
  ),
541
534
  ):
542
535
  return
543
- if (
544
- k == "name"
545
- and isinstance(el, SlotDefinition)
546
- and el.alias is not None
547
- ):
536
+ if k == "name" and isinstance(el, SlotDefinition) and el.alias is not None:
548
537
  prop_uri = RDFS.label
549
538
  e = el.alias
550
539
  else:
551
540
  prop_uri = URIRef(
552
- self.metamodel.namespaces.uri_for(
553
- defining_slot.slot_uri
554
- )
541
+ self.metamodel.namespaces.uri_for(defining_slot.slot_uri)
555
542
  )
556
543
  object = self._as_rdf_element(e, defining_slot)
557
544
  if object is not None:
@@ -576,7 +563,7 @@ class OwlSchemaGenerator(Generator):
576
563
  elif element_name in self.metamodel.schema.enums:
577
564
  return self._enum_uri(element_name)
578
565
  else:
579
- logging.warning(f"Unknown range {defining_slot.range}")
566
+ logging.warning(f"Unknown range {parent_slot.range}")
580
567
  return None
581
568
 
582
569
  def _range_is_datatype(self, slot: SlotDefinition) -> bool:
@@ -621,9 +608,7 @@ class OwlSchemaGenerator(Generator):
621
608
 
622
609
  def _add_metamodel_class(self, cname: str) -> None:
623
610
  metac = self.metamodel.schema.classes[cname]
624
- metac_uri = self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME][
625
- camelcase(metac.name)
626
- ]
611
+ metac_uri = self.metamodel.namespaces[METAMODEL_NAMESPACE_NAME][camelcase(metac.name)]
627
612
  self.graph.add((metac_uri, RDF.type, OWL.Class))
628
613
  # self._add_element_properties(metac_uri, metac)
629
614
 
@@ -714,9 +699,9 @@ def cli(yamlfile, metadata_profile: str, **kwargs):
714
699
  else:
715
700
  metadata_profile = MetadataProfile.linkml
716
701
  print(
717
- OwlSchemaGenerator(
718
- yamlfile, metadata_profile=metadata_profile, **kwargs
719
- ).serialize(**kwargs)
702
+ OwlSchemaGenerator(yamlfile, metadata_profile=metadata_profile, **kwargs).serialize(
703
+ **kwargs
704
+ )
720
705
  )
721
706
 
722
707
 
@@ -3,18 +3,15 @@ Generate JSON-LD contexts
3
3
 
4
4
  """
5
5
  import csv
6
- import logging
7
6
  import os
8
7
  from dataclasses import dataclass, field
9
- from typing import Dict, Mapping, Optional, Set, TextIO, Union
8
+ from typing import Dict, Optional, Set
10
9
 
11
10
  import click
12
11
  from jsonasobj2 import JsonObj, as_json
13
- from linkml_runtime.linkml_model.meta import (ClassDefinition, Definition,
14
- Element, SchemaDefinition,
15
- SlotDefinition)
12
+ from linkml_runtime.linkml_model.meta import ClassDefinition, SlotDefinition
16
13
  from linkml_runtime.linkml_model.types import SHEX
17
- from linkml_runtime.utils.formatutils import be, camelcase, underscore
14
+ from linkml_runtime.utils.formatutils import camelcase
18
15
  from rdflib import XSD
19
16
 
20
17
  from linkml._version import __version__
@@ -25,7 +22,6 @@ URI_RANGES = (XSD.anyURI, SHEX.nonliteral, SHEX.bnode, SHEX.iri)
25
22
 
26
23
  @dataclass
27
24
  class PrefixGenerator(Generator):
28
-
29
25
  # ClassVars
30
26
  generatorname = os.path.basename(__file__)
31
27
  generatorversion = "0.1.1"
@@ -47,9 +43,7 @@ class PrefixGenerator(Generator):
47
43
  "Schema text must be supplied to context generator. Preparsed schema will not work"
48
44
  )
49
45
 
50
- def visit_schema(
51
- self, base: Optional[str] = None, output: Optional[str] = None, **_
52
- ):
46
+ def visit_schema(self, base: Optional[str] = None, output: Optional[str] = None, **_):
53
47
  # Add any explicitly declared prefixes
54
48
  for prefix in self.schema.prefixes.values():
55
49
  self.emit_prefixes.add(prefix.prefix_prefix)
@@ -66,9 +60,7 @@ class PrefixGenerator(Generator):
66
60
  if self.default_ns:
67
61
  self.emit_prefixes.add(self.default_ns)
68
62
 
69
- def end_schema(
70
- self, base: Optional[str] = None, output: Optional[str] = None, **_
71
- ) -> None:
63
+ def end_schema(self, base: Optional[str] = None, output: Optional[str] = None, **_) -> None:
72
64
  context = JsonObj()
73
65
  if base:
74
66
  if "://" not in base: