linkml 1.8.3__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 (160) hide show
  1. {linkml-1.8.3 → linkml-1.8.4}/PKG-INFO +3 -1
  2. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/__init__.py +2 -0
  3. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/index.md.jinja2 +6 -6
  4. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen.py +64 -14
  5. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/golanggen.py +3 -1
  6. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/jsonschemagen.py +4 -2
  7. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/owlgen.py +36 -17
  8. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/projectgen.py +13 -11
  9. linkml-1.8.4/linkml/generators/pydanticgen/array.py +662 -0
  10. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/build.py +4 -2
  11. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/pydanticgen.py +35 -16
  12. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/template.py +108 -3
  13. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/imports.py.jinja +11 -3
  14. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/module.py.jinja +1 -3
  15. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/validator.py.jinja +2 -2
  16. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pythongen.py +12 -10
  17. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/shaclgen.py +34 -10
  18. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sparqlgen.py +3 -1
  19. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sqlalchemygen.py +5 -3
  20. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sqltablegen.py +4 -2
  21. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/typescriptgen.py +13 -6
  22. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/linter.py +2 -1
  23. {linkml-1.8.3 → linkml-1.8.4}/linkml/transformers/logical_model_transformer.py +3 -3
  24. {linkml-1.8.3 → linkml-1.8.4}/linkml/transformers/relmodel_transformer.py +18 -4
  25. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/converter.py +3 -1
  26. linkml-1.8.4/linkml/utils/exceptions.py +11 -0
  27. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/execute_tutorial.py +22 -20
  28. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/generator.py +6 -4
  29. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/mergeutils.py +4 -2
  30. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/schema_fixer.py +5 -5
  31. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/schemaloader.py +5 -3
  32. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/sqlutils.py +3 -1
  33. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/plugins/pydantic_validation_plugin.py +1 -1
  34. {linkml-1.8.3 → linkml-1.8.4}/linkml/validators/jsonschemavalidator.py +3 -1
  35. {linkml-1.8.3 → linkml-1.8.4}/linkml/validators/sparqlvalidator.py +5 -3
  36. {linkml-1.8.3 → linkml-1.8.4}/linkml/workspaces/example_runner.py +3 -1
  37. {linkml-1.8.3 → linkml-1.8.4}/pyproject.toml +7 -3
  38. {linkml-1.8.3 → linkml-1.8.4}/setup.py +4 -2
  39. linkml-1.8.3/linkml/generators/pydanticgen/array.py +0 -378
  40. {linkml-1.8.3 → linkml-1.8.4}/LICENSE +0 -0
  41. {linkml-1.8.3 → linkml-1.8.4}/README.md +0 -0
  42. {linkml-1.8.3 → linkml-1.8.4}/linkml/__init__.py +0 -0
  43. {linkml-1.8.3 → linkml-1.8.4}/linkml/_version.py +0 -0
  44. {linkml-1.8.3 → linkml-1.8.4}/linkml/cli/__init__.py +0 -0
  45. {linkml-1.8.3 → linkml-1.8.4}/linkml/cli/__main__.py +0 -0
  46. {linkml-1.8.3 → linkml-1.8.4}/linkml/cli/main.py +0 -0
  47. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/PythonGenNotes.md +0 -0
  48. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/README.md +0 -0
  49. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/common/__init__.py +0 -0
  50. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/common/build.py +0 -0
  51. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/common/ifabsent_processor.py +0 -0
  52. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/common/lifecycle.py +0 -0
  53. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/common/template.py +0 -0
  54. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/common/type_designators.py +0 -0
  55. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/csvgen.py +0 -0
  56. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/class.md.jinja2 +0 -0
  57. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/class_diagram.md.jinja2 +0 -0
  58. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/common_metadata.md.jinja2 +0 -0
  59. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/enum.md.jinja2 +0 -0
  60. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/index.tex.jinja2 +0 -0
  61. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/schema.md.jinja2 +0 -0
  62. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/slot.md.jinja2 +0 -0
  63. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/subset.md.jinja2 +0 -0
  64. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/docgen/type.md.jinja2 +0 -0
  65. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/dotgen.py +0 -0
  66. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/erdiagramgen.py +0 -0
  67. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/excelgen.py +0 -0
  68. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/golrgen.py +0 -0
  69. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/graphqlgen.py +0 -0
  70. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/javagen/example_template.java.jinja2 +0 -0
  71. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/javagen/java_record_template.jinja2 +0 -0
  72. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/javagen.py +0 -0
  73. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/jsonldcontextgen.py +0 -0
  74. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/jsonldgen.py +0 -0
  75. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/legacy/__init__.py +0 -0
  76. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/linkmlgen.py +0 -0
  77. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/markdowngen.py +0 -0
  78. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/namespacegen.py +0 -0
  79. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/oocodegen.py +0 -0
  80. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/plantumlgen.py +0 -0
  81. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/prefixmapgen.py +0 -0
  82. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/protogen.py +0 -0
  83. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/__init__.py +0 -0
  84. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/black.py +0 -0
  85. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/includes.py +0 -0
  86. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/attribute.py.jinja +0 -0
  87. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/base_model.py.jinja +0 -0
  88. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/class.py.jinja +0 -0
  89. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/conditional_import.py.jinja +0 -0
  90. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/enum.py.jinja +0 -0
  91. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/pydanticgen/templates/footer.py.jinja +0 -0
  92. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/python/__init__.py +0 -0
  93. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/python/python_ifabsent_processor.py +0 -0
  94. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/rdfgen.py +0 -0
  95. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/shacl/__init__.py +0 -0
  96. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/shacl/shacl_data_type.py +0 -0
  97. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/shacl/shacl_ifabsent_processor.py +0 -0
  98. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/shexgen.py +0 -0
  99. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sqlalchemy/__init__.py +0 -0
  100. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +0 -0
  101. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +0 -0
  102. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/sssomgen.py +0 -0
  103. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/string_template.md +0 -0
  104. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/summarygen.py +0 -0
  105. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/terminusdbgen.py +0 -0
  106. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/yamlgen.py +0 -0
  107. {linkml-1.8.3 → linkml-1.8.4}/linkml/generators/yumlgen.py +0 -0
  108. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/__init__.py +0 -0
  109. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/cli.py +0 -0
  110. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/config/datamodel/.linkmllint.yaml +0 -0
  111. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/config/datamodel/__init__.py +0 -0
  112. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/config/datamodel/config.py +0 -0
  113. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/config/datamodel/config.yaml +0 -0
  114. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/config/default.yaml +0 -0
  115. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/config/recommended.yaml +0 -0
  116. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/formatters/__init__.py +0 -0
  117. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/formatters/formatter.py +0 -0
  118. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/formatters/json_formatter.py +0 -0
  119. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/formatters/markdown_formatter.py +0 -0
  120. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/formatters/terminal_formatter.py +0 -0
  121. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/formatters/tsv_formatter.py +0 -0
  122. {linkml-1.8.3 → linkml-1.8.4}/linkml/linter/rules.py +0 -0
  123. {linkml-1.8.3 → linkml-1.8.4}/linkml/reporting/__init__.py +0 -0
  124. {linkml-1.8.3 → linkml-1.8.4}/linkml/reporting/model.py +0 -0
  125. {linkml-1.8.3 → linkml-1.8.4}/linkml/transformers/__init__.py +0 -0
  126. {linkml-1.8.3 → linkml-1.8.4}/linkml/transformers/model_transformer.py +0 -0
  127. {linkml-1.8.3 → linkml-1.8.4}/linkml/transformers/schema_renamer.py +0 -0
  128. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/__init__.py +0 -0
  129. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/cli_utils.py +0 -0
  130. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/datautils.py +0 -0
  131. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/datavalidator.py +0 -0
  132. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/deprecation.py +0 -0
  133. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/helpers.py +0 -0
  134. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/logictools.py +0 -0
  135. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/rawloader.py +0 -0
  136. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/schema_builder.py +0 -0
  137. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/schemasynopsis.py +0 -0
  138. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/typereferences.py +0 -0
  139. {linkml-1.8.3 → linkml-1.8.4}/linkml/utils/validation.py +0 -0
  140. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/__init__.py +0 -0
  141. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/cli.py +0 -0
  142. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/loaders/__init__.py +0 -0
  143. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/loaders/delimited_file_loader.py +0 -0
  144. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/loaders/json_loader.py +0 -0
  145. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/loaders/loader.py +0 -0
  146. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/loaders/passthrough_loader.py +0 -0
  147. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/loaders/yaml_loader.py +0 -0
  148. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/plugins/__init__.py +0 -0
  149. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/plugins/jsonschema_validation_plugin.py +0 -0
  150. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/plugins/recommended_slots_plugin.py +0 -0
  151. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/plugins/shacl_validation_plugin.py +0 -0
  152. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/plugins/validation_plugin.py +0 -0
  153. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/report.py +0 -0
  154. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/validation_context.py +0 -0
  155. {linkml-1.8.3 → linkml-1.8.4}/linkml/validator/validator.py +0 -0
  156. {linkml-1.8.3 → linkml-1.8.4}/linkml/validators/__init__.py +0 -0
  157. {linkml-1.8.3 → linkml-1.8.4}/linkml/workspaces/__init__.py +0 -0
  158. {linkml-1.8.3 → linkml-1.8.4}/linkml/workspaces/datamodel/__init__.py +0 -0
  159. {linkml-1.8.3 → linkml-1.8.4}/linkml/workspaces/datamodel/workspaces.py +0 -0
  160. {linkml-1.8.3 → 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.3
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)
@@ -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
@@ -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
@@ -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
@@ -40,6 +40,8 @@ from linkml import METAMODEL_NAMESPACE_NAME
40
40
  from linkml._version import __version__
41
41
  from linkml.utils.generator import Generator, shared_arguments
42
42
 
43
+ logger = logging.getLogger(__name__)
44
+
43
45
  OWL_TYPE = URIRef ## RDFS.Literal or OWL.Thing
44
46
 
45
47
  SWRL = rdflib.Namespace("http://www.w3.org/2003/11/swrl#")
@@ -270,7 +272,7 @@ class OwlSchemaGenerator(Generator):
270
272
  # if isinstance(v, str):
271
273
  # obj = URIRef(msv.expand_curie(v))
272
274
  # else:
273
- # logging.debug(f"Skipping {uri} {metaslot_uri} => {v}")
275
+ # logger.debug(f"Skipping {uri} {metaslot_uri} => {v}")
274
276
  else:
275
277
  obj = Literal(v)
276
278
  self.graph.add((uri, metaslot_uri, obj))
@@ -438,7 +440,7 @@ class OwlSchemaGenerator(Generator):
438
440
  if slot:
439
441
  own_slots.append(slot)
440
442
  else:
441
- logging.warning(f"Unknown top-level slot {slot_name}")
443
+ logger.warning(f"Unknown top-level slot {slot_name}")
442
444
  else:
443
445
  own_slots = []
444
446
  own_slots.extend(cls.slot_conditions.values())
@@ -503,9 +505,9 @@ class OwlSchemaGenerator(Generator):
503
505
  owl_exprs.append(self._complement_of_union_of([self.transform_class_expression(x) for x in cls.none_of]))
504
506
  for slot in own_slots:
505
507
  if slot.name:
506
- owltypes = self.slot_node_owltypes(sv.get_slot(slot.name))
508
+ owltypes = self.slot_node_owltypes(sv.get_slot(slot.name), owning_class=cls)
507
509
  else:
508
- owltypes = self.slot_node_owltypes(slot)
510
+ owltypes = self.slot_node_owltypes(slot, owning_class=cls)
509
511
  x = self.transform_class_slot_expression(cls, slot, slot, owltypes)
510
512
  if not x:
511
513
  range = sv.schema.default_range
@@ -552,12 +554,28 @@ class OwlSchemaGenerator(Generator):
552
554
  owl_exprs.append(self._some_values_from(slot_uri, has_member_expr))
553
555
  return self._intersection_of(owl_exprs)
554
556
 
555
- def slot_node_owltypes(self, slot: Union[SlotDefinition, AnonymousSlotExpression]) -> Set[URIRef]:
557
+ def slot_node_owltypes(
558
+ self,
559
+ slot: Union[SlotDefinition, AnonymousSlotExpression],
560
+ owning_class: Optional[Union[ClassDefinition, AnonymousClassExpression]] = None,
561
+ ) -> Set[URIRef]:
562
+ """
563
+ Determine the OWL types of a named slot or slot expression
564
+
565
+ The OWL type is either OWL.Thing or RDFS.Datatype
566
+
567
+ :param slot:
568
+ :param owning_class:
569
+ :return:
570
+ """
556
571
  sv = self.schemaview
557
572
  node_types = set()
558
573
  if isinstance(slot, SlotDefinition):
559
- if slot.range in sv.all_classes():
560
- range_class = sv.get_class(slot.range)
574
+ slot_range = slot.range
575
+ if isinstance(owning_class, ClassDefinition):
576
+ slot_range = sv.induced_slot(slot.name, owning_class.name).range
577
+ if slot_range in sv.all_classes():
578
+ range_class = sv.get_class(slot_range)
561
579
  if not (range_class and range_class.class_uri == "linkml:Any"):
562
580
  node_types.add(OWL.Thing)
563
581
  if slot.range in sv.all_types():
@@ -565,7 +583,7 @@ class OwlSchemaGenerator(Generator):
565
583
  for k in ["any_of", "all_of", "exactly_one_of", "none_of"]:
566
584
  subslot = getattr(slot, k, None)
567
585
  if subslot:
568
- node_types.update(self.slot_node_owltypes(subslot))
586
+ node_types.update(self.slot_node_owltypes(subslot, owning_class=owning_class))
569
587
  return node_types
570
588
 
571
589
  def transform_class_slot_expression(
@@ -679,7 +697,7 @@ class OwlSchemaGenerator(Generator):
679
697
  if element.equals_string is not None:
680
698
  equals_string = element.equals_string
681
699
  if is_literal is None:
682
- logging.warning(f"ignoring equals_string={equals_string} as unable to tell if literal")
700
+ logger.warning(f"ignoring equals_string={equals_string} as unable to tell if literal")
683
701
  elif is_literal:
684
702
  constraints[XSD.pattern] = equals_string
685
703
  else:
@@ -688,7 +706,7 @@ class OwlSchemaGenerator(Generator):
688
706
  if element.equals_string_in:
689
707
  equals_string_in = element.equals_string_in
690
708
  if is_literal is None:
691
- logging.warning(f"ignoring equals_string={equals_string_in} as unable to tell if literal")
709
+ logger.warning(f"ignoring equals_string={equals_string_in} as unable to tell if literal")
692
710
  elif is_literal:
693
711
  dt_exprs = [
694
712
  self._datatype_restriction(XSD.string, [self._facet(XSD.pattern, s)]) for s in equals_string_in
@@ -754,7 +772,7 @@ class OwlSchemaGenerator(Generator):
754
772
  if slot_uri == URIRef(att_uri):
755
773
  n += 1
756
774
  if n > 1:
757
- logging.warning(f"Ambiguous attribute: {slot.name} {slot_uri}")
775
+ logger.warning(f"Ambiguous attribute: {slot.name} {slot_uri}")
758
776
  return
759
777
 
760
778
  self.add_metadata(slot, slot_uri)
@@ -845,6 +863,7 @@ class OwlSchemaGenerator(Generator):
845
863
  if not isinstance(v, list):
846
864
  v = [v]
847
865
  impls.extend(v)
866
+ impls.extend(element.implements)
848
867
  for impl in impls:
849
868
  if impl.startswith("owl:"):
850
869
  return OWL[impl.split(":")[1]]
@@ -889,7 +908,7 @@ class OwlSchemaGenerator(Generator):
889
908
  if pv_owl_type == RDFS.Literal:
890
909
  pv_node = Literal(pv.text)
891
910
  if pv.meaning:
892
- logging.warning(f"Meaning on literal {pv.text} in {e.name} is ignored")
911
+ logger.warning(f"Meaning on literal {pv.text} in {e.name} is ignored")
893
912
  else:
894
913
  pv_node = self._permissible_value_uri(pv, enum_uri, e)
895
914
  pv_uris.append(pv_node)
@@ -950,7 +969,7 @@ class OwlSchemaGenerator(Generator):
950
969
  def _add_rule(self, subject: Union[URIRef, BNode], rule: ClassRule, cls: ClassDefinition):
951
970
  if not self.use_swrl:
952
971
  return
953
- logging.warning("SWRL support is experimental and incomplete")
972
+ logger.warning("SWRL support is experimental and incomplete")
954
973
  head = []
955
974
  body = []
956
975
  for pre in rule.preconditions:
@@ -997,7 +1016,7 @@ class OwlSchemaGenerator(Generator):
997
1016
  owltypes.update(x_owltypes)
998
1017
  owltypes.update(current)
999
1018
  if len(owltypes) > 1:
1000
- logging.warning(f"Multiple owl types {owltypes}")
1019
+ logger.warning(f"Multiple owl types {owltypes}")
1001
1020
  # if self.target_profile == OWLProfile.dl:
1002
1021
  return owltypes
1003
1022
 
@@ -1125,7 +1144,7 @@ class OwlSchemaGenerator(Generator):
1125
1144
  ) -> Optional[Union[BNode, URIRef]]:
1126
1145
  graph = self.graph
1127
1146
  if [x for x in exprs if x is None]:
1128
- logging.warning(f"Null expr in: {exprs} for {predicate} {node}")
1147
+ logger.warning(f"Null expr in: {exprs} for {predicate} {node}")
1129
1148
  exprs = [x for x in exprs if x is not None]
1130
1149
  if len(exprs) == 0:
1131
1150
  return None
@@ -1251,10 +1270,10 @@ class OwlSchemaGenerator(Generator):
1251
1270
  return OWL.ObjectProperty
1252
1271
  is_literal_vals = self.slot_is_literal_map[slot.name]
1253
1272
  if len(is_literal_vals) > 1:
1254
- logging.warning(f"Ambiguous type for: {slot.name}")
1273
+ logger.warning(f"Ambiguous type for: {slot.name}")
1255
1274
  if range is None:
1256
1275
  if not is_literal_vals:
1257
- logging.warning(f"Guessing type for {slot.name}")
1276
+ logger.warning(f"Guessing type for {slot.name}")
1258
1277
  return OWL.ObjectProperty
1259
1278
  if (list(is_literal_vals))[0]:
1260
1279
  return OWL.DatatypeProperty
@@ -26,6 +26,8 @@ from linkml.generators.sqltablegen import SQLTableGenerator
26
26
  from linkml.utils.cli_utils import log_level_option
27
27
  from linkml.utils.generator import Generator
28
28
 
29
+ logger = logging.getLogger(__name__)
30
+
29
31
  PATH_FSTRING = str
30
32
  GENERATOR_NAME = str
31
33
  ARG_DICT = Dict[str, Any]
@@ -63,14 +65,14 @@ GEN_MAP = {
63
65
 
64
66
  @lru_cache()
65
67
  def get_local_imports(schema_path: str, dir: str):
66
- logging.info(f"GETTING IMPORTS = {schema_path}")
68
+ logger.info(f"GETTING IMPORTS = {schema_path}")
67
69
  all_imports = [schema_path]
68
70
  with open(schema_path) as stream:
69
71
  with open(schema_path) as stream:
70
72
  schema = yaml.safe_load(stream)
71
73
  for imp in schema.get("imports", []):
72
74
  imp_path = os.path.join(dir, imp) + ".yaml"
73
- logging.info(f" IMP={imp} // path={imp_path}")
75
+ logger.info(f" IMP={imp} // path={imp_path}")
74
76
  if os.path.isfile(imp_path):
75
77
  all_imports += get_local_imports(imp_path, dir)
76
78
  return all_imports
@@ -105,23 +107,23 @@ class ProjectGenerator:
105
107
  all_schemas = [schema_path]
106
108
  else:
107
109
  all_schemas = get_local_imports(schema_path, os.path.dirname(schema_path))
108
- logging.debug(f"ALL_SCHEMAS = {all_schemas}")
110
+ logger.debug(f"ALL_SCHEMAS = {all_schemas}")
109
111
  for gen_name, (gen_cls, gen_path_fmt, default_gen_args) in GEN_MAP.items():
110
112
  if config.includes is not None and config.includes != [] and gen_name not in config.includes:
111
- logging.info(f"Skipping {gen_name} as not in inclusion list: {config.includes}")
113
+ logger.info(f"Skipping {gen_name} as not in inclusion list: {config.includes}")
112
114
  continue
113
115
  if config.excludes is not None and gen_name in config.excludes:
114
- logging.info(f"Skipping {gen_name} as it is in exclusion list")
116
+ logger.info(f"Skipping {gen_name} as it is in exclusion list")
115
117
  continue
116
- logging.info(f"Generating: {gen_name}")
118
+ logger.info(f"Generating: {gen_name}")
117
119
  for local_path in all_schemas:
118
- logging.info(f" SCHEMA: {local_path}")
120
+ logger.info(f" SCHEMA: {local_path}")
119
121
  name = os.path.basename(local_path).replace(".yaml", "")
120
122
  gen_path = gen_path_fmt.format(name=name)
121
123
  gen_path_full = f"{config.directory}/{gen_path}"
122
124
  parts = gen_path_full.split("/")
123
125
  parent_dir = "/".join(parts[0:-1])
124
- logging.info(f" PARENT={parent_dir}")
126
+ logger.info(f" PARENT={parent_dir}")
125
127
  Path(parent_dir).mkdir(parents=True, exist_ok=True)
126
128
  gen_path_full = "/".join(parts)
127
129
  all_gen_args = {
@@ -143,13 +145,13 @@ class ProjectGenerator:
143
145
  if isinstance(v, str):
144
146
  v = v.format(name=name, parent=parent_dir)
145
147
  serialize_args[k] = v
146
- logging.info(f" {gen_name} ARGS: {serialize_args}")
148
+ logger.info(f" {gen_name} ARGS: {serialize_args}")
147
149
  gen_dump = gen.serialize(**serialize_args)
148
150
 
149
151
  if gen_name != "excel":
150
152
  if parts[-1] != "":
151
153
  # markdowngen does not write to a file
152
- logging.info(f" WRITING TO: {gen_path_full}")
154
+ logger.info(f" WRITING TO: {gen_path_full}")
153
155
  with open(gen_path_full, "w", encoding="UTF-8") as stream:
154
156
  stream.write(gen_dump)
155
157
  else:
@@ -249,7 +251,7 @@ def cli(
249
251
  project_config.generator_args = yaml.safe_load(generator_arguments)
250
252
  except Exception:
251
253
  raise Exception("Argument must be a valid YAML blob")
252
- logging.info(f"generator args: {project_config.generator_args}")
254
+ logger.info(f"generator args: {project_config.generator_args}")
253
255
  if dir is not None:
254
256
  project_config.directory = dir
255
257
  project_config.mergeimports = mergeimports