linkml 1.9.1rc2__tar.gz → 1.9.2__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 (174) hide show
  1. {linkml-1.9.1rc2 → linkml-1.9.2}/PKG-INFO +19 -16
  2. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/cli/main.py +2 -0
  3. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/__init__.py +2 -0
  4. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/class_diagram.md.jinja2 +10 -8
  5. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/common_metadata.md.jinja2 +1 -1
  6. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/index.md.jinja2 +1 -1
  7. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen.py +33 -7
  8. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/jsonldgen.py +1 -1
  9. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/markdowngen.py +24 -1
  10. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/mermaidclassdiagramgen.py +3 -2
  11. linkml-1.9.2/linkml/generators/panderagen/__init__.py +9 -0
  12. linkml-1.9.2/linkml/generators/panderagen/class_generator_mixin.py +20 -0
  13. linkml-1.9.2/linkml/generators/panderagen/enum_generator_mixin.py +17 -0
  14. linkml-1.9.2/linkml/generators/panderagen/panderagen.py +216 -0
  15. linkml-1.9.2/linkml/generators/panderagen/panderagen_class_based/class.jinja2 +26 -0
  16. linkml-1.9.2/linkml/generators/panderagen/panderagen_class_based/enums.jinja2 +9 -0
  17. linkml-1.9.2/linkml/generators/panderagen/panderagen_class_based/header.jinja2 +21 -0
  18. linkml-1.9.2/linkml/generators/panderagen/panderagen_class_based/mixins.jinja2 +26 -0
  19. linkml-1.9.2/linkml/generators/panderagen/panderagen_class_based/pandera.jinja2 +16 -0
  20. linkml-1.9.2/linkml/generators/panderagen/panderagen_class_based/slots.jinja2 +36 -0
  21. linkml-1.9.2/linkml/generators/panderagen/slot_generator_mixin.py +77 -0
  22. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/enum.py.jinja +6 -4
  23. linkml-1.9.2/linkml/generators/pydanticgen/templates/validator.py.jinja +12 -0
  24. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sqltablegen.py +143 -86
  25. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/yumlgen.py +33 -1
  26. linkml-1.9.2/linkml/transformers/rollup_transformer.py +115 -0
  27. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/deprecation.py +26 -0
  28. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/execute_tutorial.py +71 -9
  29. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/plugins/recommended_slots_plugin.py +4 -4
  30. {linkml-1.9.1rc2 → linkml-1.9.2}/pyproject.toml +87 -66
  31. linkml-1.9.1rc2/linkml/generators/pydanticgen/templates/validator.py.jinja +0 -11
  32. {linkml-1.9.1rc2 → linkml-1.9.2}/LICENSE +0 -0
  33. {linkml-1.9.1rc2 → linkml-1.9.2}/README.md +0 -0
  34. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/__init__.py +0 -0
  35. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/_version.py +0 -0
  36. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/cli/__init__.py +0 -0
  37. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/cli/__main__.py +0 -0
  38. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/PythonGenNotes.md +0 -0
  39. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/README.md +0 -0
  40. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/__init__.py +0 -0
  41. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/build.py +0 -0
  42. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/ifabsent_processor.py +0 -0
  43. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/lifecycle.py +0 -0
  44. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/naming.py +0 -0
  45. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/template.py +0 -0
  46. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/common/type_designators.py +0 -0
  47. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/csvgen.py +0 -0
  48. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/dbmlgen.py +0 -0
  49. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/class.md.jinja2 +0 -0
  50. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/enum.md.jinja2 +0 -0
  51. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/index.tex.jinja2 +0 -0
  52. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/schema.md.jinja2 +0 -0
  53. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/slot.md.jinja2 +0 -0
  54. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/subset.md.jinja2 +0 -0
  55. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/docgen/type.md.jinja2 +0 -0
  56. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/dotgen.py +0 -0
  57. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/erdiagramgen.py +0 -0
  58. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/excelgen.py +0 -0
  59. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/golanggen.py +0 -0
  60. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/golrgen.py +0 -0
  61. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/graphqlgen.py +0 -0
  62. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/javagen/example_template.java.jinja2 +0 -0
  63. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/javagen/java_record_template.jinja2 +0 -0
  64. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/javagen.py +0 -0
  65. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/jsonldcontextgen.py +0 -0
  66. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/jsonschemagen.py +0 -0
  67. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/legacy/__init__.py +0 -0
  68. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/linkmlgen.py +0 -0
  69. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/namespacegen.py +0 -0
  70. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/oocodegen.py +0 -0
  71. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/owlgen.py +0 -0
  72. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/plantumlgen.py +0 -0
  73. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/prefixmapgen.py +0 -0
  74. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/projectgen.py +0 -0
  75. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/protogen.py +0 -0
  76. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/__init__.py +0 -0
  77. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/array.py +0 -0
  78. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/black.py +0 -0
  79. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/build.py +0 -0
  80. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/includes.py +0 -0
  81. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/pydanticgen.py +0 -0
  82. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/template.py +0 -0
  83. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/attribute.py.jinja +0 -0
  84. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/base_model.py.jinja +0 -0
  85. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/class.py.jinja +0 -0
  86. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/conditional_import.py.jinja +0 -0
  87. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/footer.py.jinja +0 -0
  88. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/imports.py.jinja +0 -0
  89. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pydanticgen/templates/module.py.jinja +0 -0
  90. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/python/__init__.py +0 -0
  91. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/python/python_ifabsent_processor.py +0 -0
  92. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/pythongen.py +0 -0
  93. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/rdfgen.py +0 -0
  94. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/shacl/__init__.py +0 -0
  95. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/shacl/shacl_data_type.py +0 -0
  96. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/shacl/shacl_ifabsent_processor.py +0 -0
  97. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/shaclgen.py +0 -0
  98. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/shexgen.py +0 -0
  99. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sparqlgen.py +0 -0
  100. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sqlalchemy/__init__.py +0 -0
  101. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +0 -0
  102. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +0 -0
  103. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sqlalchemygen.py +0 -0
  104. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/sssomgen.py +0 -0
  105. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/string_template.md +0 -0
  106. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/summarygen.py +0 -0
  107. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/terminusdbgen.py +0 -0
  108. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/typescriptgen.py +0 -0
  109. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/generators/yamlgen.py +0 -0
  110. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/__init__.py +0 -0
  111. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/cli.py +0 -0
  112. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/config/datamodel/.linkmllint.yaml +0 -0
  113. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/config/datamodel/__init__.py +0 -0
  114. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/config/datamodel/config.py +0 -0
  115. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/config/datamodel/config.yaml +0 -0
  116. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/config/default.yaml +0 -0
  117. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/config/recommended.yaml +0 -0
  118. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/formatters/__init__.py +0 -0
  119. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/formatters/formatter.py +0 -0
  120. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/formatters/json_formatter.py +0 -0
  121. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/formatters/markdown_formatter.py +0 -0
  122. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/formatters/terminal_formatter.py +0 -0
  123. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/formatters/tsv_formatter.py +0 -0
  124. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/linter.py +0 -0
  125. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/linter/rules.py +0 -0
  126. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/reporting/__init__.py +0 -0
  127. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/reporting/model.py +0 -0
  128. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/transformers/__init__.py +0 -0
  129. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/transformers/logical_model_transformer.py +0 -0
  130. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/transformers/model_transformer.py +0 -0
  131. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/transformers/relmodel_transformer.py +0 -0
  132. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/transformers/schema_renamer.py +0 -0
  133. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/__init__.py +0 -0
  134. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/cli_utils.py +0 -0
  135. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/converter.py +0 -0
  136. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/datautils.py +0 -0
  137. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/datavalidator.py +0 -0
  138. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/exceptions.py +0 -0
  139. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/generator.py +0 -0
  140. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/helpers.py +0 -0
  141. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/logictools.py +0 -0
  142. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/mergeutils.py +0 -0
  143. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/rawloader.py +0 -0
  144. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/schema_builder.py +0 -0
  145. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/schema_fixer.py +0 -0
  146. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/schemaloader.py +0 -0
  147. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/schemasynopsis.py +0 -0
  148. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/sqlutils.py +0 -0
  149. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/typereferences.py +0 -0
  150. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/utils/validation.py +0 -0
  151. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/__init__.py +0 -0
  152. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/cli.py +0 -0
  153. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/loaders/__init__.py +0 -0
  154. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/loaders/delimited_file_loader.py +0 -0
  155. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/loaders/json_loader.py +0 -0
  156. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/loaders/loader.py +0 -0
  157. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/loaders/passthrough_loader.py +0 -0
  158. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/loaders/yaml_loader.py +0 -0
  159. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/plugins/__init__.py +0 -0
  160. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/plugins/jsonschema_validation_plugin.py +0 -0
  161. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/plugins/pydantic_validation_plugin.py +0 -0
  162. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/plugins/shacl_validation_plugin.py +0 -0
  163. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/plugins/validation_plugin.py +0 -0
  164. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/report.py +0 -0
  165. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/validation_context.py +0 -0
  166. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validator/validator.py +0 -0
  167. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validators/__init__.py +0 -0
  168. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validators/jsonschemavalidator.py +0 -0
  169. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/validators/sparqlvalidator.py +0 -0
  170. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/workspaces/__init__.py +0 -0
  171. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/workspaces/datamodel/__init__.py +0 -0
  172. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/workspaces/datamodel/workspaces.py +0 -0
  173. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/workspaces/datamodel/workspaces.yaml +0 -0
  174. {linkml-1.9.1rc2 → linkml-1.9.2}/linkml/workspaces/example_runner.py +0 -0
@@ -1,59 +1,62 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: linkml
3
- Version: 1.9.1rc2
3
+ Version: 1.9.2
4
4
  Summary: Linked Open Data Modeling Language
5
- Home-page: https://linkml.io/linkml/
5
+ License: Apache-2.0
6
6
  Keywords: schema,linked data,data modeling,rdf,owl,biolink
7
7
  Author: Chris Mungall
8
8
  Author-email: cjmungall@lbl.gov
9
- Requires-Python: >=3.9.0,<4.0.0
9
+ Requires-Python: >=3.9
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Environment :: Console
12
12
  Classifier: Intended Audience :: Developers
13
- Classifier: Intended Audience :: Healthcare Industry
14
13
  Classifier: Intended Audience :: Science/Research
15
- Classifier: License :: OSI Approved :: Apache Software License
16
- Classifier: Programming Language :: Python :: 3
14
+ Classifier: Intended Audience :: Healthcare Industry
15
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
16
  Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
21
20
  Classifier: Programming Language :: Python :: 3.13
22
- Classifier: Programming Language :: Python :: 3.8
23
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
21
  Provides-Extra: black
25
22
  Provides-Extra: numpydantic
23
+ Provides-Extra: pandera
24
+ Provides-Extra: polars-lts-cpu
26
25
  Provides-Extra: shacl
27
26
  Provides-Extra: tests
28
27
  Requires-Dist: antlr4-python3-runtime (>=4.9.0,<4.10)
29
- Requires-Dist: black (>=24.0.0) ; extra == "black" or extra == "tests"
28
+ Requires-Dist: black (>=24.0.0) ; extra == "black"
29
+ Requires-Dist: black (>=24.0.0) ; extra == "tests"
30
30
  Requires-Dist: click (>=7.0)
31
31
  Requires-Dist: graphviz (>=0.10.1)
32
32
  Requires-Dist: hbreader
33
33
  Requires-Dist: isodate (>=0.6.0)
34
34
  Requires-Dist: jinja2 (>=3.1.0)
35
- Requires-Dist: jsonasobj2 (>=1.0.3,<2.dev0)
35
+ Requires-Dist: jsonasobj2 (>=1.0.3,<2.0.0)
36
36
  Requires-Dist: jsonschema[format] (>=4.0.0)
37
- Requires-Dist: linkml-runtime (>=1.9.1,<2.0.0)
38
- Requires-Dist: numpydantic (>=1.6.1) ; extra == "numpydantic" or extra == "tests"
37
+ Requires-Dist: linkml-runtime (>=1.9.2,<2.0.0)
38
+ Requires-Dist: numpydantic (>=1.6.1) ; extra == "numpydantic"
39
+ Requires-Dist: numpydantic (>=1.6.1) ; extra == "tests"
39
40
  Requires-Dist: openpyxl
41
+ Requires-Dist: pandera (>=0.19.0) ; extra == "pandera"
40
42
  Requires-Dist: parse
43
+ Requires-Dist: polars-lts-cpu (>=1.0.0) ; extra == "polars-lts-cpu"
41
44
  Requires-Dist: prefixcommons (>=0.1.7)
42
45
  Requires-Dist: prefixmaps (>=0.2.2)
43
46
  Requires-Dist: pydantic (>=1.0.0,<3.0.0)
44
47
  Requires-Dist: pyjsg (>=0.11.6)
45
- Requires-Dist: pyshacl (>=0.25.0,<0.26.0) ; extra == "shacl" or extra == "tests"
48
+ Requires-Dist: pyshacl (>=0.25.0) ; extra == "shacl"
49
+ Requires-Dist: pyshacl (>=0.25.0) ; extra == "tests"
46
50
  Requires-Dist: pyshex (>=0.7.20)
47
51
  Requires-Dist: pyshexc (>=0.8.3)
48
52
  Requires-Dist: python-dateutil
49
53
  Requires-Dist: pyyaml
50
54
  Requires-Dist: rdflib (>=6.0.0)
51
55
  Requires-Dist: requests (>=2.22)
56
+ Requires-Dist: sphinx-click (>=6.0.0)
52
57
  Requires-Dist: sqlalchemy (>=1.4.31)
53
58
  Requires-Dist: typing-extensions (>=4.6.0) ; python_version < "3.12"
54
59
  Requires-Dist: watchdog (>=0.9.0)
55
- Project-URL: Documentation, https://linkml.io/linkml/
56
- Project-URL: Repository, https://github.com/linkml/linkml
57
60
  Description-Content-Type: text/markdown
58
61
 
59
62
  [![Pyversions](https://img.shields.io/pypi/pyversions/linkml.svg)](https://pypi.python.org/pypi/linkml)
@@ -24,6 +24,7 @@ from linkml.generators.linkmlgen import cli as gen_linkml
24
24
  from linkml.generators.markdowngen import cli as gen_markdown
25
25
  from linkml.generators.namespacegen import cli as gen_namespaces
26
26
  from linkml.generators.owlgen import cli as gen_owl
27
+ from linkml.generators.panderagen import cli as gen_pandera
27
28
  from linkml.generators.plantumlgen import cli as gen_plantuml
28
29
  from linkml.generators.prefixmapgen import cli as gen_prefix_map
29
30
  from linkml.generators.projectgen import cli as gen_project
@@ -110,6 +111,7 @@ generate.add_command(gen_plantuml, name="plantuml")
110
111
  generate.add_command(gen_proto, name="proto")
111
112
  generate.add_command(gen_python, name="python")
112
113
  generate.add_command(gen_pydantic, name="pydantic")
114
+ generate.add_command(gen_pandera, name="pandera")
113
115
  generate.add_command(gen_rdf, name="rdf")
114
116
  generate.add_command(gen_shex, name="shex")
115
117
  generate.add_command(gen_shacl, name="shacl")
@@ -8,6 +8,7 @@ from linkml.generators.jsonldcontextgen import ContextGenerator
8
8
  from linkml.generators.jsonldgen import JSONLDGenerator
9
9
  from linkml.generators.jsonschemagen import JsonSchemaGenerator
10
10
  from linkml.generators.owlgen import OwlSchemaGenerator
11
+ from linkml.generators.panderagen import PanderaGenerator
11
12
  from linkml.generators.pydanticgen import PydanticGenerator
12
13
  from linkml.generators.pythongen import PythonGenerator
13
14
  from linkml.generators.rdfgen import RDFGenerator
@@ -42,6 +43,7 @@ __all__ = [
42
43
  "yumlgen",
43
44
  "OwlSchemaGenerator",
44
45
  "PydanticGenerator",
46
+ "PanderaGenerator",
45
47
  "PythonGenerator",
46
48
  "JavaGenerator",
47
49
  "ContextGenerator",
@@ -1,8 +1,10 @@
1
1
  {% macro slot_relationship(element, slot) %}
2
- {% set range_element = gen.name(schemaview.get_element(slot.range)) %}
3
- {% set relation_label = gen.name(slot) %}
4
- {{ gen.name(element) }} --> "{{ gen.cardinality(slot) }}" {{ range_element }} : {{ relation_label }}
5
- click {{ range_element }} href "../{{ range_element }}"
2
+ {% if slot.range is not none %}
3
+ {% set range_element = gen.name(schemaview.get_element(slot.range)) %}
4
+ {% set relation_label = gen.name(slot) %}
5
+ {{ gen.name(element) }} --> "{{ gen.cardinality(slot) }}" {{ range_element }} : {{ relation_label }}
6
+ click {{ range_element }} href "../{{ range_element }}"
7
+ {% endif %}
6
8
  {% endmacro %}
7
9
 
8
10
  {% if schemaview.class_parents(element.name) and schemaview.class_children(element.name) %}
@@ -22,7 +24,7 @@
22
24
 
23
25
  {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
24
26
  {{ gen.name(element) }} : {{gen.name(s)}}
25
- {% if s.range not in gen.all_type_object_names() %}
27
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
26
28
  {{ slot_relationship(element, s) }}
27
29
  {% endif %}
28
30
  {% endfor %}
@@ -38,7 +40,7 @@
38
40
  {% endfor %}
39
41
  {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
40
42
  {{ gen.name(element) }} : {{gen.name(s)}}
41
- {% if s.range not in gen.all_type_object_names() %}
43
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
42
44
  {{ slot_relationship(element, s) }}
43
45
  {% endif %}
44
46
  {% endfor %}
@@ -54,7 +56,7 @@
54
56
  {% endfor %}
55
57
  {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
56
58
  {{ gen.name(element) }} : {{gen.name(s)}}
57
- {% if s.range not in gen.all_type_object_names() %}
59
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
58
60
  {{ slot_relationship(element, s) }}
59
61
  {% endif %}
60
62
  {% endfor %}
@@ -66,7 +68,7 @@
66
68
  click {{ gen.name(element) }} href "../{{gen.name(element)}}"
67
69
  {% for s in schemaview.class_induced_slots(element.name)|sort(attribute='name') -%}
68
70
  {{ gen.name(element) }} : {{gen.name(s)}}
69
- {% if s.range not in gen.all_type_object_names() %}
71
+ {% if s.range is not none and s.range not in gen.all_type_object_names() %}
70
72
  {{ slot_relationship(element, s) }}
71
73
  {% endif %}
72
74
  {% endfor %}
@@ -62,7 +62,7 @@ Instances of this class *should* have identifiers with one of the following pref
62
62
  {% for a in element.annotations -%}
63
63
  {%- if a|string|first != '_' -%}
64
64
  | {{ a }} | {{ element.annotations[a].value }} |
65
- {%- endif -%}
65
+ {% endif -%}
66
66
  {% endfor %}
67
67
  {% endif %}
68
68
 
@@ -21,7 +21,7 @@ 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), True) }} | {{ schemaview.get_class(v).description }} |
24
+ | {{ "&nbsp;"|safe*u*8 }}{{ gen.link(schemaview.get_class(v), True) }} | {{ schemaview.get_class(v).description|enshorten }} |
25
25
  {% endfor %}
26
26
  {% else -%}
27
27
  {% for c in gen.all_class_objects()|sort(attribute=sort_by) -%}
@@ -61,7 +61,7 @@ SUBSET_SUBFOLDER = "subsets"
61
61
 
62
62
  def enshorten(input):
63
63
  """
64
- Custom filter to truncate any long text intended to go in a table,
64
+ Custom filters to truncate any long text intended to go in a table
65
65
  and to remove anything after a newline"""
66
66
  if input is None:
67
67
  return ""
@@ -76,8 +76,11 @@ def enshorten(input):
76
76
  return input
77
77
 
78
78
 
79
- def customize_environment(env: Environment):
80
- env.filters["enshorten"] = enshorten
79
+ def text_to_web(input) -> str:
80
+ """Custom filter to convert multi-line text strings into a suitable format for web/markdown output."""
81
+ if input is None:
82
+ return ""
83
+ return "<br>".join(input.strip().split("\n"))
81
84
 
82
85
 
83
86
  def _ensure_ranked(elements: Iterable[Element]):
@@ -155,6 +158,9 @@ class DocGenerator(Generator):
155
158
  subfolder_type_separation: bool = False
156
159
  """Whether each type (class, slot, etc.) should be put in separate subfolder for navigation purposes"""
157
160
 
161
+ truncate_descriptions: bool = True
162
+ """Whether to truncate long (multi-line) descriptions down to a single line."""
163
+
158
164
  example_directory: Optional[str] = None
159
165
  example_runner: ExampleRunner = field(default_factory=lambda: ExampleRunner())
160
166
 
@@ -314,7 +320,7 @@ class DocGenerator(Generator):
314
320
  # TODO: relative paths
315
321
  # loader = FileSystemLoader()
316
322
  env = Environment()
317
- customize_environment(env)
323
+ self.customize_environment(env)
318
324
  return env.get_template(path)
319
325
  else:
320
326
  base_file_name = f"{element_type}.{self._file_suffix()}.jinja2"
@@ -332,7 +338,7 @@ class DocGenerator(Generator):
332
338
  folder = os.path.join(package_dir, "docgen", "")
333
339
  loader = FileSystemLoader(folder)
334
340
  env = Environment(loader=loader)
335
- customize_environment(env)
341
+ self.customize_environment(env)
336
342
  return env.get_template(base_file_name)
337
343
 
338
344
  def schema_title(self) -> str:
@@ -384,6 +390,10 @@ class DocGenerator(Generator):
384
390
  if isinstance(element, (EnumDefinition, SubsetDefinition)):
385
391
  # TODO: fix schema view to handle URIs for enums and subsets
386
392
  return self.name(element)
393
+
394
+ if self.subfolder_type_separation:
395
+ return self.schemaview.get_uri(element, expand=expand, use_element_type=True)
396
+
387
397
  return self.schemaview.get_uri(element, expand=expand)
388
398
 
389
399
  def uri_link(self, element: Union[Element, str]) -> str:
@@ -955,13 +965,19 @@ class DocGenerator(Generator):
955
965
  objs.append((stem, f.read()))
956
966
  return objs
957
967
 
968
+ def customize_environment(self, env: Environment):
969
+ if self.truncate_descriptions:
970
+ env.filters["enshorten"] = enshorten
971
+ else:
972
+ env.filters["enshorten"] = text_to_web
973
+
958
974
 
959
975
  @shared_arguments(DocGenerator)
960
976
  @click.option(
961
977
  "--directory",
962
978
  "-d",
963
979
  required=True,
964
- help="Folder to which document files are written",
980
+ help="Path to the directory where you want the Markdown files to be written to",
965
981
  )
966
982
  @click.option("--index-name", default="index", show_default=True, help="Name of the index document.")
967
983
  @click.option("--dialect", help="Dialect or 'flavor' of Markdown used.")
@@ -988,7 +1004,7 @@ class DocGenerator(Generator):
988
1004
  show_default=True,
989
1005
  help="Generating metamodel. Only use this for generating meta.py",
990
1006
  )
991
- @click.option("--template-directory", help="Folder in which custom templates are kept")
1007
+ @click.option("--template-directory", help="Path to the directory with custom jinja2 templates")
992
1008
  @click.option(
993
1009
  "--use-slot-uris/--no-use-slot-uris",
994
1010
  default=False,
@@ -1027,6 +1043,14 @@ YAML, and including it when necessary but not by default (e.g. in documentation
1027
1043
  default=False,
1028
1044
  help="Separate type (class, slot, etc.) outputs in different subfolders for navigation purposes",
1029
1045
  )
1046
+ @click.option(
1047
+ "--truncate-descriptions",
1048
+ default=True,
1049
+ show_default=True,
1050
+ help="""
1051
+ Whether to truncate long (potentially spanning multiple lines) descriptions of classes, slots, etc., in the docs.
1052
+ Set to true for truncated descriptions, and false to display full descriptions.""",
1053
+ )
1030
1054
  @click.version_option(__version__, "-V", "--version")
1031
1055
  @click.command(name="doc")
1032
1056
  def cli(
@@ -1040,6 +1064,7 @@ def cli(
1040
1064
  hierarchical_class_view,
1041
1065
  subfolder_type_separation,
1042
1066
  render_imports,
1067
+ truncate_descriptions,
1043
1068
  **args,
1044
1069
  ):
1045
1070
  """Generate documentation folder from a LinkML YAML schema
@@ -1072,6 +1097,7 @@ def cli(
1072
1097
  index_name=index_name,
1073
1098
  subfolder_type_separation=subfolder_type_separation,
1074
1099
  render_imports=render_imports,
1100
+ truncate_descriptions=truncate_descriptions,
1075
1101
  **args,
1076
1102
  )
1077
1103
  print(gen.serialize())
@@ -162,7 +162,7 @@ class JSONLDGenerator(Generator):
162
162
  # model_context = self.schema.source_file.replace('.yaml', '.prefixes.context.jsonld')
163
163
  # context = [METAMODEL_CONTEXT_URI, f'file://./{model_context}']
164
164
  # TODO: The _visit function above alters the schema in situ
165
- add_prefixes = ContextGenerator(self.original_schema, model=False, metadata=False).serialize()
165
+ add_prefixes = ContextGenerator(self.original_schema, model=False, emit_metadata=False).serialize()
166
166
  add_prefixes_json = loads(add_prefixes)
167
167
  context = [METAMODEL_CONTEXT_URI, add_prefixes_json["@context"]]
168
168
  elif isinstance(context, str): # Some of the older code doesn't do multiple contexts
@@ -18,6 +18,7 @@ from linkml_runtime.utils.formatutils import be, camelcase, underscore
18
18
 
19
19
  from linkml._version import __version__
20
20
  from linkml.generators.yumlgen import YumlGenerator
21
+ from linkml.utils.deprecation import deprecation_warning
21
22
  from linkml.utils.generator import Generator, shared_arguments
22
23
  from linkml.utils.typereferences import References
23
24
 
@@ -31,8 +32,24 @@ class MarkdownGenerator(Generator):
31
32
  additionally, an index.md is generated that links everything together.
32
33
 
33
34
  The markdown is suitable for deployment as a MkDocs or Sphinx site
35
+
36
+ .. admonition:: Deprecated
37
+ :class: warning
38
+
39
+ The MarkdownGenerator class is being deprecated in favor of DocGenerator which can
40
+ be found at the following path – `linkml/generators/docgen.py`. Going forward, DocGenerator
41
+ which can be invoked using the `gen-doc` command will be the preferred way to generate
42
+ Markdown documentation files for LinkML schemas.
43
+
44
+ .. deprecated:: v1.9.1
45
+
46
+ Recommendation: Update to use `gen-doc`
34
47
  """
35
48
 
49
+ def __post_init__(self) -> None:
50
+ deprecation_warning("gen-markdown")
51
+ super().__post_init__()
52
+
36
53
  # ClassVars
37
54
  generatorname = os.path.basename(__file__)
38
55
  generatorversion = "0.2.1"
@@ -799,7 +816,13 @@ def pad_heading(text: str) -> str:
799
816
  @click.option("--warnonexist", is_flag=True, help="Warn if output file already exists")
800
817
  @click.version_option(__version__, "-V", "--version")
801
818
  def cli(yamlfile, map_fields, dir, img, index_file, notypesdir, warnonexist, **kwargs):
802
- """Generate markdown documentation of a LinkML model"""
819
+ """Generate markdown documentation of a LinkML model.
820
+
821
+ .. warning::
822
+ `gen-markdown` is deprecated. Please use `gen-doc` instead.
823
+ """
824
+ deprecation_warning("gen-markdown")
825
+
803
826
  gen = MarkdownGenerator(yamlfile, no_types_dir=notypesdir, warn_on_exist=warnonexist, **kwargs)
804
827
  if map_fields is not None:
805
828
  gen.metamodel_name_map = {}
@@ -10,7 +10,7 @@ from jinja2 import Environment, FileSystemLoader
10
10
  from linkml_runtime.linkml_model.meta import Element, SlotDefinition
11
11
  from linkml_runtime.utils.schemaview import SchemaView
12
12
 
13
- from linkml.generators.docgen import DocGenerator, customize_environment
13
+ from linkml.generators.docgen import DocGenerator
14
14
  from linkml.utils.generator import Generator, shared_arguments
15
15
 
16
16
 
@@ -59,7 +59,8 @@ class MermaidClassDiagramGenerator(Generator):
59
59
  template_name = os.path.basename(self.template_file)
60
60
  loader = FileSystemLoader(template_folder)
61
61
  env = Environment(loader=loader)
62
- customize_environment(env)
62
+ temp_doc_gen = DocGenerator(self.schema, mergeimports=self.mergeimports)
63
+ temp_doc_gen.customize_environment(env)
63
64
 
64
65
  template = env.get_template(template_name)
65
66
 
@@ -0,0 +1,9 @@
1
+ from .panderagen import (
2
+ PanderaGenerator,
3
+ cli,
4
+ )
5
+
6
+ __all__ = [
7
+ "cli",
8
+ "PanderaGenerator",
9
+ ]
@@ -0,0 +1,20 @@
1
+ from linkml_runtime.linkml_model import ClassDefinitionName
2
+
3
+
4
+ class ClassGeneratorMixin:
5
+ def ordered_classes(self):
6
+ return [self.schemaview.get_class(cn, strict=True) for cn in self.order_classes_by_hierarchy()]
7
+
8
+ def order_classes_by_hierarchy(self) -> list[ClassDefinitionName]:
9
+ sv = self.schemaview
10
+ olist = sv.class_roots()
11
+ unprocessed = [cn for cn in sv.all_classes() if cn not in olist]
12
+
13
+ while len(unprocessed) > 0:
14
+ ext_list = [cn for cn in unprocessed if not any(p for p in sv.class_parents(cn) if p not in olist)]
15
+ if len(ext_list) == 0:
16
+ raise ValueError(f"Cycle in hierarchy, cannot process: {unprocessed}")
17
+ olist += ext_list
18
+ unprocessed = [cn for cn in unprocessed if cn not in olist]
19
+
20
+ return olist
@@ -0,0 +1,17 @@
1
+ from linkml_runtime.linkml_model.meta import PermissibleValue, PermissibleValueText
2
+
3
+
4
+ class EnumGeneratorMixin:
5
+ def escape_permissible_value_text(self, pv_text):
6
+ return pv_text.replace("'", "\\'").replace('"', '\\"')
7
+
8
+ def extract_permissible_text(self, pv):
9
+ if isinstance(pv, str) or isinstance(pv, PermissibleValueText):
10
+ return self.escape_permissible_value_text(pv)
11
+ elif isinstance(pv, PermissibleValue):
12
+ return pv.text.code
13
+ else:
14
+ raise ValueError(f"Invalid permissible value in enum : {pv}")
15
+
16
+ def get_enum_permissible_values(self, enum):
17
+ return list(map(self.extract_permissible_text, enum.permissible_values or []))
@@ -0,0 +1,216 @@
1
+ import logging
2
+ import os
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+ from pathlib import PurePosixPath
6
+ from types import ModuleType
7
+ from typing import Optional
8
+
9
+ import click
10
+ from jinja2 import Environment, PackageLoader
11
+ from linkml_runtime.linkml_model.meta import TypeDefinition
12
+ from linkml_runtime.utils.compile_python import compile_python
13
+ from linkml_runtime.utils.formatutils import camelcase
14
+ from linkml_runtime.utils.schemaview import SchemaView
15
+
16
+ from linkml._version import __version__
17
+ from linkml.generators.oocodegen import OOClass, OOCodeGenerator, OODocument
18
+
19
+ from .class_generator_mixin import ClassGeneratorMixin
20
+ from .enum_generator_mixin import EnumGeneratorMixin
21
+ from .slot_generator_mixin import SlotGeneratorMixin
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ # keys are template_path
27
+ TYPEMAP = {
28
+ "panderagen_class_based": {
29
+ "xsd:string": "str",
30
+ "xsd:integer": "int",
31
+ "xsd:float": "float",
32
+ "xsd:double": "float",
33
+ "xsd:boolean": "bool",
34
+ "xsd:dateTime": "DateTime",
35
+ "xsd:date": "Date",
36
+ "xsd:time": "Time",
37
+ "xsd:anyURI": "str",
38
+ "xsd:decimal": "float",
39
+ },
40
+ }
41
+
42
+
43
+ class TemplateEnum(Enum):
44
+ CLASS_BASED = "panderagen_class_based"
45
+
46
+
47
+ @dataclass
48
+ class PanderaGenerator(OOCodeGenerator, EnumGeneratorMixin, ClassGeneratorMixin, SlotGeneratorMixin):
49
+ """
50
+ Generates Pandera python classes from a LinkML schema.
51
+
52
+ Status: incompletely implemented
53
+
54
+ One styles is supported:
55
+
56
+ - panderagen_class_based
57
+ """
58
+
59
+ DEFAULT_TEMPLATE_PATH = "panderagen_class_based"
60
+ DEFAULT_TEMPLATE_FILE = "pandera.jinja2"
61
+
62
+ # ClassVars
63
+ generatorname = os.path.basename(__file__)
64
+ generatorstem = PurePosixPath(generatorname).stem
65
+ generatorversion = "0.0.1"
66
+ valid_formats = ["python"]
67
+ file_extension = "py"
68
+ java_style = False
69
+
70
+ # ObjectVars
71
+ template_file: Optional[str] = None
72
+ template_path: str = DEFAULT_TEMPLATE_PATH
73
+
74
+ gen_classvars: bool = True
75
+ gen_slots: bool = True
76
+ genmeta: bool = False
77
+ emit_metadata: bool = True
78
+ coerce: bool = False
79
+
80
+ def default_value_for_type(self, typ: str) -> str:
81
+ """Allow underlying framework to handle default if not specified."""
82
+ return None
83
+
84
+ @staticmethod
85
+ def make_multivalued(range: str) -> str:
86
+ return f"List[{range}]"
87
+
88
+ def uri_type_map(self, xsd_uri: str, template: str = None):
89
+ if template is None:
90
+ template = self.template_path
91
+
92
+ return TYPEMAP[template].get(xsd_uri)
93
+
94
+ def map_type(self, t: TypeDefinition) -> str:
95
+ if t.uri:
96
+ typ = self.uri_type_map(t.uri)
97
+ return typ
98
+ elif t.typeof:
99
+ typ = self.map_type(self.schemaview.get_type(t.typeof))
100
+ return typ
101
+ else:
102
+ raise ValueError(f"{t} cannot be mapped to a type")
103
+
104
+ def load_template(self, template_filename):
105
+ jinja_env = Environment(loader=PackageLoader("linkml.generators.panderagen", self.template_path))
106
+ return jinja_env.get_template(template_filename)
107
+
108
+ def compile_pandera(self) -> ModuleType:
109
+ """
110
+ Generates and compiles Pandera model
111
+ """
112
+ pandera_code = self.serialize()
113
+
114
+ return compile_python(pandera_code)
115
+
116
+ def serialize(self, rendered_module: Optional[OODocument] = None) -> str:
117
+ """
118
+ Serialize the schema to a Pandera module as a string
119
+ """
120
+ if self.template_path is None:
121
+ self.template_path = PanderaGenerator.DEFAULT_TEMPLATE_PATH
122
+
123
+ if rendered_module is not None:
124
+ module = rendered_module
125
+ else:
126
+ module = self.render()
127
+
128
+ if self.template_file is None:
129
+ self.template_file = PanderaGenerator.DEFAULT_TEMPLATE_FILE
130
+ template_file = self.template_file
131
+
132
+ template_obj = self.load_template(template_file)
133
+
134
+ code = template_obj.render(
135
+ doc=module,
136
+ metamodel_version=self.schema.metamodel_version,
137
+ model_version=self.schema.version,
138
+ coerce=self.coerce,
139
+ type_map=TYPEMAP,
140
+ template_path=self.template_path,
141
+ )
142
+ return code
143
+
144
+ def render(self) -> OODocument:
145
+ """
146
+ Create a data structure ready to pass to the serialization templates.
147
+ """
148
+ sv: SchemaView = self.schemaview
149
+
150
+ module_name = camelcase(sv.schema.name)
151
+
152
+ oodoc = OODocument(name=module_name, package=self.package, source_schema=sv.schema)
153
+
154
+ classes = []
155
+
156
+ for c in self.ordered_classes():
157
+ cn = c.name
158
+ safe_cn = camelcase(cn)
159
+ ooclass = OOClass(
160
+ name=safe_cn,
161
+ description=c.description,
162
+ package=self.package,
163
+ fields=[],
164
+ source_class=c,
165
+ )
166
+ classes.append(ooclass)
167
+ if c.mixin:
168
+ ooclass.mixin = c.mixin
169
+ if c.mixins:
170
+ ooclass.mixins = [(x) for x in c.mixins]
171
+ if c.is_a:
172
+ ooclass.is_a = self.get_class_name(c.is_a)
173
+ parent_slots = sv.class_slots(c.is_a)
174
+ else:
175
+ parent_slots = []
176
+ for sn in sv.class_slots(cn):
177
+ oofield = self.handle_slot(cn, sn)
178
+ if sn not in parent_slots:
179
+ ooclass.fields.append(oofield)
180
+ ooclass.all_fields.append(oofield)
181
+
182
+ oodoc.classes = classes
183
+
184
+ return oodoc
185
+
186
+
187
+ @click.option("--package", help="Package name where relevant for generated class files")
188
+ @click.option("--template-path", help="Optional jinja2 template directory within module")
189
+ @click.option("--template-file", help="Optional jinja2 template to use for class generation")
190
+ @click.version_option(__version__, "-V", "--version")
191
+ @click.argument("yamlfile")
192
+ @click.command(name="gen-pandera")
193
+ def cli(
194
+ yamlfile,
195
+ package=None,
196
+ template_path=None,
197
+ template_file=None,
198
+ **args,
199
+ ):
200
+ if template_path is not None and template_path not in TYPEMAP:
201
+ raise Exception(f"Template {template_path} not supported")
202
+
203
+ """Generate Pandera classes to represent a LinkML model"""
204
+ gen = PanderaGenerator(
205
+ yamlfile,
206
+ package=package,
207
+ template_path=template_path,
208
+ template_file=template_file,
209
+ **args,
210
+ )
211
+
212
+ print(gen.serialize())
213
+
214
+
215
+ if __name__ == "__main__":
216
+ cli()
@@ -0,0 +1,26 @@
1
+ {#-
2
+ Jinja2 Template for a Pandera class-based model
3
+ Details at https://pandera.readthedocs.io/en/stable/dataframe_models.html
4
+ -#}
5
+ {%- import 'slots.jinja2' as slot_macros -%}
6
+
7
+ {%- macro render_class(cls) %}
8
+ class {{cls.name}}(
9
+ {%- if cls.is_a -%}
10
+ {{ cls.is_a }}
11
+ {%- else -%}
12
+ pla.DataFrameModel, _LinkmlPanderaValidator
13
+ {%- endif -%}
14
+ ):
15
+ {%- if cls.source_class.description %}
16
+ """
17
+ {{ cls.source_class.description }}
18
+ """
19
+ {% endif -%}
20
+ {%- if (cls.fields | length) == 0 %}
21
+ pass
22
+ {% endif -%}
23
+ {%- for field in cls.fields -%}
24
+ {{ slot_macros.render_slot(field) }}
25
+ {%- endfor -%}
26
+ {% endmacro -%}