linkml 1.8.2__tar.gz → 1.8.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 (163) hide show
  1. {linkml-1.8.2 → linkml-1.8.4}/PKG-INFO +3 -1
  2. {linkml-1.8.2 → linkml-1.8.4}/linkml/cli/main.py +4 -0
  3. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/__init__.py +2 -0
  4. linkml-1.8.4/linkml/generators/common/ifabsent_processor.py +286 -0
  5. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/index.md.jinja2 +6 -6
  6. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen.py +64 -14
  7. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/golanggen.py +3 -1
  8. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/jsonldcontextgen.py +0 -1
  9. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/jsonschemagen.py +4 -2
  10. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/owlgen.py +36 -17
  11. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/projectgen.py +13 -11
  12. linkml-1.8.4/linkml/generators/pydanticgen/array.py +662 -0
  13. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/build.py +4 -2
  14. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/pydanticgen.py +46 -24
  15. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/template.py +108 -3
  16. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/imports.py.jinja +11 -3
  17. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/module.py.jinja +1 -3
  18. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/validator.py.jinja +2 -2
  19. linkml-1.8.4/linkml/generators/python/__init__.py +1 -0
  20. linkml-1.8.4/linkml/generators/python/python_ifabsent_processor.py +92 -0
  21. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pythongen.py +19 -31
  22. linkml-1.8.4/linkml/generators/shacl/__init__.py +1 -0
  23. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/shacl/shacl_data_type.py +1 -1
  24. linkml-1.8.4/linkml/generators/shacl/shacl_ifabsent_processor.py +89 -0
  25. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/shaclgen.py +39 -13
  26. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sparqlgen.py +3 -1
  27. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sqlalchemygen.py +5 -3
  28. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sqltablegen.py +4 -2
  29. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/typescriptgen.py +13 -6
  30. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/linter.py +2 -1
  31. {linkml-1.8.2 → linkml-1.8.4}/linkml/transformers/logical_model_transformer.py +3 -3
  32. {linkml-1.8.2 → linkml-1.8.4}/linkml/transformers/relmodel_transformer.py +18 -4
  33. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/converter.py +3 -1
  34. linkml-1.8.4/linkml/utils/exceptions.py +11 -0
  35. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/execute_tutorial.py +22 -20
  36. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/generator.py +6 -4
  37. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/mergeutils.py +4 -2
  38. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/schema_fixer.py +5 -5
  39. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/schemaloader.py +5 -3
  40. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/sqlutils.py +3 -1
  41. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/plugins/pydantic_validation_plugin.py +1 -1
  42. {linkml-1.8.2 → linkml-1.8.4}/linkml/validators/jsonschemavalidator.py +3 -1
  43. {linkml-1.8.2 → linkml-1.8.4}/linkml/validators/sparqlvalidator.py +5 -3
  44. {linkml-1.8.2 → linkml-1.8.4}/linkml/workspaces/example_runner.py +3 -1
  45. {linkml-1.8.2 → linkml-1.8.4}/pyproject.toml +8 -3
  46. {linkml-1.8.2 → linkml-1.8.4}/setup.py +5 -2
  47. linkml-1.8.2/linkml/generators/pydanticgen/array.py +0 -378
  48. linkml-1.8.2/linkml/generators/shacl/__init__.py +0 -3
  49. linkml-1.8.2/linkml/generators/shacl/ifabsent_processor.py +0 -59
  50. linkml-1.8.2/linkml/utils/ifabsent_functions.py +0 -138
  51. {linkml-1.8.2 → linkml-1.8.4}/LICENSE +0 -0
  52. {linkml-1.8.2 → linkml-1.8.4}/README.md +0 -0
  53. {linkml-1.8.2 → linkml-1.8.4}/linkml/__init__.py +0 -0
  54. {linkml-1.8.2 → linkml-1.8.4}/linkml/_version.py +0 -0
  55. {linkml-1.8.2 → linkml-1.8.4}/linkml/cli/__init__.py +0 -0
  56. {linkml-1.8.2 → linkml-1.8.4}/linkml/cli/__main__.py +0 -0
  57. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/PythonGenNotes.md +0 -0
  58. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/README.md +0 -0
  59. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/common/__init__.py +0 -0
  60. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/common/build.py +0 -0
  61. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/common/lifecycle.py +0 -0
  62. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/common/template.py +0 -0
  63. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/common/type_designators.py +0 -0
  64. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/csvgen.py +0 -0
  65. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/class.md.jinja2 +0 -0
  66. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/class_diagram.md.jinja2 +0 -0
  67. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/common_metadata.md.jinja2 +0 -0
  68. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/enum.md.jinja2 +0 -0
  69. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/index.tex.jinja2 +0 -0
  70. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/schema.md.jinja2 +0 -0
  71. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/slot.md.jinja2 +0 -0
  72. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/subset.md.jinja2 +0 -0
  73. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/docgen/type.md.jinja2 +0 -0
  74. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/dotgen.py +0 -0
  75. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/erdiagramgen.py +0 -0
  76. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/excelgen.py +0 -0
  77. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/golrgen.py +0 -0
  78. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/graphqlgen.py +0 -0
  79. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/javagen/example_template.java.jinja2 +0 -0
  80. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/javagen/java_record_template.jinja2 +0 -0
  81. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/javagen.py +0 -0
  82. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/jsonldgen.py +0 -0
  83. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/legacy/__init__.py +0 -0
  84. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/linkmlgen.py +0 -0
  85. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/markdowngen.py +0 -0
  86. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/namespacegen.py +0 -0
  87. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/oocodegen.py +0 -0
  88. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/plantumlgen.py +0 -0
  89. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/prefixmapgen.py +0 -0
  90. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/protogen.py +0 -0
  91. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/__init__.py +0 -0
  92. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/black.py +0 -0
  93. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/includes.py +0 -0
  94. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/attribute.py.jinja +0 -0
  95. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/base_model.py.jinja +0 -0
  96. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/class.py.jinja +0 -0
  97. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/conditional_import.py.jinja +0 -0
  98. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/enum.py.jinja +0 -0
  99. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/footer.py.jinja +0 -0
  100. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/rdfgen.py +0 -0
  101. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/shexgen.py +0 -0
  102. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sqlalchemy/__init__.py +0 -0
  103. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +0 -0
  104. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +0 -0
  105. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/sssomgen.py +0 -0
  106. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/string_template.md +0 -0
  107. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/summarygen.py +0 -0
  108. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/terminusdbgen.py +0 -0
  109. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/yamlgen.py +0 -0
  110. {linkml-1.8.2 → linkml-1.8.4}/linkml/generators/yumlgen.py +0 -0
  111. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/__init__.py +0 -0
  112. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/cli.py +0 -0
  113. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/config/datamodel/.linkmllint.yaml +0 -0
  114. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/config/datamodel/__init__.py +0 -0
  115. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/config/datamodel/config.py +0 -0
  116. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/config/datamodel/config.yaml +0 -0
  117. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/config/default.yaml +0 -0
  118. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/config/recommended.yaml +0 -0
  119. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/formatters/__init__.py +0 -0
  120. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/formatters/formatter.py +0 -0
  121. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/formatters/json_formatter.py +0 -0
  122. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/formatters/markdown_formatter.py +0 -0
  123. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/formatters/terminal_formatter.py +0 -0
  124. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/formatters/tsv_formatter.py +0 -0
  125. {linkml-1.8.2 → linkml-1.8.4}/linkml/linter/rules.py +0 -0
  126. {linkml-1.8.2 → linkml-1.8.4}/linkml/reporting/__init__.py +0 -0
  127. {linkml-1.8.2 → linkml-1.8.4}/linkml/reporting/model.py +0 -0
  128. {linkml-1.8.2 → linkml-1.8.4}/linkml/transformers/__init__.py +0 -0
  129. {linkml-1.8.2 → linkml-1.8.4}/linkml/transformers/model_transformer.py +0 -0
  130. {linkml-1.8.2 → linkml-1.8.4}/linkml/transformers/schema_renamer.py +0 -0
  131. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/__init__.py +0 -0
  132. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/cli_utils.py +0 -0
  133. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/datautils.py +0 -0
  134. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/datavalidator.py +0 -0
  135. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/deprecation.py +0 -0
  136. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/helpers.py +0 -0
  137. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/logictools.py +0 -0
  138. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/rawloader.py +0 -0
  139. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/schema_builder.py +0 -0
  140. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/schemasynopsis.py +0 -0
  141. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/typereferences.py +0 -0
  142. {linkml-1.8.2 → linkml-1.8.4}/linkml/utils/validation.py +0 -0
  143. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/__init__.py +0 -0
  144. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/cli.py +0 -0
  145. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/loaders/__init__.py +0 -0
  146. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/loaders/delimited_file_loader.py +0 -0
  147. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/loaders/json_loader.py +0 -0
  148. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/loaders/loader.py +0 -0
  149. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/loaders/passthrough_loader.py +0 -0
  150. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/loaders/yaml_loader.py +0 -0
  151. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/plugins/__init__.py +0 -0
  152. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/plugins/jsonschema_validation_plugin.py +0 -0
  153. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/plugins/recommended_slots_plugin.py +0 -0
  154. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/plugins/shacl_validation_plugin.py +0 -0
  155. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/plugins/validation_plugin.py +0 -0
  156. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/report.py +0 -0
  157. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/validation_context.py +0 -0
  158. {linkml-1.8.2 → linkml-1.8.4}/linkml/validator/validator.py +0 -0
  159. {linkml-1.8.2 → linkml-1.8.4}/linkml/validators/__init__.py +0 -0
  160. {linkml-1.8.2 → linkml-1.8.4}/linkml/workspaces/__init__.py +0 -0
  161. {linkml-1.8.2 → linkml-1.8.4}/linkml/workspaces/datamodel/__init__.py +0 -0
  162. {linkml-1.8.2 → linkml-1.8.4}/linkml/workspaces/datamodel/workspaces.py +0 -0
  163. {linkml-1.8.2 → linkml-1.8.4}/linkml/workspaces/datamodel/workspaces.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkml
3
- Version: 1.8.2
3
+ Version: 1.8.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
@@ -24,6 +24,7 @@ Classifier: Programming Language :: Python :: 3.8
24
24
  Classifier: Programming Language :: Python :: 3.9
25
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
26
  Provides-Extra: black
27
+ Provides-Extra: numpydantic
27
28
  Provides-Extra: shacl
28
29
  Provides-Extra: tests
29
30
  Requires-Dist: antlr4-python3-runtime (>=4.9.0,<4.10)
@@ -37,6 +38,7 @@ Requires-Dist: jsonasobj2 (>=1.0.3,<2.0.0)
37
38
  Requires-Dist: jsonschema[format] (>=4.0.0)
38
39
  Requires-Dist: linkml-dataops
39
40
  Requires-Dist: linkml-runtime (>=1.8.1,<2.0.0)
41
+ Requires-Dist: numpydantic (>=1.6.1) ; (python_version >= "3.9") and (extra == "numpydantic" or extra == "tests")
40
42
  Requires-Dist: openpyxl
41
43
  Requires-Dist: parse
42
44
  Requires-Dist: prefixcommons (>=0.1.7)
@@ -6,6 +6,7 @@ Gathers all the other linkml click entrypoints and puts them under ``linkml`` :)
6
6
 
7
7
  import click
8
8
 
9
+ from linkml._version import __version__
9
10
  from linkml.generators.csvgen import cli as gen_csv
10
11
  from linkml.generators.docgen import cli as gen_doc
11
12
  from linkml.generators.dotgen import cli as gen_graphviz
@@ -54,6 +55,7 @@ from linkml.workspaces.example_runner import cli as linkml_run_examples
54
55
 
55
56
 
56
57
  @click.group()
58
+ @click.version_option(__version__, "-V", "--version")
57
59
  def linkml():
58
60
  """
59
61
  LinkML: A flexible linked data modeling language
@@ -61,6 +63,7 @@ def linkml():
61
63
 
62
64
 
63
65
  @linkml.group()
66
+ @click.version_option(__version__, "-V", "--version")
64
67
  def generate():
65
68
  """
66
69
  Generate formats from a LinkML schema
@@ -68,6 +71,7 @@ def generate():
68
71
 
69
72
 
70
73
  @linkml.group()
74
+ @click.version_option(__version__, "-V", "--version")
71
75
  def dev():
72
76
  """
73
77
  Helper tools for linkml development
@@ -10,6 +10,7 @@ from linkml.generators.jsonschemagen import JsonSchemaGenerator
10
10
  from linkml.generators.owlgen import OwlSchemaGenerator
11
11
  from linkml.generators.pydanticgen import PydanticGenerator
12
12
  from linkml.generators.pythongen import PythonGenerator
13
+ from linkml.generators.rdfgen import RDFGenerator
13
14
  from linkml.generators.shaclgen import ShaclGenerator
14
15
  from linkml.generators.shexgen import ShExGenerator
15
16
  from linkml.generators.sqlalchemygen import SQLAlchemyGenerator
@@ -50,6 +51,7 @@ __all__ = [
50
51
  "ShExGenerator",
51
52
  "SQLAlchemyGenerator",
52
53
  "SQLTableGenerator",
54
+ "RDFGenerator",
53
55
  ]
54
56
 
55
57
  # TODO: deprecate usage of these
@@ -0,0 +1,286 @@
1
+ import abc
2
+ import re
3
+ from abc import ABC
4
+ from typing import Any, Optional
5
+
6
+ from linkml_runtime import SchemaView
7
+ from linkml_runtime.linkml_model import (
8
+ Boolean,
9
+ ClassDefinition,
10
+ Date,
11
+ Datetime,
12
+ Decimal,
13
+ Double,
14
+ EnumDefinitionName,
15
+ Float,
16
+ Integer,
17
+ SlotDefinition,
18
+ String,
19
+ Time,
20
+ Uri,
21
+ )
22
+ from linkml_runtime.linkml_model.types import (
23
+ Curie,
24
+ DateOrDatetime,
25
+ Jsonpath,
26
+ Jsonpointer,
27
+ Ncname,
28
+ Nodeidentifier,
29
+ Objectidentifier,
30
+ Sparqlpath,
31
+ Uriorcurie,
32
+ )
33
+
34
+
35
+ class IfAbsentProcessor(ABC):
36
+ """
37
+ Processes value of ifabsent slot.
38
+
39
+ See `<https://w3id.org/linkml/ifabsent>`_.
40
+ """
41
+
42
+ ifabsent_regex = re.compile("""(?:(?P<type>\w+)\()?[\"\']?(?P<default_value>[^\(\)\"\')]*)[\"\']?\)?""")
43
+
44
+ def __init__(self, schema_view: SchemaView):
45
+ self.schema_view = schema_view
46
+
47
+ def process_slot(self, slot: SlotDefinition, cls: ClassDefinition) -> Optional[str]:
48
+ if slot.ifabsent:
49
+ ifabsent_match = self.ifabsent_regex.search(slot.ifabsent)
50
+ ifabsent_default_value = ifabsent_match.group("default_value")
51
+
52
+ return self._map_to_default_value(slot, ifabsent_default_value, cls)
53
+
54
+ return None
55
+
56
+ def _map_to_default_value(
57
+ self, slot: SlotDefinition, ifabsent_default_value: Any, cls: ClassDefinition
58
+ ) -> Optional[str]:
59
+ # Used to manage specific cases that aren't generic
60
+ mapped, custom_default_value = self.map_custom_default_values(ifabsent_default_value, slot, cls)
61
+ if mapped:
62
+ return custom_default_value
63
+
64
+ if slot.range == String.type_name:
65
+ return self.map_string_default_value(ifabsent_default_value, slot, cls)
66
+
67
+ if slot.range == Boolean.type_name:
68
+ if re.match(r"^[Tt]rue$", ifabsent_default_value):
69
+ return self.map_boolean_true_default_value(slot, cls)
70
+ elif re.match(r"^[Ff]alse$", ifabsent_default_value):
71
+ return self.map_boolean_false_default_value(slot, cls)
72
+ else:
73
+ raise ValueError(
74
+ f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot does not match a valid boolean "
75
+ f"value"
76
+ )
77
+
78
+ if slot.range == Integer.type_name:
79
+ return self.map_integer_default_value(ifabsent_default_value, slot, cls)
80
+
81
+ if slot.range == Float.type_name:
82
+ return self.map_float_default_value(ifabsent_default_value, slot, cls)
83
+
84
+ if slot.range == Double.type_name:
85
+ return self.map_double_default_value(ifabsent_default_value, slot, cls)
86
+
87
+ if slot.range == Decimal.type_name:
88
+ return self.map_decimal_default_value(ifabsent_default_value, slot, cls)
89
+
90
+ if slot.range == Time.type_name:
91
+ match = re.match(r"^(\d{2}):(\d{2}):(\d{2}).*$", ifabsent_default_value)
92
+ if match:
93
+ return self.map_time_default_value(match[1], match[2], match[3], slot, cls)
94
+ else:
95
+ raise ValueError(
96
+ f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot does not match a valid time value"
97
+ )
98
+
99
+ # TODO manage timezones and offsets
100
+ if slot.range == Date.type_name:
101
+ match = re.match(r"^(\d{4})-(\d{2})-(\d{2})$", ifabsent_default_value)
102
+ if match:
103
+ return self.map_date_default_value(match[1], match[2], match[3], slot, cls)
104
+ else:
105
+ raise ValueError(
106
+ f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot does not match a valid date value"
107
+ )
108
+
109
+ # TODO manage timezones and offsets
110
+ if slot.range == Datetime.type_name:
111
+ match = re.match(r"^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).*$", ifabsent_default_value)
112
+ if match:
113
+ return self.map_datetime_default_value(
114
+ match[1], match[2], match[3], match[4], match[5], match[6], slot, cls
115
+ )
116
+ else:
117
+ raise ValueError(
118
+ f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot does not match a valid datetime "
119
+ f"value"
120
+ )
121
+
122
+ # TODO manage timezones and offsets
123
+ if slot.range == DateOrDatetime.type_name:
124
+ match = re.match(r"^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2}))?.*$", ifabsent_default_value)
125
+ if match and (match[4] is None or match[5] is None or match[6] is None):
126
+ return self.map_date_default_value(match[1], match[2], match[3], slot, cls)
127
+ elif match:
128
+ return self.map_datetime_default_value(
129
+ match[1], match[2], match[3], match[4], match[5], match[6], slot, cls
130
+ )
131
+ else:
132
+ raise ValueError(
133
+ f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot does not match a valid date or "
134
+ f"datetime value"
135
+ )
136
+
137
+ if slot.range == Uri.type_name:
138
+ return self.map_uri_default_value(ifabsent_default_value, slot, cls)
139
+
140
+ if slot.range == Curie.type_name:
141
+ return self.map_curie_default_value(ifabsent_default_value, slot, cls)
142
+
143
+ if slot.range == Uriorcurie.type_name:
144
+ return self.map_uri_or_curie_default_value(ifabsent_default_value, slot, cls)
145
+
146
+ if slot.range == Ncname.type_name:
147
+ return self.map_nc_name_default_value(ifabsent_default_value, slot, cls)
148
+
149
+ if slot.range == Objectidentifier.type_name:
150
+ return self.map_object_identifier_default_value(ifabsent_default_value, slot, cls)
151
+
152
+ if slot.range == Nodeidentifier.type_name:
153
+ return self.map_node_identifier_default_value(ifabsent_default_value, slot, cls)
154
+
155
+ if slot.range == Jsonpointer.type_name:
156
+ return self.map_json_pointer_default_value(ifabsent_default_value, slot, cls)
157
+
158
+ if slot.range == Jsonpath.type_name:
159
+ return self.map_json_path_default_value(ifabsent_default_value, slot, cls)
160
+
161
+ if slot.range == Sparqlpath.type_name:
162
+ return self.map_sparql_path_default_value(ifabsent_default_value, slot, cls)
163
+
164
+ # -----------------------
165
+ # Enum slot ranges
166
+ # -----------------------
167
+
168
+ for enum_name, enum in self.schema_view.all_enums().items():
169
+ if enum_name == slot.range:
170
+ for permissible_value_name, permissible_value in enum.permissible_values.items():
171
+ if permissible_value_name == ifabsent_default_value:
172
+ return self.map_enum_default_value(enum_name, permissible_value_name, slot, cls)
173
+
174
+ raise ValueError(f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot could not be processed")
175
+
176
+ @abc.abstractmethod
177
+ def map_custom_default_values(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition) -> (bool, str):
178
+ """
179
+ Maps custom default values that aren't generic behaviours.
180
+
181
+ @param default_value: the default value extracted from the ifabsent attribute
182
+ @param slot: the definition of the slot
183
+ @param cls: the definition of the class
184
+ @return: a boolean that indicates if the value has been mapped followed by the mapped value
185
+ """
186
+ return False, None
187
+
188
+ @abc.abstractmethod
189
+ def map_string_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
190
+ raise NotImplementedError()
191
+
192
+ @abc.abstractmethod
193
+ def map_integer_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
194
+ raise NotImplementedError()
195
+
196
+ @abc.abstractmethod
197
+ def map_boolean_true_default_value(self, slot: SlotDefinition, cls: ClassDefinition):
198
+ raise NotImplementedError()
199
+
200
+ @abc.abstractmethod
201
+ def map_boolean_false_default_value(self, slot: SlotDefinition, cls: ClassDefinition):
202
+ raise NotImplementedError()
203
+
204
+ @abc.abstractmethod
205
+ def map_float_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
206
+ raise NotImplementedError()
207
+
208
+ @abc.abstractmethod
209
+ def map_double_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
210
+ raise NotImplementedError()
211
+
212
+ @abc.abstractmethod
213
+ def map_decimal_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
214
+ raise NotImplementedError()
215
+
216
+ @abc.abstractmethod
217
+ def map_time_default_value(self, hour: str, minutes: str, seconds: str, slot: SlotDefinition, cls: ClassDefinition):
218
+ raise NotImplementedError()
219
+
220
+ @abc.abstractmethod
221
+ def map_date_default_value(self, year: str, month: str, day: str, slot: SlotDefinition, cls: ClassDefinition):
222
+ raise NotImplementedError()
223
+
224
+ @abc.abstractmethod
225
+ def map_datetime_default_value(
226
+ self,
227
+ year: str,
228
+ month: str,
229
+ day: str,
230
+ hour: str,
231
+ minutes: str,
232
+ seconds: str,
233
+ slot: SlotDefinition,
234
+ cls: ClassDefinition,
235
+ ):
236
+ raise NotImplementedError()
237
+
238
+ @abc.abstractmethod
239
+ def map_uri_or_curie_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
240
+ raise NotImplementedError()
241
+
242
+ @abc.abstractmethod
243
+ def map_curie_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
244
+ raise NotImplementedError()
245
+
246
+ @abc.abstractmethod
247
+ def map_uri_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
248
+ raise NotImplementedError()
249
+
250
+ @abc.abstractmethod
251
+ def map_nc_name_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
252
+ raise NotImplementedError()
253
+
254
+ @abc.abstractmethod
255
+ def map_object_identifier_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
256
+ raise NotImplementedError()
257
+
258
+ @abc.abstractmethod
259
+ def map_node_identifier_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
260
+ raise NotImplementedError()
261
+
262
+ @abc.abstractmethod
263
+ def map_json_pointer_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
264
+ raise NotImplementedError()
265
+
266
+ @abc.abstractmethod
267
+ def map_json_path_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
268
+ raise NotImplementedError()
269
+
270
+ @abc.abstractmethod
271
+ def map_sparql_path_default_value(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition):
272
+ raise NotImplementedError()
273
+
274
+ @abc.abstractmethod
275
+ def map_enum_default_value(
276
+ self, enum_name: EnumDefinitionName, permissible_value_name: str, slot: SlotDefinition, cls: ClassDefinition
277
+ ):
278
+ raise NotImplementedError()
279
+
280
+ def _uri_for(self, s: str) -> str:
281
+ uri = str(self.schema_view.namespaces().uri_for(s))
282
+ return self.schema_view.namespaces().curie_for(uri, True, True) or self._strval(uri)
283
+
284
+ def _strval(self, txt: str) -> str:
285
+ txt = str(txt).replace('"', '\\"')
286
+ return f'"{txt}"'
@@ -21,11 +21,11 @@ Name: {{ schema.name }}
21
21
  | --- | --- |
22
22
  {% if gen.hierarchical_class_view -%}
23
23
  {% for u, v in gen.class_hierarchy_as_tuples() -%}
24
- | {{ "&nbsp;"|safe*u*8 }}{{ gen.link(schemaview.get_class(v)) }} | {{ schemaview.get_class(v).description }} |
24
+ | {{ "&nbsp;"|safe*u*8 }}{{ gen.link(schemaview.get_class(v), True) }} | {{ schemaview.get_class(v).description }} |
25
25
  {% endfor %}
26
26
  {% else -%}
27
27
  {% for c in gen.all_class_objects()|sort(attribute=sort_by) -%}
28
- | {{gen.link(c)}} | {{c.description|enshorten}} |
28
+ | {{gen.link(c, True)}} | {{c.description|enshorten}} |
29
29
  {% endfor %}
30
30
  {% endif %}
31
31
 
@@ -34,7 +34,7 @@ Name: {{ schema.name }}
34
34
  | Slot | Description |
35
35
  | --- | --- |
36
36
  {% for s in gen.all_slot_objects()|sort(attribute=sort_by) -%}
37
- | {{gen.link(s)}} | {{s.description|enshorten}} |
37
+ | {{gen.link(s, True)}} | {{s.description|enshorten}} |
38
38
  {% endfor %}
39
39
 
40
40
  ## Enumerations
@@ -42,7 +42,7 @@ Name: {{ schema.name }}
42
42
  | Enumeration | Description |
43
43
  | --- | --- |
44
44
  {% for e in gen.all_enum_objects()|sort(attribute=sort_by) -%}
45
- | {{gen.link(e)}} | {{e.description|enshorten}} |
45
+ | {{gen.link(e, True)}} | {{e.description|enshorten}} |
46
46
  {% endfor %}
47
47
 
48
48
  ## Types
@@ -50,7 +50,7 @@ Name: {{ schema.name }}
50
50
  | Type | Description |
51
51
  | --- | --- |
52
52
  {% for t in gen.all_type_objects()|sort(attribute=sort_by) -%}
53
- | {{gen.link(t)}} | {{t.description|enshorten}} |
53
+ | {{gen.link(t, True)}} | {{t.description|enshorten}} |
54
54
  {% endfor %}
55
55
 
56
56
  ## Subsets
@@ -58,5 +58,5 @@ Name: {{ schema.name }}
58
58
  | Subset | Description |
59
59
  | --- | --- |
60
60
  {% for ss in schemaview.all_subsets().values()|sort(attribute='name') -%}
61
- | {{gen.link(ss)}} | {{ss.description|enshorten}} |
61
+ | {{gen.link(ss, True)}} | {{ss.description|enshorten}} |
62
62
  {% endfor %}
@@ -50,6 +50,13 @@ DIALECT = MarkdownDialect
50
50
  MAX_CHARS_IN_TABLE = 80
51
51
  MAX_RANK = 1000
52
52
 
53
+ SCHEMA_SUBFOLDER = "schemas"
54
+ CLASS_SUBFOLDER = "classes"
55
+ SLOT_SUBFOLDER = "slots"
56
+ ENUM_SUBFOLDER = "enums"
57
+ TYPE_SUBFOLDER = "types"
58
+ SUBSET_SUBFOLDER = "subsets"
59
+
53
60
 
54
61
  def enshorten(input):
55
62
  """
@@ -144,6 +151,9 @@ class DocGenerator(Generator):
144
151
  include_top_level_diagram: bool = False
145
152
  """Whether the index page should include a schema diagram"""
146
153
 
154
+ subfolder_type_separation: bool = False
155
+ """Whether each type (class, slot, etc.) should be put in separate subfolder for navigation purposes"""
156
+
147
157
  example_directory: Optional[str] = None
148
158
  example_runner: ExampleRunner = field(default_factory=lambda: ExampleRunner())
149
159
 
@@ -205,7 +215,11 @@ class DocGenerator(Generator):
205
215
  self.logger.debug(f" Generating doc for {schema_name}")
206
216
  imported_schema = sv.schema_map.get(schema_name)
207
217
  out_str = template.render(gen=self, schema=imported_schema, schemaview=sv, **template_vars)
208
- self._write(out_str, directory, imported_schema.name)
218
+ self._write(
219
+ out_str,
220
+ f"{directory}/{SCHEMA_SUBFOLDER}" if self.subfolder_type_separation else directory,
221
+ imported_schema.name,
222
+ )
209
223
  self.logger.debug("Processing Classes...")
210
224
  template = self._get_template("class")
211
225
  for cn, c in sv.all_classes().items():
@@ -214,7 +228,7 @@ class DocGenerator(Generator):
214
228
  n = self.name(c)
215
229
  self.logger.debug(f" Generating doc for {n}")
216
230
  out_str = template.render(gen=self, element=c, schemaview=sv, **template_vars)
217
- self._write(out_str, directory, n)
231
+ self._write(out_str, f"{directory}/{CLASS_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
218
232
  self.logger.debug("Processing Slots...")
219
233
  template = self._get_template("slot")
220
234
  for sn, s in sv.all_slots().items():
@@ -224,7 +238,7 @@ class DocGenerator(Generator):
224
238
  self.logger.debug(f" Generating doc for {n}")
225
239
  s = sv.induced_slot(sn)
226
240
  out_str = template.render(gen=self, element=s, schemaview=sv, **template_vars)
227
- self._write(out_str, directory, n)
241
+ self._write(out_str, f"{directory}/{SLOT_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
228
242
  self.logger.debug("Processing Enums...")
229
243
  template = self._get_template("enum")
230
244
  for en, e in sv.all_enums().items():
@@ -233,7 +247,7 @@ class DocGenerator(Generator):
233
247
  n = self.name(e)
234
248
  self.logger.debug(f" Generating doc for {n}")
235
249
  out_str = template.render(gen=self, element=e, schemaview=sv, **template_vars)
236
- self._write(out_str, directory, n)
250
+ self._write(out_str, f"{directory}/{ENUM_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
237
251
  self.logger.debug("Processing Types...")
238
252
  template = self._get_template("type")
239
253
  for tn, t in sv.all_types().items():
@@ -243,7 +257,7 @@ class DocGenerator(Generator):
243
257
  self.logger.debug(f" Generating doc for {n}")
244
258
  t = sv.induced_type(tn)
245
259
  out_str = template.render(gen=self, element=t, schemaview=sv, **template_vars)
246
- self._write(out_str, directory, n)
260
+ self._write(out_str, f"{directory}/{TYPE_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
247
261
  self.logger.debug("Processing Subsets...")
248
262
  template = self._get_template("subset")
249
263
  for _, s in sv.all_subsets().items():
@@ -252,7 +266,7 @@ class DocGenerator(Generator):
252
266
  n = self.name(s)
253
267
  self.logger.debug(f" Generating doc for {n}")
254
268
  out_str = template.render(gen=self, element=s, schemaview=sv, **template_vars)
255
- self._write(out_str, directory, n)
269
+ self._write(out_str, f"{directory}/{SUBSET_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
256
270
 
257
271
  def _write(self, out_str: str, directory: str, name: str) -> None:
258
272
  """
@@ -384,13 +398,19 @@ class DocGenerator(Generator):
384
398
  curie = self.uri(element, expand=False)
385
399
  return f"[{curie}]({uri})"
386
400
 
387
- def link(self, e: Union[Definition, DefinitionName]) -> str:
401
+ def link(self, e: Union[Definition, DefinitionName], index_link: bool = False) -> str:
388
402
  """
389
403
  Render an element as a hyperlink
390
404
 
391
405
  :param e:
406
+ :param index_link: Whether this is a link for the index page or not
392
407
  :return:
393
408
  """
409
+ if index_link:
410
+ subfolder = ""
411
+ else:
412
+ subfolder = "../"
413
+
394
414
  if e is None:
395
415
  return "NONE"
396
416
  if not isinstance(e, Definition):
@@ -401,20 +421,43 @@ class DocGenerator(Generator):
401
421
  if self.use_class_uris:
402
422
  curie = self.schemaview.get_uri(e)
403
423
  if curie is not None:
404
- return self._markdown_link(n=curie.split(":")[1], name=e.name)
405
- return self._markdown_link(camelcase(e.name))
424
+ return self._markdown_link(
425
+ n=curie.split(":")[1],
426
+ name=e.name,
427
+ subfolder=subfolder + CLASS_SUBFOLDER if self.subfolder_type_separation else None,
428
+ )
429
+ return self._markdown_link(
430
+ camelcase(e.name),
431
+ subfolder=subfolder + CLASS_SUBFOLDER if self.subfolder_type_separation else None,
432
+ )
406
433
  elif isinstance(e, EnumDefinition):
407
- return self._markdown_link(camelcase(e.name))
434
+ return self._markdown_link(
435
+ camelcase(e.name),
436
+ subfolder=subfolder + ENUM_SUBFOLDER if self.subfolder_type_separation else None,
437
+ )
408
438
  elif isinstance(e, SlotDefinition):
409
439
  if self.use_slot_uris:
410
440
  curie = self.schemaview.get_uri(e)
411
441
  if curie is not None:
412
- return self._markdown_link(n=curie.split(":")[1], name=e.name)
413
- return self._markdown_link(underscore(e.name))
442
+ return self._markdown_link(
443
+ n=curie.split(":")[1],
444
+ name=e.name,
445
+ subfolder=subfolder + SLOT_SUBFOLDER if self.subfolder_type_separation else None,
446
+ )
447
+ return self._markdown_link(
448
+ underscore(e.name),
449
+ subfolder=subfolder + SLOT_SUBFOLDER if self.subfolder_type_separation else None,
450
+ )
414
451
  elif isinstance(e, TypeDefinition):
415
- return self._markdown_link(camelcase(e.name))
452
+ return self._markdown_link(
453
+ camelcase(e.name),
454
+ subfolder=subfolder + TYPE_SUBFOLDER if self.subfolder_type_separation else None,
455
+ )
416
456
  elif isinstance(e, SubsetDefinition):
417
- return self._markdown_link(camelcase(e.name))
457
+ return self._markdown_link(
458
+ camelcase(e.name),
459
+ subfolder=subfolder + SUBSET_SUBFOLDER if self.subfolder_type_separation else None,
460
+ )
418
461
  else:
419
462
  return e.name
420
463
 
@@ -977,6 +1020,11 @@ Include LinkML Schema outside of imports mechanism. Helpful in including deprec
977
1020
  YAML, and including it when necessary but not by default (e.g. in documentation or for backwards compatibility)
978
1021
  """,
979
1022
  )
1023
+ @click.option(
1024
+ "--subfolder-type-separation/--no-subfolder-type-separation",
1025
+ default=False,
1026
+ help="Separate type (class, slot, etc.) outputs in different subfolders for navigation purposes",
1027
+ )
980
1028
  @click.version_option(__version__, "-V", "--version")
981
1029
  @click.command(name="doc")
982
1030
  def cli(
@@ -988,6 +1036,7 @@ def cli(
988
1036
  use_slot_uris,
989
1037
  use_class_uris,
990
1038
  hierarchical_class_view,
1039
+ subfolder_type_separation,
991
1040
  **args,
992
1041
  ):
993
1042
  """Generate documentation folder from a LinkML YAML schema
@@ -1018,6 +1067,7 @@ def cli(
1018
1067
  use_class_uris=use_class_uris,
1019
1068
  hierarchical_class_view=hierarchical_class_view,
1020
1069
  index_name=index_name,
1070
+ subfolder_type_separation=subfolder_type_separation,
1021
1071
  **args,
1022
1072
  )
1023
1073
  print(gen.serialize())
@@ -11,6 +11,8 @@ from linkml_runtime.utils.formatutils import camelcase, underscore
11
11
  from linkml._version import __version__
12
12
  from linkml.utils.generator import Generator, shared_arguments
13
13
 
14
+ logger = logging.getLogger(__name__)
15
+
14
16
  type_map = {
15
17
  "str": "string",
16
18
  "int": "int",
@@ -175,7 +177,7 @@ class GolangGenerator(Generator):
175
177
  if t.base and t.base in type_map:
176
178
  return type_map[t.base]
177
179
  else:
178
- logging.warning(f"Unknown type.base: {t.name}")
180
+ logger.warning(f"Unknown type.base: {t.name}")
179
181
  return "string"
180
182
 
181
183
  @staticmethod
@@ -21,7 +21,6 @@ from linkml.utils.generator import Generator, shared_arguments
21
21
  URI_RANGES = (SHEX.nonliteral, SHEX.bnode, SHEX.iri)
22
22
 
23
23
  ENUM_CONTEXT = {
24
- "@vocab": "@null",
25
24
  "text": "skos:notation",
26
25
  "description": "skos:prefLabel",
27
26
  "meaning": "@id",
@@ -24,6 +24,8 @@ from linkml._version import __version__
24
24
  from linkml.generators.common.type_designators import get_type_designator_value
25
25
  from linkml.utils.generator import Generator, shared_arguments
26
26
 
27
+ logger = logging.getLogger(__name__)
28
+
27
29
  # Map from underlying python data type to json equivalent
28
30
  # Note: The underlying types are a union of any built-in python datatype + any type defined in
29
31
  # linkml-runtime/utils/metamodelcore.py
@@ -222,14 +224,14 @@ class JsonSchemaGenerator(Generator):
222
224
 
223
225
  def __post_init__(self):
224
226
  if self.topClass:
225
- logging.warning("topClass is deprecated - use top_class")
227
+ logger.warning("topClass is deprecated - use top_class")
226
228
  self.top_class = self.topClass
227
229
 
228
230
  super().__post_init__()
229
231
 
230
232
  if self.top_class:
231
233
  if self.schemaview.get_class(self.top_class) is None:
232
- logging.warning(f"No class in schema named {self.top_class}")
234
+ logger.warning(f"No class in schema named {self.top_class}")
233
235
 
234
236
  def start_schema(self, inline: bool = False) -> JsonSchema:
235
237
  self.inline = inline