linkml 1.8.3__tar.gz → 1.8.5__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 (161) hide show
  1. {linkml-1.8.3 → linkml-1.8.5}/PKG-INFO +3 -1
  2. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/__init__.py +2 -0
  3. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/common/ifabsent_processor.py +98 -21
  4. linkml-1.8.5/linkml/generators/common/naming.py +106 -0
  5. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/index.md.jinja2 +6 -6
  6. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen.py +80 -21
  7. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/golanggen.py +3 -1
  8. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/graphqlgen.py +34 -2
  9. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/jsonschemagen.py +4 -2
  10. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/owlgen.py +36 -17
  11. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/projectgen.py +13 -11
  12. linkml-1.8.5/linkml/generators/pydanticgen/array.py +662 -0
  13. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/build.py +4 -2
  14. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/pydanticgen.py +35 -16
  15. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/template.py +119 -3
  16. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/imports.py.jinja +11 -3
  17. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/module.py.jinja +1 -3
  18. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/validator.py.jinja +2 -2
  19. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/python/python_ifabsent_processor.py +1 -1
  20. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pythongen.py +135 -31
  21. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/shaclgen.py +34 -10
  22. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sparqlgen.py +3 -1
  23. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sqlalchemygen.py +5 -3
  24. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sqltablegen.py +4 -2
  25. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/typescriptgen.py +13 -6
  26. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/linter.py +2 -1
  27. {linkml-1.8.3 → linkml-1.8.5}/linkml/transformers/logical_model_transformer.py +3 -3
  28. {linkml-1.8.3 → linkml-1.8.5}/linkml/transformers/relmodel_transformer.py +18 -4
  29. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/converter.py +3 -1
  30. linkml-1.8.5/linkml/utils/exceptions.py +11 -0
  31. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/execute_tutorial.py +22 -20
  32. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/generator.py +6 -4
  33. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/mergeutils.py +4 -2
  34. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/schema_fixer.py +5 -5
  35. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/schemaloader.py +5 -3
  36. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/sqlutils.py +3 -1
  37. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/plugins/pydantic_validation_plugin.py +1 -1
  38. {linkml-1.8.3 → linkml-1.8.5}/linkml/validators/jsonschemavalidator.py +3 -1
  39. {linkml-1.8.3 → linkml-1.8.5}/linkml/validators/sparqlvalidator.py +5 -3
  40. {linkml-1.8.3 → linkml-1.8.5}/linkml/workspaces/example_runner.py +3 -1
  41. {linkml-1.8.3 → linkml-1.8.5}/pyproject.toml +11 -4
  42. {linkml-1.8.3 → linkml-1.8.5}/setup.py +4 -2
  43. linkml-1.8.3/linkml/generators/pydanticgen/array.py +0 -378
  44. {linkml-1.8.3 → linkml-1.8.5}/LICENSE +0 -0
  45. {linkml-1.8.3 → linkml-1.8.5}/README.md +0 -0
  46. {linkml-1.8.3 → linkml-1.8.5}/linkml/__init__.py +0 -0
  47. {linkml-1.8.3 → linkml-1.8.5}/linkml/_version.py +0 -0
  48. {linkml-1.8.3 → linkml-1.8.5}/linkml/cli/__init__.py +0 -0
  49. {linkml-1.8.3 → linkml-1.8.5}/linkml/cli/__main__.py +0 -0
  50. {linkml-1.8.3 → linkml-1.8.5}/linkml/cli/main.py +0 -0
  51. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/PythonGenNotes.md +0 -0
  52. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/README.md +0 -0
  53. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/common/__init__.py +0 -0
  54. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/common/build.py +0 -0
  55. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/common/lifecycle.py +0 -0
  56. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/common/template.py +0 -0
  57. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/common/type_designators.py +0 -0
  58. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/csvgen.py +0 -0
  59. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/class.md.jinja2 +0 -0
  60. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/class_diagram.md.jinja2 +0 -0
  61. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/common_metadata.md.jinja2 +0 -0
  62. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/enum.md.jinja2 +0 -0
  63. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/index.tex.jinja2 +0 -0
  64. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/schema.md.jinja2 +0 -0
  65. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/slot.md.jinja2 +0 -0
  66. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/subset.md.jinja2 +0 -0
  67. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/docgen/type.md.jinja2 +0 -0
  68. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/dotgen.py +0 -0
  69. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/erdiagramgen.py +0 -0
  70. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/excelgen.py +0 -0
  71. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/golrgen.py +0 -0
  72. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/javagen/example_template.java.jinja2 +0 -0
  73. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/javagen/java_record_template.jinja2 +0 -0
  74. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/javagen.py +0 -0
  75. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/jsonldcontextgen.py +0 -0
  76. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/jsonldgen.py +0 -0
  77. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/legacy/__init__.py +0 -0
  78. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/linkmlgen.py +0 -0
  79. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/markdowngen.py +0 -0
  80. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/namespacegen.py +0 -0
  81. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/oocodegen.py +0 -0
  82. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/plantumlgen.py +0 -0
  83. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/prefixmapgen.py +0 -0
  84. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/protogen.py +0 -0
  85. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/__init__.py +0 -0
  86. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/black.py +0 -0
  87. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/includes.py +0 -0
  88. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/attribute.py.jinja +0 -0
  89. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/base_model.py.jinja +0 -0
  90. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/class.py.jinja +0 -0
  91. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/conditional_import.py.jinja +0 -0
  92. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/enum.py.jinja +0 -0
  93. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/pydanticgen/templates/footer.py.jinja +0 -0
  94. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/python/__init__.py +0 -0
  95. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/rdfgen.py +0 -0
  96. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/shacl/__init__.py +0 -0
  97. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/shacl/shacl_data_type.py +0 -0
  98. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/shacl/shacl_ifabsent_processor.py +0 -0
  99. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/shexgen.py +0 -0
  100. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sqlalchemy/__init__.py +0 -0
  101. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +0 -0
  102. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +0 -0
  103. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/sssomgen.py +0 -0
  104. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/string_template.md +0 -0
  105. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/summarygen.py +0 -0
  106. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/terminusdbgen.py +0 -0
  107. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/yamlgen.py +0 -0
  108. {linkml-1.8.3 → linkml-1.8.5}/linkml/generators/yumlgen.py +0 -0
  109. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/__init__.py +0 -0
  110. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/cli.py +0 -0
  111. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/config/datamodel/.linkmllint.yaml +0 -0
  112. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/config/datamodel/__init__.py +0 -0
  113. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/config/datamodel/config.py +0 -0
  114. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/config/datamodel/config.yaml +0 -0
  115. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/config/default.yaml +0 -0
  116. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/config/recommended.yaml +0 -0
  117. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/formatters/__init__.py +0 -0
  118. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/formatters/formatter.py +0 -0
  119. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/formatters/json_formatter.py +0 -0
  120. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/formatters/markdown_formatter.py +0 -0
  121. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/formatters/terminal_formatter.py +0 -0
  122. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/formatters/tsv_formatter.py +0 -0
  123. {linkml-1.8.3 → linkml-1.8.5}/linkml/linter/rules.py +0 -0
  124. {linkml-1.8.3 → linkml-1.8.5}/linkml/reporting/__init__.py +0 -0
  125. {linkml-1.8.3 → linkml-1.8.5}/linkml/reporting/model.py +0 -0
  126. {linkml-1.8.3 → linkml-1.8.5}/linkml/transformers/__init__.py +0 -0
  127. {linkml-1.8.3 → linkml-1.8.5}/linkml/transformers/model_transformer.py +0 -0
  128. {linkml-1.8.3 → linkml-1.8.5}/linkml/transformers/schema_renamer.py +0 -0
  129. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/__init__.py +0 -0
  130. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/cli_utils.py +0 -0
  131. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/datautils.py +0 -0
  132. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/datavalidator.py +0 -0
  133. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/deprecation.py +0 -0
  134. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/helpers.py +0 -0
  135. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/logictools.py +0 -0
  136. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/rawloader.py +0 -0
  137. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/schema_builder.py +0 -0
  138. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/schemasynopsis.py +0 -0
  139. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/typereferences.py +0 -0
  140. {linkml-1.8.3 → linkml-1.8.5}/linkml/utils/validation.py +0 -0
  141. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/__init__.py +0 -0
  142. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/cli.py +0 -0
  143. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/loaders/__init__.py +0 -0
  144. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/loaders/delimited_file_loader.py +0 -0
  145. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/loaders/json_loader.py +0 -0
  146. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/loaders/loader.py +0 -0
  147. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/loaders/passthrough_loader.py +0 -0
  148. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/loaders/yaml_loader.py +0 -0
  149. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/plugins/__init__.py +0 -0
  150. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/plugins/jsonschema_validation_plugin.py +0 -0
  151. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/plugins/recommended_slots_plugin.py +0 -0
  152. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/plugins/shacl_validation_plugin.py +0 -0
  153. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/plugins/validation_plugin.py +0 -0
  154. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/report.py +0 -0
  155. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/validation_context.py +0 -0
  156. {linkml-1.8.3 → linkml-1.8.5}/linkml/validator/validator.py +0 -0
  157. {linkml-1.8.3 → linkml-1.8.5}/linkml/validators/__init__.py +0 -0
  158. {linkml-1.8.3 → linkml-1.8.5}/linkml/workspaces/__init__.py +0 -0
  159. {linkml-1.8.3 → linkml-1.8.5}/linkml/workspaces/datamodel/__init__.py +0 -0
  160. {linkml-1.8.3 → linkml-1.8.5}/linkml/workspaces/datamodel/workspaces.py +0 -0
  161. {linkml-1.8.3 → linkml-1.8.5}/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.3
3
+ Version: 1.8.5
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)
@@ -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
@@ -1,7 +1,13 @@
1
1
  import abc
2
2
  import re
3
+ import sys
3
4
  from abc import ABC
4
- from typing import Any, Optional
5
+ from typing import Any, Optional, Type, Union
6
+
7
+ if sys.version_info < (3, 10):
8
+ from typing_extensions import TypeAlias
9
+ else:
10
+ from typing import TypeAlias
5
11
 
6
12
  from linkml_runtime import SchemaView
7
13
  from linkml_runtime.linkml_model import (
@@ -18,6 +24,7 @@ from linkml_runtime.linkml_model import (
18
24
  String,
19
25
  Time,
20
26
  Uri,
27
+ types,
21
28
  )
22
29
  from linkml_runtime.linkml_model.types import (
23
30
  Curie,
@@ -31,6 +38,34 @@ from linkml_runtime.linkml_model.types import (
31
38
  Uriorcurie,
32
39
  )
33
40
 
41
+ TYPES_TYPE: TypeAlias = Union[
42
+ Type[Boolean],
43
+ Type[Curie],
44
+ Type[Date],
45
+ Type[DateOrDatetime],
46
+ Type[Datetime],
47
+ Type[Decimal],
48
+ Type[Double],
49
+ Type[Float],
50
+ Type[Integer],
51
+ Type[Jsonpath],
52
+ Type[Jsonpointer],
53
+ Type[Ncname],
54
+ Type[Nodeidentifier],
55
+ Type[Objectidentifier],
56
+ Type[Sparqlpath],
57
+ Type[String],
58
+ Type[Time],
59
+ Type[Uri],
60
+ Type[Uriorcurie],
61
+ ]
62
+
63
+ TYPES = [
64
+ t
65
+ for t in types.__dict__.values()
66
+ if isinstance(t, type) and t.__module__ == types.__name__ and hasattr(t, "type_name")
67
+ ]
68
+
34
69
 
35
70
  class IfAbsentProcessor(ABC):
36
71
  """
@@ -39,7 +74,7 @@ class IfAbsentProcessor(ABC):
39
74
  See `<https://w3id.org/linkml/ifabsent>`_.
40
75
  """
41
76
 
42
- ifabsent_regex = re.compile("""(?:(?P<type>\w+)\()?[\"\']?(?P<default_value>[^\(\)\"\')]*)[\"\']?\)?""")
77
+ ifabsent_regex = re.compile(r"""(?:(?P<type>\w+)\()?[\"\']?(?P<default_value>[^\(\)\"\')]*)[\"\']?\)?""")
43
78
 
44
79
  def __init__(self, schema_view: SchemaView):
45
80
  self.schema_view = schema_view
@@ -61,10 +96,12 @@ class IfAbsentProcessor(ABC):
61
96
  if mapped:
62
97
  return custom_default_value
63
98
 
64
- if slot.range == String.type_name:
99
+ base_type = self._base_type(slot.range)
100
+
101
+ if base_type is String:
65
102
  return self.map_string_default_value(ifabsent_default_value, slot, cls)
66
103
 
67
- if slot.range == Boolean.type_name:
104
+ if base_type is Boolean:
68
105
  if re.match(r"^[Tt]rue$", ifabsent_default_value):
69
106
  return self.map_boolean_true_default_value(slot, cls)
70
107
  elif re.match(r"^[Ff]alse$", ifabsent_default_value):
@@ -75,19 +112,19 @@ class IfAbsentProcessor(ABC):
75
112
  f"value"
76
113
  )
77
114
 
78
- if slot.range == Integer.type_name:
115
+ if base_type is Integer:
79
116
  return self.map_integer_default_value(ifabsent_default_value, slot, cls)
80
117
 
81
- if slot.range == Float.type_name:
118
+ if base_type is Float:
82
119
  return self.map_float_default_value(ifabsent_default_value, slot, cls)
83
120
 
84
- if slot.range == Double.type_name:
121
+ if base_type is Double:
85
122
  return self.map_double_default_value(ifabsent_default_value, slot, cls)
86
123
 
87
- if slot.range == Decimal.type_name:
124
+ if base_type is Decimal:
88
125
  return self.map_decimal_default_value(ifabsent_default_value, slot, cls)
89
126
 
90
- if slot.range == Time.type_name:
127
+ if base_type is Time:
91
128
  match = re.match(r"^(\d{2}):(\d{2}):(\d{2}).*$", ifabsent_default_value)
92
129
  if match:
93
130
  return self.map_time_default_value(match[1], match[2], match[3], slot, cls)
@@ -97,7 +134,7 @@ class IfAbsentProcessor(ABC):
97
134
  )
98
135
 
99
136
  # TODO manage timezones and offsets
100
- if slot.range == Date.type_name:
137
+ if base_type is Date:
101
138
  match = re.match(r"^(\d{4})-(\d{2})-(\d{2})$", ifabsent_default_value)
102
139
  if match:
103
140
  return self.map_date_default_value(match[1], match[2], match[3], slot, cls)
@@ -107,7 +144,7 @@ class IfAbsentProcessor(ABC):
107
144
  )
108
145
 
109
146
  # TODO manage timezones and offsets
110
- if slot.range == Datetime.type_name:
147
+ if base_type is Datetime:
111
148
  match = re.match(r"^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).*$", ifabsent_default_value)
112
149
  if match:
113
150
  return self.map_datetime_default_value(
@@ -120,7 +157,7 @@ class IfAbsentProcessor(ABC):
120
157
  )
121
158
 
122
159
  # TODO manage timezones and offsets
123
- if slot.range == DateOrDatetime.type_name:
160
+ if base_type is DateOrDatetime:
124
161
  match = re.match(r"^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2}))?.*$", ifabsent_default_value)
125
162
  if match and (match[4] is None or match[5] is None or match[6] is None):
126
163
  return self.map_date_default_value(match[1], match[2], match[3], slot, cls)
@@ -134,31 +171,31 @@ class IfAbsentProcessor(ABC):
134
171
  f"datetime value"
135
172
  )
136
173
 
137
- if slot.range == Uri.type_name:
174
+ if base_type is Uri:
138
175
  return self.map_uri_default_value(ifabsent_default_value, slot, cls)
139
176
 
140
- if slot.range == Curie.type_name:
177
+ if base_type is Curie:
141
178
  return self.map_curie_default_value(ifabsent_default_value, slot, cls)
142
179
 
143
- if slot.range == Uriorcurie.type_name:
180
+ if base_type is Uriorcurie:
144
181
  return self.map_uri_or_curie_default_value(ifabsent_default_value, slot, cls)
145
182
 
146
- if slot.range == Ncname.type_name:
183
+ if base_type is Ncname:
147
184
  return self.map_nc_name_default_value(ifabsent_default_value, slot, cls)
148
185
 
149
- if slot.range == Objectidentifier.type_name:
186
+ if base_type is Objectidentifier:
150
187
  return self.map_object_identifier_default_value(ifabsent_default_value, slot, cls)
151
188
 
152
- if slot.range == Nodeidentifier.type_name:
189
+ if base_type is Nodeidentifier:
153
190
  return self.map_node_identifier_default_value(ifabsent_default_value, slot, cls)
154
191
 
155
- if slot.range == Jsonpointer.type_name:
192
+ if base_type is Jsonpointer:
156
193
  return self.map_json_pointer_default_value(ifabsent_default_value, slot, cls)
157
194
 
158
- if slot.range == Jsonpath.type_name:
195
+ if base_type is Jsonpath:
159
196
  return self.map_json_path_default_value(ifabsent_default_value, slot, cls)
160
197
 
161
- if slot.range == Sparqlpath.type_name:
198
+ if base_type is Sparqlpath:
162
199
  return self.map_sparql_path_default_value(ifabsent_default_value, slot, cls)
163
200
 
164
201
  # -----------------------
@@ -173,6 +210,46 @@ class IfAbsentProcessor(ABC):
173
210
 
174
211
  raise ValueError(f"The ifabsent value `{slot.ifabsent}` of the `{slot.name}` slot could not be processed")
175
212
 
213
+ def _base_type(self, range_: str) -> Optional[TYPES_TYPE]:
214
+ """
215
+ Find the linkml base type that corresponds to either a matching type_name or custom type
216
+
217
+ First check for an explicit match of the range == TypeDefinition.type_name
218
+ Then check for explicit inheritance via typeof
219
+ Finally check for implicit matching via matching base
220
+
221
+ Don't raise here, just return None in case another method of resolution like enums are
222
+ available
223
+ """
224
+ # first check for matching type using type_name - ie. range is already a base type
225
+
226
+ for typ in TYPES:
227
+ if range_ == typ.type_name:
228
+ return typ
229
+
230
+ # if we're not a type, return None to indicate that, e.g. if an enum's permissible_value
231
+ if range_ not in self.schema_view.all_types(imports=True):
232
+ return
233
+
234
+ # then check explicit descendents of types
235
+ # base types do not inherit from one another, so the last ancestor is always a base type
236
+ # if it is inheriting from a base type
237
+ ancestor = self.schema_view.type_ancestors(range_)[-1]
238
+ for typ in TYPES:
239
+ if ancestor == typ.type_name:
240
+ return typ
241
+
242
+ # finally check if we have a matching base
243
+ induced_typ = self.schema_view.induced_type(range_)
244
+ if induced_typ.repr is None and induced_typ.base is None:
245
+ return None
246
+ for typ in TYPES:
247
+ # types always inherit from a single type, and that type is their base
248
+ # our range can match it with repr or base
249
+ typ_base = typ.__mro__[1].__name__
250
+ if typ_base == induced_typ.base:
251
+ return typ
252
+
176
253
  @abc.abstractmethod
177
254
  def map_custom_default_values(self, default_value: str, slot: SlotDefinition, cls: ClassDefinition) -> (bool, str):
178
255
  """
@@ -0,0 +1,106 @@
1
+ import logging
2
+ import re
3
+ import unicodedata
4
+ from enum import Enum
5
+
6
+
7
+ class NamingProfiles(str, Enum):
8
+ # GraphQL naming profile ensures compatibility with the GraphQL specification
9
+ # WRT names: https://spec.graphql.org/October2021/#Name
10
+ graphql = "graphql"
11
+
12
+
13
+ class NameCompatibility(object):
14
+ """Make a name compatible to the given profile"""
15
+
16
+ # heading double underscores and digit reserved to names starting with a digit
17
+ re_reserved_heading_digit = re.compile("^__[0-9]")
18
+ # valid name between double underscores is reserved for unicode name transformations
19
+ re_reserved_unicode_name_transformation = re.compile("__[0-9a-zA-Z][0-9a-zA-Z_]*__")
20
+ # something like '__U_xxxx_' is reserved for unicode code transformations
21
+ re_reserved_unicode_code_transformation = re.compile("__U_[0-9a-eA-E]{4}_")
22
+ # strings starting with a digit
23
+ re_heading_digit = re.compile("^[0-9]")
24
+ # character that is neither alphanumeric nor underscore
25
+ re_no_alphanum_underscore = re.compile("[^0-9a-zA-Z_]")
26
+
27
+ def __init__(self, profile: NamingProfiles, do_not_fix: bool = False):
28
+ """Specify the naming policy on instantiation"""
29
+ self.profile = profile
30
+ self.do_not_fix = do_not_fix
31
+
32
+ def _no_heading_digits(self, input: str) -> str:
33
+ """Ensure name does not start with a heading digit"""
34
+ output = input
35
+ if self.re_heading_digit.match(input):
36
+ if self.do_not_fix:
37
+ raise ValueError(f"Name '{input}' starts with digit (illegal GraphQL) and will not be fixed!")
38
+ else:
39
+ logging.warning(
40
+ f"Name '{input}' starts with digit (illegal GraphQL), "
41
+ + f"it has been prefixed with '__', resulting in {output}"
42
+ )
43
+ output = f"__{input}"
44
+ return output
45
+
46
+ def _transform_char(self, char: str) -> str:
47
+ """Transform unsupported characters"""
48
+ if len(char) != 1:
49
+ raise Exception(f"Single character expected, but got '{char}'!!")
50
+ # replace whitespaces with underscores
51
+ # the transformation cannot be inverted, but is a well-established
52
+ # and expected transformation
53
+ if char == " ":
54
+ return "_"
55
+ # try to use names for ASCII characters
56
+ if ord(char) < 128:
57
+ try:
58
+ # unicodedata.lookup should be able to invert the transformation
59
+ return f"__{unicodedata.name(char).replace(' ', '_').replace('-', '_')}__"
60
+ except ValueError:
61
+ pass
62
+ # fallback to code-transformation if none of the previous has worked
63
+ return f"__U_{ord(char):04X}_"
64
+
65
+ def _only_alphanum_underscore(self, input: str) -> str:
66
+ """Ensure name does not contain any unsupported characters"""
67
+ output = input
68
+ # with re.split and re.findall we get in the same order and separated in two arrays
69
+ # the substrings between special characters and the special characters
70
+ no_alphanum_underscore_match = self.re_no_alphanum_underscore.findall(input)
71
+ if no_alphanum_underscore_match:
72
+ if self.do_not_fix:
73
+ raise ValueError(f"Name '{input}' contains a character illegal in GraphQL and will not be fixed!")
74
+ else:
75
+ logging.warning(
76
+ f"Name '{input}' contains a character illegal in GraphQL, "
77
+ + f"the resulting encoded name is {output}"
78
+ )
79
+ to_keep = self.re_no_alphanum_underscore.split(input)
80
+ # first comes first substring to keep
81
+ output = to_keep[0]
82
+ # each char replacement is followed by the next substring to keep
83
+ for offset in range(0, len(to_keep) - 1):
84
+ output = output + self._transform_char(no_alphanum_underscore_match[offset])
85
+ output = output + to_keep[offset + 1]
86
+ return output
87
+
88
+ def _graphql_compatibility(self, input: str) -> str:
89
+ """Ensure name compatibility with GraphQL name policies"""
90
+ # as of now, some (hopefully) very rare patterns are reserved to mark transformations
91
+ if self.re_reserved_heading_digit.match(input):
92
+ raise NotImplementedError("Names starting with a double underscore followed by a digit are not supported!!")
93
+ if self.re_reserved_unicode_name_transformation.match(input):
94
+ raise NotImplementedError("Names containing valid names between double underscores are not supported!!")
95
+ if self.re_reserved_unicode_code_transformation.match(input):
96
+ raise NotImplementedError("Names containing strings like '__U_xxxx_' are not supported!!")
97
+ # apply transformation
98
+ output = input
99
+ output = self._no_heading_digits(output)
100
+ output = self._only_alphanum_underscore(output)
101
+ return output
102
+
103
+ def compatible(self, input: str) -> str:
104
+ """Make given name compatible with the given naming policy."""
105
+ if self.profile == "graphql":
106
+ return self._graphql_compatibility(input)
@@ -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
 
@@ -154,6 +164,7 @@ class DocGenerator(Generator):
154
164
  use_slot_uris: bool = False
155
165
  use_class_uris: bool = False
156
166
  hierarchical_class_view: bool = False
167
+ render_imports: bool = False
157
168
 
158
169
  def __post_init__(self):
159
170
  dialect = self.dialect
@@ -205,7 +216,11 @@ class DocGenerator(Generator):
205
216
  self.logger.debug(f" Generating doc for {schema_name}")
206
217
  imported_schema = sv.schema_map.get(schema_name)
207
218
  out_str = template.render(gen=self, schema=imported_schema, schemaview=sv, **template_vars)
208
- self._write(out_str, directory, imported_schema.name)
219
+ self._write(
220
+ out_str,
221
+ f"{directory}/{SCHEMA_SUBFOLDER}" if self.subfolder_type_separation else directory,
222
+ imported_schema.name,
223
+ )
209
224
  self.logger.debug("Processing Classes...")
210
225
  template = self._get_template("class")
211
226
  for cn, c in sv.all_classes().items():
@@ -214,7 +229,7 @@ class DocGenerator(Generator):
214
229
  n = self.name(c)
215
230
  self.logger.debug(f" Generating doc for {n}")
216
231
  out_str = template.render(gen=self, element=c, schemaview=sv, **template_vars)
217
- self._write(out_str, directory, n)
232
+ self._write(out_str, f"{directory}/{CLASS_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
218
233
  self.logger.debug("Processing Slots...")
219
234
  template = self._get_template("slot")
220
235
  for sn, s in sv.all_slots().items():
@@ -224,7 +239,7 @@ class DocGenerator(Generator):
224
239
  self.logger.debug(f" Generating doc for {n}")
225
240
  s = sv.induced_slot(sn)
226
241
  out_str = template.render(gen=self, element=s, schemaview=sv, **template_vars)
227
- self._write(out_str, directory, n)
242
+ self._write(out_str, f"{directory}/{SLOT_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
228
243
  self.logger.debug("Processing Enums...")
229
244
  template = self._get_template("enum")
230
245
  for en, e in sv.all_enums().items():
@@ -233,7 +248,7 @@ class DocGenerator(Generator):
233
248
  n = self.name(e)
234
249
  self.logger.debug(f" Generating doc for {n}")
235
250
  out_str = template.render(gen=self, element=e, schemaview=sv, **template_vars)
236
- self._write(out_str, directory, n)
251
+ self._write(out_str, f"{directory}/{ENUM_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
237
252
  self.logger.debug("Processing Types...")
238
253
  template = self._get_template("type")
239
254
  for tn, t in sv.all_types().items():
@@ -243,7 +258,7 @@ class DocGenerator(Generator):
243
258
  self.logger.debug(f" Generating doc for {n}")
244
259
  t = sv.induced_type(tn)
245
260
  out_str = template.render(gen=self, element=t, schemaview=sv, **template_vars)
246
- self._write(out_str, directory, n)
261
+ self._write(out_str, f"{directory}/{TYPE_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
247
262
  self.logger.debug("Processing Subsets...")
248
263
  template = self._get_template("subset")
249
264
  for _, s in sv.all_subsets().items():
@@ -252,7 +267,7 @@ class DocGenerator(Generator):
252
267
  n = self.name(s)
253
268
  self.logger.debug(f" Generating doc for {n}")
254
269
  out_str = template.render(gen=self, element=s, schemaview=sv, **template_vars)
255
- self._write(out_str, directory, n)
270
+ self._write(out_str, f"{directory}/{SUBSET_SUBFOLDER}" if self.subfolder_type_separation else directory, n)
256
271
 
257
272
  def _write(self, out_str: str, directory: str, name: str) -> None:
258
273
  """
@@ -384,13 +399,19 @@ class DocGenerator(Generator):
384
399
  curie = self.uri(element, expand=False)
385
400
  return f"[{curie}]({uri})"
386
401
 
387
- def link(self, e: Union[Definition, DefinitionName]) -> str:
402
+ def link(self, e: Union[Definition, DefinitionName], index_link: bool = False) -> str:
388
403
  """
389
404
  Render an element as a hyperlink
390
405
 
391
406
  :param e:
407
+ :param index_link: Whether this is a link for the index page or not
392
408
  :return:
393
409
  """
410
+ if index_link:
411
+ subfolder = ""
412
+ else:
413
+ subfolder = "../"
414
+
394
415
  if e is None:
395
416
  return "NONE"
396
417
  if not isinstance(e, Definition):
@@ -401,20 +422,43 @@ class DocGenerator(Generator):
401
422
  if self.use_class_uris:
402
423
  curie = self.schemaview.get_uri(e)
403
424
  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))
425
+ return self._markdown_link(
426
+ n=curie.split(":")[1],
427
+ name=e.name,
428
+ subfolder=subfolder + CLASS_SUBFOLDER if self.subfolder_type_separation else None,
429
+ )
430
+ return self._markdown_link(
431
+ camelcase(e.name),
432
+ subfolder=subfolder + CLASS_SUBFOLDER if self.subfolder_type_separation else None,
433
+ )
406
434
  elif isinstance(e, EnumDefinition):
407
- return self._markdown_link(camelcase(e.name))
435
+ return self._markdown_link(
436
+ camelcase(e.name),
437
+ subfolder=subfolder + ENUM_SUBFOLDER if self.subfolder_type_separation else None,
438
+ )
408
439
  elif isinstance(e, SlotDefinition):
409
440
  if self.use_slot_uris:
410
441
  curie = self.schemaview.get_uri(e)
411
442
  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))
443
+ return self._markdown_link(
444
+ n=curie.split(":")[1],
445
+ name=e.name,
446
+ subfolder=subfolder + SLOT_SUBFOLDER if self.subfolder_type_separation else None,
447
+ )
448
+ return self._markdown_link(
449
+ underscore(e.name),
450
+ subfolder=subfolder + SLOT_SUBFOLDER if self.subfolder_type_separation else None,
451
+ )
414
452
  elif isinstance(e, TypeDefinition):
415
- return self._markdown_link(camelcase(e.name))
453
+ return self._markdown_link(
454
+ camelcase(e.name),
455
+ subfolder=subfolder + TYPE_SUBFOLDER if self.subfolder_type_separation else None,
456
+ )
416
457
  elif isinstance(e, SubsetDefinition):
417
- return self._markdown_link(camelcase(e.name))
458
+ return self._markdown_link(
459
+ camelcase(e.name),
460
+ subfolder=subfolder + SUBSET_SUBFOLDER if self.subfolder_type_separation else None,
461
+ )
418
462
  else:
419
463
  return e.name
420
464
 
@@ -716,7 +760,7 @@ class DocGenerator(Generator):
716
760
  Ensures rank is non-null
717
761
  :return: iterator
718
762
  """
719
- elts = self.schemaview.all_classes(imports=self.mergeimports).values()
763
+ elts = self.schemaview.all_classes(imports=self.render_imports).values()
720
764
  _ensure_ranked(elts)
721
765
  for e in elts:
722
766
  yield e
@@ -728,7 +772,7 @@ class DocGenerator(Generator):
728
772
  Ensures rank is non-null
729
773
  :return: iterator
730
774
  """
731
- elts = self.schemaview.all_slots(imports=self.mergeimports).values()
775
+ elts = self.schemaview.all_slots(imports=self.render_imports).values()
732
776
  _ensure_ranked(elts)
733
777
  for e in elts:
734
778
  yield e
@@ -740,7 +784,7 @@ class DocGenerator(Generator):
740
784
  Ensures rank is non-null
741
785
  :return: iterator
742
786
  """
743
- elts = self.schemaview.all_types(imports=self.mergeimports).values()
787
+ elts = self.schemaview.all_types(imports=self.render_imports).values()
744
788
  _ensure_ranked(elts)
745
789
  for e in elts:
746
790
  yield e
@@ -755,7 +799,7 @@ class DocGenerator(Generator):
755
799
  Ensures rank is non-null
756
800
  :return: iterator
757
801
  """
758
- elts = self.schemaview.all_enums(imports=self.mergeimports).values()
802
+ elts = self.schemaview.all_enums(imports=self.render_imports).values()
759
803
  _ensure_ranked(elts)
760
804
  for e in elts:
761
805
  yield e
@@ -767,7 +811,7 @@ class DocGenerator(Generator):
767
811
  Ensures rank is non-null
768
812
  :return: iterator
769
813
  """
770
- elts = self.schemaview.all_subsets(imports=self.mergeimports).values()
814
+ elts = self.schemaview.all_subsets(imports=self.render_imports).values()
771
815
  _ensure_ranked(elts)
772
816
  for e in elts:
773
817
  yield e
@@ -791,7 +835,7 @@ class DocGenerator(Generator):
791
835
  :return: tuples (depth: int, cls: ClassDefinitionName)
792
836
  """
793
837
  sv = self.schemaview
794
- roots = sv.class_roots(mixins=False, imports=self.mergeimports)
838
+ roots = sv.class_roots(mixins=False, imports=self.render_imports)
795
839
 
796
840
  # by default the classes are sorted alphabetically
797
841
  roots = sorted(roots, key=str.casefold, reverse=True)
@@ -805,7 +849,7 @@ class DocGenerator(Generator):
805
849
  depth, class_name = stack.pop()
806
850
  yield depth, class_name
807
851
  children = sorted(
808
- sv.class_children(class_name=class_name, mixins=False, imports=self.mergeimports),
852
+ sv.class_children(class_name=class_name, mixins=False, imports=self.render_imports),
809
853
  key=str.casefold,
810
854
  reverse=True,
811
855
  )
@@ -965,6 +1009,12 @@ class DocGenerator(Generator):
965
1009
  default=True,
966
1010
  help="Render class table on index page in a hierarchically indented view",
967
1011
  )
1012
+ @click.option(
1013
+ "--render-imports/--no-render-imports",
1014
+ default=False,
1015
+ show_default=True,
1016
+ help="Render also the documentation of elements from imported schemas",
1017
+ )
968
1018
  @click.option(
969
1019
  "--example-directory",
970
1020
  help="Folder in which example files are found. These are used to make inline examples",
@@ -977,6 +1027,11 @@ Include LinkML Schema outside of imports mechanism. Helpful in including deprec
977
1027
  YAML, and including it when necessary but not by default (e.g. in documentation or for backwards compatibility)
978
1028
  """,
979
1029
  )
1030
+ @click.option(
1031
+ "--subfolder-type-separation/--no-subfolder-type-separation",
1032
+ default=False,
1033
+ help="Separate type (class, slot, etc.) outputs in different subfolders for navigation purposes",
1034
+ )
980
1035
  @click.version_option(__version__, "-V", "--version")
981
1036
  @click.command(name="doc")
982
1037
  def cli(
@@ -988,6 +1043,8 @@ def cli(
988
1043
  use_slot_uris,
989
1044
  use_class_uris,
990
1045
  hierarchical_class_view,
1046
+ subfolder_type_separation,
1047
+ render_imports,
991
1048
  **args,
992
1049
  ):
993
1050
  """Generate documentation folder from a LinkML YAML schema
@@ -1018,6 +1075,8 @@ def cli(
1018
1075
  use_class_uris=use_class_uris,
1019
1076
  hierarchical_class_view=hierarchical_class_view,
1020
1077
  index_name=index_name,
1078
+ subfolder_type_separation=subfolder_type_separation,
1079
+ render_imports=render_imports,
1021
1080
  **args,
1022
1081
  )
1023
1082
  print(gen.serialize())