linkml 1.7.7__tar.gz → 1.7.8__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 (148) hide show
  1. {linkml-1.7.7 → linkml-1.7.8}/PKG-INFO +2 -1
  2. {linkml-1.7.7 → linkml-1.7.8}/linkml/__init__.py +14 -0
  3. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/subset.md.jinja2 +7 -7
  4. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/array.py +15 -3
  5. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/pydanticgen.py +4 -2
  6. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/template.py +6 -4
  7. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pythongen.py +3 -0
  8. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/rdfgen.py +9 -1
  9. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/shaclgen.py +14 -3
  10. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sqlalchemygen.py +1 -0
  11. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sqltablegen.py +16 -1
  12. {linkml-1.7.7 → linkml-1.7.8}/linkml/transformers/relmodel_transformer.py +21 -1
  13. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/generator.py +9 -5
  14. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/rawloader.py +5 -1
  15. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/schemaloader.py +2 -1
  16. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/sqlutils.py +13 -14
  17. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/plugins/shacl_validation_plugin.py +10 -4
  18. {linkml-1.7.7 → linkml-1.7.8}/pyproject.toml +16 -8
  19. {linkml-1.7.7 → linkml-1.7.8}/setup.py +3 -2
  20. {linkml-1.7.7 → linkml-1.7.8}/LICENSE +0 -0
  21. {linkml-1.7.7 → linkml-1.7.8}/README.md +0 -0
  22. {linkml-1.7.7 → linkml-1.7.8}/linkml/_version.py +0 -0
  23. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/PythonGenNotes.md +0 -0
  24. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/README.md +0 -0
  25. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/__init__.py +0 -0
  26. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/common/__init__.py +0 -0
  27. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/common/type_designators.py +0 -0
  28. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/csvgen.py +0 -0
  29. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/class.md.jinja2 +0 -0
  30. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/class_diagram.md.jinja2 +0 -0
  31. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/common_metadata.md.jinja2 +0 -0
  32. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/enum.md.jinja2 +0 -0
  33. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/index.md.jinja2 +0 -0
  34. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/index.tex.jinja2 +0 -0
  35. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/schema.md.jinja2 +0 -0
  36. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/slot.md.jinja2 +0 -0
  37. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen/type.md.jinja2 +0 -0
  38. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/docgen.py +0 -0
  39. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/dotgen.py +0 -0
  40. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/erdiagramgen.py +0 -0
  41. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/excelgen.py +0 -0
  42. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/golanggen.py +0 -0
  43. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/golrgen.py +0 -0
  44. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/graphqlgen.py +0 -0
  45. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/javagen/example_template.java.jinja2 +0 -0
  46. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/javagen/java_record_template.jinja2 +0 -0
  47. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/javagen.py +0 -0
  48. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/jsonldcontextgen.py +0 -0
  49. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/jsonldgen.py +1 -1
  50. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/jsonschemagen.py +0 -0
  51. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/legacy/__init__.py +0 -0
  52. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/linkmlgen.py +0 -0
  53. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/markdowngen.py +0 -0
  54. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/namespacegen.py +0 -0
  55. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/oocodegen.py +0 -0
  56. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/owlgen.py +0 -0
  57. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/plantumlgen.py +0 -0
  58. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/prefixmapgen.py +0 -0
  59. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/projectgen.py +0 -0
  60. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/protogen.py +0 -0
  61. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/__init__.py +0 -0
  62. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/black.py +0 -0
  63. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/build.py +0 -0
  64. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/attribute.py.jinja +0 -0
  65. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/base_model.py.jinja +0 -0
  66. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/class.py.jinja +0 -0
  67. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/conditional_import.py.jinja +0 -0
  68. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/enum.py.jinja +0 -0
  69. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/footer.py.jinja +0 -0
  70. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/imports.py.jinja +0 -0
  71. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/module.py.jinja +0 -0
  72. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/pydanticgen/templates/validator.py.jinja +0 -0
  73. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/shacl/__init__.py +0 -0
  74. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/shacl/ifabsent_processor.py +0 -0
  75. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/shacl/shacl_data_type.py +0 -0
  76. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/shexgen.py +0 -0
  77. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sparqlgen.py +0 -0
  78. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sqlalchemy/__init__.py +0 -0
  79. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sqlalchemy/sqlalchemy_declarative_template.py +0 -0
  80. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sqlalchemy/sqlalchemy_imperative_template.py +0 -0
  81. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/sssomgen.py +0 -0
  82. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/string_template.md +0 -0
  83. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/summarygen.py +0 -0
  84. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/terminusdbgen.py +0 -0
  85. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/typescriptgen.py +0 -0
  86. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/yamlgen.py +0 -0
  87. {linkml-1.7.7 → linkml-1.7.8}/linkml/generators/yumlgen.py +0 -0
  88. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/__init__.py +0 -0
  89. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/cli.py +0 -0
  90. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/config/datamodel/.linkmllint.yaml +0 -0
  91. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/config/datamodel/__init__.py +0 -0
  92. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/config/datamodel/config.py +0 -0
  93. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/config/datamodel/config.yaml +0 -0
  94. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/config/default.yaml +0 -0
  95. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/config/recommended.yaml +0 -0
  96. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/formatters/__init__.py +0 -0
  97. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/formatters/formatter.py +0 -0
  98. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/formatters/json_formatter.py +0 -0
  99. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/formatters/markdown_formatter.py +0 -0
  100. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/formatters/terminal_formatter.py +0 -0
  101. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/formatters/tsv_formatter.py +0 -0
  102. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/linter.py +0 -0
  103. {linkml-1.7.7 → linkml-1.7.8}/linkml/linter/rules.py +0 -0
  104. {linkml-1.7.7 → linkml-1.7.8}/linkml/reporting/__init__.py +0 -0
  105. {linkml-1.7.7 → linkml-1.7.8}/linkml/reporting/model.py +0 -0
  106. {linkml-1.7.7 → linkml-1.7.8}/linkml/transformers/__init__.py +0 -0
  107. {linkml-1.7.7 → linkml-1.7.8}/linkml/transformers/logical_model_transformer.py +0 -0
  108. {linkml-1.7.7 → linkml-1.7.8}/linkml/transformers/model_transformer.py +0 -0
  109. {linkml-1.7.7 → linkml-1.7.8}/linkml/transformers/schema_renamer.py +0 -0
  110. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/__init__.py +0 -0
  111. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/cli_utils.py +0 -0
  112. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/converter.py +0 -0
  113. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/datautils.py +0 -0
  114. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/datavalidator.py +0 -0
  115. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/execute_tutorial.py +0 -0
  116. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/helpers.py +0 -0
  117. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/ifabsent_functions.py +0 -0
  118. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/logictools.py +0 -0
  119. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/mergeutils.py +0 -0
  120. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/schema_builder.py +0 -0
  121. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/schema_fixer.py +0 -0
  122. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/schemasynopsis.py +0 -0
  123. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/typereferences.py +0 -0
  124. {linkml-1.7.7 → linkml-1.7.8}/linkml/utils/validation.py +0 -0
  125. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/__init__.py +0 -0
  126. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/cli.py +0 -0
  127. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/loaders/__init__.py +0 -0
  128. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/loaders/delimited_file_loader.py +0 -0
  129. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/loaders/json_loader.py +0 -0
  130. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/loaders/loader.py +0 -0
  131. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/loaders/passthrough_loader.py +0 -0
  132. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/loaders/yaml_loader.py +0 -0
  133. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/plugins/__init__.py +0 -0
  134. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/plugins/jsonschema_validation_plugin.py +0 -0
  135. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/plugins/pydantic_validation_plugin.py +0 -0
  136. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/plugins/recommended_slots_plugin.py +0 -0
  137. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/plugins/validation_plugin.py +0 -0
  138. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/report.py +0 -0
  139. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/validation_context.py +0 -0
  140. {linkml-1.7.7 → linkml-1.7.8}/linkml/validator/validator.py +0 -0
  141. {linkml-1.7.7 → linkml-1.7.8}/linkml/validators/__init__.py +0 -0
  142. {linkml-1.7.7 → linkml-1.7.8}/linkml/validators/jsonschemavalidator.py +0 -0
  143. {linkml-1.7.7 → linkml-1.7.8}/linkml/validators/sparqlvalidator.py +0 -0
  144. {linkml-1.7.7 → linkml-1.7.8}/linkml/workspaces/__init__.py +0 -0
  145. {linkml-1.7.7 → linkml-1.7.8}/linkml/workspaces/datamodel/__init__.py +0 -0
  146. {linkml-1.7.7 → linkml-1.7.8}/linkml/workspaces/datamodel/workspaces.py +0 -0
  147. {linkml-1.7.7 → linkml-1.7.8}/linkml/workspaces/datamodel/workspaces.yaml +0 -0
  148. {linkml-1.7.7 → linkml-1.7.8}/linkml/workspaces/example_runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: linkml
3
- Version: 1.7.7
3
+ Version: 1.7.8
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
@@ -51,6 +51,7 @@ Requires-Dist: pyyaml
51
51
  Requires-Dist: rdflib (>=6.0.0)
52
52
  Requires-Dist: requests (>=2.22)
53
53
  Requires-Dist: sqlalchemy (>=1.4.31)
54
+ Requires-Dist: typing-extensions (>=4.4.0) ; python_version < "3.9"
54
55
  Requires-Dist: watchdog (>=0.9.0)
55
56
  Project-URL: Documentation, https://linkml.io/linkml/
56
57
  Project-URL: Repository, https://github.com/linkml/linkml
@@ -19,6 +19,13 @@ LOCAL_TYPES_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.TYPES, Format.YAML)
19
19
  LOCAL_MAPPINGS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.MAPPINGS, Format.YAML)
20
20
  LOCAL_ANNOTATIONS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.ANNOTATIONS, Format.YAML)
21
21
  LOCAL_EXTENSIONS_YAML_FILE = linkml_files.LOCAL_PATH_FOR(Source.EXTENSIONS, Format.YAML)
22
+ LOCAL_MODEL_YAML_FILES = (
23
+ LOCAL_METAMODEL_YAML_FILE,
24
+ LOCAL_TYPES_YAML_FILE,
25
+ LOCAL_MAPPINGS_YAML_FILE,
26
+ LOCAL_ANNOTATIONS_YAML_FILE,
27
+ LOCAL_EXTENSIONS_YAML_FILE,
28
+ )
22
29
 
23
30
  # Local location of jsonld and context.jsonld files
24
31
  LOCAL_METAMODEL_LDCONTEXT_FILE = linkml_files.LOCAL_PATH_FOR(Source.META, Format.JSONLD)
@@ -55,6 +62,13 @@ METATYPE_NAMESPACE = METAMODEL_NAMESPACE
55
62
  METAMAPPING_NAMESPACE = METAMODEL_NAMESPACE
56
63
  METAANNOTATIONS_NAMESPACE = METAMODEL_NAMESPACE
57
64
  METAEXTENSIONS_NAMESPACE = METAMODEL_NAMESPACE
65
+ NAMESPACES = (
66
+ METAMODEL_NAMESPACE,
67
+ METATYPE_NAMESPACE,
68
+ METAMAPPING_NAMESPACE,
69
+ METAANNOTATIONS_NAMESPACE,
70
+ METAEXTENSIONS_NAMESPACE,
71
+ )
58
72
 
59
73
  # Metamodel Context URI
60
74
  METAMODEL_CONTEXT_URI = linkml_files.URL_FOR(Source.META, Format.JSONLD)
@@ -43,20 +43,18 @@ URI: {{ gen.link(element) }}
43
43
 
44
44
  | Class | Description |
45
45
  | --- | --- |
46
- {% for c in gen.all_class_objects()|sort(attribute=sort_by) -%}
46
+ {% for c in classes_in_subset -%}
47
47
  {%- if element.name in c.in_subset -%}
48
48
  | {{gen.link(c)}} | {{c.description|enshorten}} |
49
49
  {% endif -%}
50
50
  {% endfor %}
51
51
 
52
- {% for c in gen.all_class_objects()|sort(attribute=sort_by) -%}
52
+ {% for c in classes_in_subset -%}
53
53
  {%- if element.name in c.in_subset -%}
54
- ### {{ gen.name(c) }}
55
54
 
56
- {{c.description}}
55
+ {% set induced_slots = gen.class_induced_slots(c.name)|sort(attribute=sort_by) %}
57
56
 
58
57
  {%- set filtered_slots = [] -%}
59
-
60
58
  {%- for s in induced_slots|sort(attribute=sort_by) -%}
61
59
  {%- if element.name in s.in_subset or element.name in schemaview.get_slot(s.name).in_subset -%}
62
60
  {% set _ = filtered_slots.append(s) %}
@@ -64,10 +62,12 @@ URI: {{ gen.link(element) }}
64
62
  {%- endfor %}
65
63
 
66
64
  {%- if filtered_slots|length > 0 -%}
67
- | Name | Cardinality and Range | Description |
65
+ ### Slots from {{ gen.link(c) }} also in _{{ element.name }}_
66
+
67
+ | Name | Cardinality and Range | Description |
68
68
  | --- | --- | --- |
69
69
  {% for s in filtered_slots -%}
70
- | {{gen.link(s)}} | {{ gen.cardinality(s) }} <br/> {{gen.link(s.range)}} | {{s.description|enshorten}} {% if s.identifier %}**identifier**{% endif %} |
70
+ | {{gen.link(s)}} | {{ gen.cardinality(s) }} <br/> {{gen.link(s.range)}} | {{s.description|enshorten}} {% if s.identifier %}**identifier**{% endif %} |
71
71
  {% endfor %}
72
72
  {%- endif %}
73
73
 
@@ -30,7 +30,7 @@ else:
30
30
  from typing import Annotated
31
31
 
32
32
  from linkml.generators.pydanticgen.build import SlotResult
33
- from linkml.generators.pydanticgen.template import Import, Imports, ObjectImport
33
+ from linkml.generators.pydanticgen.template import ConditionalImport, Import, Imports, ObjectImport
34
34
 
35
35
 
36
36
  class ArrayRepresentation(Enum):
@@ -54,7 +54,14 @@ if int(PYDANTIC_VERSION[0]) >= 2:
54
54
  item_schema = handler.generate_schema(item_type)
55
55
  if item_schema.get("type", "any") != "any":
56
56
  item_schema["strict"] = True
57
- array_ref = f"any-shape-array-{item_type.__name__}"
57
+
58
+ if item_type is Any:
59
+ # Before python 3.11, `Any` type was a special object without a __name__
60
+ item_name = "Any"
61
+ else:
62
+ item_name = item_type.__name__
63
+
64
+ array_ref = f"any-shape-array-{item_name}"
58
65
 
59
66
  schema = core_schema.definitions_schema(
60
67
  core_schema.list_schema(core_schema.definition_reference_schema(array_ref)),
@@ -78,7 +85,6 @@ if int(PYDANTIC_VERSION[0]) >= 2:
78
85
  + Import(
79
86
  module="typing",
80
87
  objects=[
81
- ObjectImport(name="Annotated"),
82
88
  ObjectImport(name="Generic"),
83
89
  ObjectImport(name="Iterable"),
84
90
  ObjectImport(name="TypeVar"),
@@ -86,6 +92,12 @@ if int(PYDANTIC_VERSION[0]) >= 2:
86
92
  ObjectImport(name="get_args"),
87
93
  ],
88
94
  )
95
+ + ConditionalImport(
96
+ condition="sys.version_info.minor > 8",
97
+ module="typing",
98
+ objects=[ObjectImport(name="Annotated")],
99
+ alternative=Import(module="typing_extensions", objects=[ObjectImport(name="Annotated")]),
100
+ )
89
101
  + Import(module="pydantic", objects=[ObjectImport(name="GetCoreSchemaHandler")])
90
102
  + Import(module="pydantic_core", objects=[ObjectImport(name="CoreSchema"), ObjectImport(name="core_schema")])
91
103
  )
@@ -76,6 +76,7 @@ DEFAULT_IMPORTS = (
76
76
  + Import(module="decimal", objects=[ObjectImport(name="Decimal")])
77
77
  + Import(module="enum", objects=[ObjectImport(name="Enum")])
78
78
  + Import(module="re")
79
+ + Import(module="sys")
79
80
  + Import(
80
81
  module="typing",
81
82
  objects=[
@@ -644,10 +645,11 @@ class PydanticGenerator(OOCodeGenerator):
644
645
  for k, c in pyschema.classes.items():
645
646
  attrs = {}
646
647
  for attr_name, src_attr in c.attributes.items():
648
+ src_attr = src_attr._as_dict
647
649
  new_fields = {
648
- k: src_attr._as_dict.get(k, None)
650
+ k: src_attr.get(k, None)
649
651
  for k in PydanticAttribute.model_fields.keys()
650
- if src_attr._as_dict.get(k, None) is not None
652
+ if src_attr.get(k, None) is not None
651
653
  }
652
654
  predef_slot = predefined.get(k, {}).get(attr_name, None)
653
655
  if predef_slot is not None:
@@ -1,3 +1,4 @@
1
+ from copy import copy
1
2
  from importlib.util import find_spec
2
3
  from typing import Any, ClassVar, Dict, Generator, List, Literal, Optional, Union, overload
3
4
 
@@ -54,6 +55,10 @@ class TemplateModel(BaseModel):
54
55
  """
55
56
 
56
57
  template: ClassVar[str]
58
+ _environment: ClassVar[Environment] = Environment(
59
+ loader=PackageLoader("linkml.generators.pydanticgen", "templates"), trim_blocks=True, lstrip_blocks=True
60
+ )
61
+
57
62
  pydantic_ver: int = int(PYDANTIC_VERSION[0])
58
63
 
59
64
  def render(self, environment: Optional[Environment] = None, black: bool = False) -> str:
@@ -95,14 +100,11 @@ class TemplateModel(BaseModel):
95
100
  def environment(cls) -> Environment:
96
101
  """
97
102
  Default environment for Template models.
98
-
99
103
  uses a :class:`jinja2.PackageLoader` for the templates directory within this module
100
104
  with the ``trim_blocks`` and ``lstrip_blocks`` parameters set to ``True`` so that the
101
105
  default templates could be written in a more readable way.
102
106
  """
103
- return Environment(
104
- loader=PackageLoader("linkml.generators.pydanticgen", "templates"), trim_blocks=True, lstrip_blocks=True
105
- )
107
+ return copy(cls._environment)
106
108
 
107
109
  if int(PYDANTIC_VERSION[0]) < 2:
108
110
  # simulate pydantic 2's model_fields behavior
@@ -4,6 +4,7 @@ import os
4
4
  import re
5
5
  from copy import copy
6
6
  from dataclasses import dataclass
7
+ from pathlib import Path
7
8
  from types import ModuleType
8
9
  from typing import Callable, Dict, Iterator, List, Optional, Set, Tuple, Union
9
10
 
@@ -62,6 +63,8 @@ class PythonGenerator(Generator):
62
63
  emit_metadata: bool = True
63
64
 
64
65
  def __post_init__(self) -> None:
66
+ if isinstance(self.schema, Path):
67
+ self.schema = str(self.schema)
65
68
  self.sourcefile = self.schema
66
69
  self.schemaview = SchemaView(self.schema, base_dir=self.base_dir)
67
70
  super().__post_init__()
@@ -7,10 +7,12 @@ Generate a JSON LD representation of the model
7
7
 
8
8
  import os
9
9
  import urllib.parse as urlparse
10
+ from copy import deepcopy
10
11
  from dataclasses import dataclass
11
12
  from typing import List, Optional
12
13
 
13
14
  import click
15
+ from linkml_runtime.linkml_model import SchemaDefinition
14
16
  from rdflib import Graph
15
17
  from rdflib.plugin import Parser as rdflib_Parser
16
18
  from rdflib.plugin import plugins as rdflib_plugins
@@ -35,13 +37,19 @@ class RDFGenerator(Generator):
35
37
  # ObjectVars
36
38
  emit_metadata: bool = False
37
39
  context: List[str] = None
40
+ original_schema: SchemaDefinition = None
41
+ """See https://github.com/linkml/linkml/issues/871"""
42
+
43
+ def __post_init__(self):
44
+ self.original_schema = deepcopy(self.schema)
45
+ super().__post_init__()
38
46
 
39
47
  def _data(self, g: Graph) -> str:
40
48
  return g.serialize(format="turtle" if self.format == "ttl" else self.format)
41
49
 
42
50
  def end_schema(self, output: Optional[str] = None, context: str = None, **_) -> None:
43
51
  gen = JSONLDGenerator(
44
- self,
52
+ self.original_schema,
45
53
  format=JSONLDGenerator.valid_formats[0],
46
54
  metadata=self.emit_metadata,
47
55
  importmap=self.importmap,
@@ -22,7 +22,8 @@ class ShaclGenerator(Generator):
22
22
  # ClassVars
23
23
  closed: bool = True
24
24
  """True means add 'sh:closed=true' to all shapes, except of mixin shapes and shapes, that have parents"""
25
-
25
+ suffix: str = None
26
+ """parameterized suffix to be appended. No suffix per default."""
26
27
  generatorname = os.path.basename(__file__)
27
28
  generatorversion = "0.0.1"
28
29
  valid_formats = ["ttl"]
@@ -59,9 +60,12 @@ class ShaclGenerator(Generator):
59
60
 
60
61
  def shape_pv(p, v):
61
62
  if v is not None:
62
- g.add((class_uri, p, v))
63
+ g.add((class_uri_with_suffix, p, v))
63
64
 
64
65
  class_uri = URIRef(sv.get_uri(c, expand=True))
66
+ class_uri_with_suffix = class_uri
67
+ if self.suffix is not None:
68
+ class_uri_with_suffix += self.suffix
65
69
  shape_pv(RDF.type, SH.NodeShape)
66
70
  shape_pv(SH.targetClass, class_uri) # TODO
67
71
  if self.closed:
@@ -211,14 +215,21 @@ def add_simple_data_type(func: Callable, r: ElementName) -> None:
211
215
 
212
216
 
213
217
  @shared_arguments(ShaclGenerator)
218
+ @click.command()
214
219
  @click.option(
215
220
  "--closed/--non-closed",
216
221
  default=True,
217
222
  show_default=True,
218
223
  help="Use '--closed' to generate closed SHACL shapes. Use '--non-closed' to generate open SHACL shapes.",
219
224
  )
225
+ @click.option(
226
+ "-s",
227
+ "--suffix",
228
+ default=None,
229
+ show_default=True,
230
+ help="Use --suffix to append given string to SHACL class name (e. g. --suffix Shape: Person becomes PersonShape).",
231
+ )
220
232
  @click.version_option(__version__, "-V", "--version")
221
- @click.command()
222
233
  def cli(yamlfile, **args):
223
234
  """Generate SHACL turtle from a LinkML model"""
224
235
  gen = ShaclGenerator(yamlfile, **args)
@@ -121,6 +121,7 @@ class SQLAlchemyGenerator(Generator):
121
121
  is_join_table=lambda c: any(tag for tag in c.annotations.keys() if tag == "linkml:derived_from"),
122
122
  classes=rel_schema_classes_ordered,
123
123
  )
124
+ logging.debug(f"# Generated code:\n{code}")
124
125
  return code
125
126
 
126
127
  def serialize(self, **kwargs) -> str:
@@ -211,7 +211,22 @@ class SQLTableGenerator(Generator):
211
211
  col.comment = s.description
212
212
  cols.append(col)
213
213
  for uc_name, uc in c.unique_keys.items():
214
- sql_uc = UniqueConstraint(*[sql_name(sn) for sn in uc.unique_key_slots])
214
+
215
+ def _sql_name(sn: str):
216
+ if sn in c.attributes:
217
+ return sql_name(sn)
218
+ else:
219
+ # for candidate in c.attributes.values():
220
+ # if "original_slot" in candidate.annotations:
221
+ # original = candidate.annotations["original_slot"]
222
+ # if original.value == sn:
223
+ # return sql_name(candidate.name)
224
+ return None
225
+
226
+ sql_names = [_sql_name(sn) for sn in uc.unique_key_slots]
227
+ if any(sn is None for sn in sql_names):
228
+ continue
229
+ sql_uc = UniqueConstraint(*sql_names)
215
230
  cols.append(sql_uc)
216
231
  Table(sql_name(cn), schema_metadata, *cols, comment=str(c.description))
217
232
  schema_metadata.create_all(engine)
@@ -226,6 +226,7 @@ class RelationalModelTransformer:
226
226
 
227
227
  # TODO: separate out the logic into separate testable methods
228
228
  target_sv.set_modified()
229
+ multivalued_slots_original = []
229
230
  # post-process target schema
230
231
  for cn, c in target_sv.all_classes().items():
231
232
  if self.foreign_key_policy == ForeignKeyPolicy.NO_FOREIGN_KEYS:
@@ -243,6 +244,7 @@ class RelationalModelTransformer:
243
244
  slot.inlined or slot.inlined_as_list or "shared" in slot.annotations
244
245
  )
245
246
  if slot.multivalued:
247
+ multivalued_slots_original.append(slot.name)
246
248
  slot.multivalued = False
247
249
  slot_name = slot.name
248
250
  sn_singular = slot.singular_name if slot.singular_name else slot.name
@@ -332,6 +334,7 @@ class RelationalModelTransformer:
332
334
  # add PK and FK anns
333
335
  target_sv.set_modified()
334
336
  fk_policy = self.foreign_key_policy
337
+ forward_map = {}
335
338
  for c in target.classes.values():
336
339
  if self.foreign_key_policy == ForeignKeyPolicy.NO_FOREIGN_KEYS:
337
340
  continue
@@ -356,14 +359,31 @@ class RelationalModelTransformer:
356
359
  # if it is already an injected backref, no need to re-inject
357
360
  if "backref" not in a.annotations:
358
361
  del c.attributes[a.name]
362
+ original_name = a.name
359
363
  if "forwardref" not in a.annotations:
360
- add_annotation(a, "original_slot", a.name)
364
+ add_annotation(a, "original_slot", original_name)
361
365
  a.alias = f"{a.name}_{tc_pk_slot.name}"
362
366
  a.name = a.alias
363
367
  c.attributes[a.name] = a
368
+ forward_map[original_name] = a.name
364
369
  ann = Annotation("foreign_key", f"{tc.name}.{tc_pk_slot.name}")
365
370
  a.annotations[ann.tag] = ann
366
371
  target_sv.set_modified()
372
+ # Rewrite unique key constraints
373
+ # - if a slot has a range of object, it may be renamed, e.g. person => person_id
374
+ # - if a slot is multivalued then it is translated to backref and the UC must be dropped
375
+ removed_ucs = []
376
+ for uc_name, uc in c.unique_keys.items():
377
+ if any(sn in multivalued_slots_original for sn in uc.unique_key_slots):
378
+ logging.warning(
379
+ f"Cannot represent uniqueness constraint {uc_name}. "
380
+ f"one of the slots {uc.unique_key_slots} is multivalued"
381
+ )
382
+ removed_ucs.append(uc_name)
383
+ new_slot_names = [forward_map.get(sn, sn) for sn in uc.unique_key_slots]
384
+ uc.unique_key_slots = new_slot_names
385
+ for uc_name in removed_ucs:
386
+ del c.unique_keys[uc_name]
367
387
 
368
388
  result = TransformationResult(target, mappings=mappings)
369
389
  return result
@@ -30,7 +30,6 @@ from typing import Callable, ClassVar, Dict, List, Mapping, Optional, Set, TextI
30
30
  import click
31
31
  from click import Argument, Command, Option
32
32
  from linkml_runtime import SchemaView
33
- from linkml_runtime.dumpers import yaml_dumper
34
33
  from linkml_runtime.linkml_model.meta import (
35
34
  ClassDefinition,
36
35
  ClassDefinitionName,
@@ -83,7 +82,7 @@ class Generator(metaclass=abc.ABCMeta):
83
82
  For usage `Generator Docs <https://linkml.io/linkml/generators/>`_
84
83
  """
85
84
 
86
- schema: Union[str, TextIO, SchemaDefinition, "Generator"]
85
+ schema: Union[str, TextIO, SchemaDefinition, "Generator", Path]
87
86
  """metamodel compliant schema. Can be URI, file name, actual schema, another generator, an
88
87
  open file or a pre-parsed schema"""
89
88
 
@@ -130,7 +129,7 @@ class Generator(metaclass=abc.ABCMeta):
130
129
  useuris: Optional[bool] = None
131
130
  """True means declared class slot uri's are used. False means use model uris"""
132
131
 
133
- log_level: int = DEFAULT_LOG_LEVEL_INT
132
+ log_level: Optional[int] = DEFAULT_LOG_LEVEL_INT
134
133
  """Logging level, 0 is minimum"""
135
134
 
136
135
  mergeimports: Optional[bool] = True
@@ -180,6 +179,8 @@ class Generator(metaclass=abc.ABCMeta):
180
179
  def __post_init__(self) -> None:
181
180
  if not self.logger:
182
181
  self.logger = logging.getLogger()
182
+ if self.log_level is not None:
183
+ self.logger.setLevel(self.log_level)
183
184
  if self.format is None:
184
185
  self.format = self.valid_formats[0]
185
186
  if self.format not in self.valid_formats:
@@ -191,7 +192,11 @@ class Generator(metaclass=abc.ABCMeta):
191
192
  self.source_file_size = None
192
193
  if self.requires_metamodel:
193
194
  self.metamodel = _resolved_metamodel(self.mergeimports)
195
+
194
196
  schema = self.schema
197
+ if isinstance(schema, Path):
198
+ schema = str(schema)
199
+
195
200
  # TODO: remove aliasing
196
201
  self.emit_metadata = self.metadata
197
202
  if self.uses_schemaloader:
@@ -225,8 +230,7 @@ class Generator(metaclass=abc.ABCMeta):
225
230
  # schemaloader based methods require schemas to have been created via SchemaLoader,
226
231
  # which prepopulates some fields (e.g. definition_url). If the schema has not been processed through the
227
232
  # loader, then roundtrip
228
- if any(c for c in schema.classes.values() if not c.definition_uri):
229
- schema = yaml_dumper.dumps(schema)
233
+ schema = schema._as_dict
230
234
  loader = SchemaLoader(
231
235
  schema,
232
236
  self.base_dir,
@@ -1,5 +1,6 @@
1
1
  import copy
2
2
  from datetime import datetime
3
+ from pathlib import Path
3
4
  from typing import Optional, TextIO, Union
4
5
  from urllib.parse import urlparse
5
6
 
@@ -29,7 +30,7 @@ SchemaDefinition.MissingRequiredField = mrf
29
30
 
30
31
 
31
32
  def load_raw_schema(
32
- data: Union[str, dict, TextIO],
33
+ data: Union[str, dict, TextIO, Path],
33
34
  source_file: Optional[str] = None,
34
35
  source_file_date: Optional[str] = None,
35
36
  source_file_size: Optional[int] = None,
@@ -58,6 +59,9 @@ def load_raw_schema(
58
59
  assert source_file_date is None, "source_file_date parameter not allowed if data is a file or URL"
59
60
  assert source_file_size is None, "source_file_size parameter not allowed if data is a file or URL"
60
61
 
62
+ if isinstance(data, Path):
63
+ data = str(data)
64
+
61
65
  # Convert the input into a valid SchemaDefinition
62
66
  if isinstance(data, (str, dict, TextIO)):
63
67
  # TODO: Build a generic loader that detects type from suffix or content and invokes the appropriate loader
@@ -2,6 +2,7 @@ import logging
2
2
  import os
3
3
  from collections import OrderedDict
4
4
  from copy import deepcopy
5
+ from pathlib import Path
5
6
  from typing import Dict, Iterator, List, Mapping, Optional, Set, TextIO, Tuple, Union, cast
6
7
  from urllib.parse import urlparse
7
8
 
@@ -32,7 +33,7 @@ from linkml.utils.schemasynopsis import SchemaSynopsis
32
33
  class SchemaLoader:
33
34
  def __init__(
34
35
  self,
35
- data: Union[str, TextIO, SchemaDefinition, dict],
36
+ data: Union[str, TextIO, SchemaDefinition, dict, Path],
36
37
  base_dir: Optional[str] = None,
37
38
  namespaces: Optional[Namespaces] = None,
38
39
  useuris: Optional[bool] = None,
@@ -58,16 +58,22 @@ class SQLStore:
58
58
  - mapping your data/objects in any LinkML compliant data format (json. yaml, rdf) into ORM objects
59
59
  """
60
60
 
61
- schema: Union[str, SchemaDefinition] = None
62
- schemaview: SchemaView = None
63
- engine: Engine = None
64
- database_path: str = None
61
+ schema: Optional[Union[str, Path, SchemaDefinition]] = None
62
+ schemaview: Optional[SchemaView] = None
63
+ engine: Optional[Engine] = None
64
+ database_path: Union[str, Path] = None
65
65
  use_memory: bool = False
66
66
  """https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#using-a-memory-database-in-multiple-threads"""
67
67
 
68
- module: ModuleType = None
69
- native_module: ModuleType = None
70
- include_schema_in_database: bool = None
68
+ module: Optional[ModuleType] = None
69
+ native_module: Optional[ModuleType] = None
70
+ include_schema_in_database: bool = False
71
+
72
+ def __post_init__(self):
73
+ if self.database_path is None and not self.use_memory:
74
+ raise ValueError("Must have database path or use_memory must be True")
75
+ if self.schema is not None and self.schemaview is None:
76
+ self.schemaview = SchemaView(self.schema)
71
77
 
72
78
  def db_exists(self, create=True, force=False) -> Optional[str]:
73
79
  """
@@ -117,8 +123,6 @@ class SQLStore:
117
123
  """
118
124
  gen = SQLAlchemyGenerator(self.schema)
119
125
  self.module = gen.compile_sqla(template=TemplateEnum.DECLARATIVE)
120
- if self.schemaview is None:
121
- self.schemaview = SchemaView(self.schema)
122
126
  return self.module
123
127
 
124
128
  def compile_native(self) -> ModuleType:
@@ -223,7 +227,6 @@ class SQLStore:
223
227
  for n, nu_typ in inspect.getmembers(self.module):
224
228
  # TODO: make more efficient
225
229
  if n == typ.__name__:
226
- # print(f'Creating {nu_typ} from: {inst_args}')
227
230
  nu_obj = nu_typ(**inst_args)
228
231
  return nu_obj
229
232
  raise ValueError(f"Cannot find {typ.__name__} in {self.module}")
@@ -237,8 +240,6 @@ class SQLStore:
237
240
  :param obj: sqla object
238
241
  :return: native dataclass object
239
242
  """
240
- if self.schemaview is None:
241
- self.schemaview = SchemaView(self.schema)
242
243
  typ = type(obj)
243
244
  nm = self.schemaview.class_name_mappings()
244
245
  if typ.__name__ in nm:
@@ -262,9 +263,7 @@ class SQLStore:
262
263
  for n, nu_typ in inspect.getmembers(self.native_module):
263
264
  # TODO: make more efficient
264
265
  if n == typ.__name__:
265
- # print(f'CREATING {nu_typ} FROM {inst_args}')
266
266
  nu_obj = nu_typ(**inst_args)
267
- # print(f'CREATED {nu_obj}')
268
267
  return nu_obj
269
268
  raise ValueError(f"Cannot find {typ.__name__} in {self.native_module}")
270
269
  else:
@@ -34,21 +34,27 @@ class ShaclValidationPlugin(ValidationPlugin):
34
34
  self.closed = closed
35
35
  self.shacl_path = shacl_path
36
36
  self.raise_on_conversion_error = raise_on_conversion_error
37
+ self._loaded_graphs = {}
37
38
 
38
39
  def _shacl_graph(self, context: ValidationContext) -> Optional[rdflib.Graph]:
39
40
  g = rdflib.Graph()
40
41
  if self.shacl_path:
41
42
  g.parse(str(self.shacl_path))
42
43
  else:
43
- gen = ShaclGenerator(context._schema)
44
- g = gen.as_graph()
44
+ schema_hash = hash(str(context._schema))
45
+ if schema_hash in self._loaded_graphs:
46
+ g = self._loaded_graphs[schema_hash]
47
+ else:
48
+ gen = ShaclGenerator(context._schema)
49
+ g = gen.as_graph()
50
+ self._loaded_graphs[schema_hash] = g
45
51
  return g
46
52
 
47
53
  def process(self, instance: Any, context: ValidationContext) -> Iterator[ValidationResult]:
48
- """Perform JSON Schema validation on the provided instance
54
+ """Perform SHACL Schema validation on the provided instance
49
55
 
50
56
  :param instance: The instance to validate
51
- :param context: The validation context which provides a JSON Schema artifact
57
+ :param context: The validation context which provides a SHACL artifact
52
58
  :return: Iterator over validation results
53
59
  :rtype: Iterator[ValidationResult]
54
60
  """
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "linkml"
3
- version = "1.7.7"
3
+ version = "1.7.8"
4
4
  description = "Linked Open Data Modeling Language"
5
5
  authors = [
6
6
  "Chris Mungall <cjmungall@lbl.gov>",
@@ -124,6 +124,7 @@ sqlalchemy = ">=1.4.31"
124
124
  watchdog = ">=0.9.0"
125
125
  pyshacl = { version = "^0.25.0", optional = true }
126
126
  black = { version=">=24.0.0", optional = true }
127
+ typing-extensions = { version=">=4.4.0", python="<3.9" }
127
128
 
128
129
  [tool.poetry.group.dev.dependencies]
129
130
  chardet = "*"
@@ -133,12 +134,6 @@ nbconvert = "*"
133
134
  nbformat = "*"
134
135
  coverage = "^6.4.1"
135
136
  tox = "^4"
136
- furo = {version = "^2023.03.27", extras = ["docs"]}
137
- sphinxcontrib-mermaid = {version = "^0.7.1", extras = ["docs"]}
138
- sphinx = "*"
139
- sphinx-click = "*"
140
- sphinx-rtd-theme = "*"
141
- myst-parser = "*"
142
137
  requests-cache = "^1.2.0"
143
138
  myst-nb = {version=">=1.0.0", python=">=3.9"}
144
139
  sphinx-design = "^0.5.0"
@@ -157,6 +152,17 @@ black = ["black"]
157
152
  shacl = ["pyshacl"]
158
153
  tests = ["black", "pyshacl"]
159
154
 
155
+ [tool.poetry.group.docs]
156
+ optional = true
157
+
158
+ [tool.poetry.group.docs.dependencies]
159
+ furo = {version = "^2023.03.27", extras = ["docs"]}
160
+ sphinxcontrib-mermaid = {version = "^0.7.1", extras = ["docs"]}
161
+ sphinx = "*"
162
+ sphinx-click = "*"
163
+ sphinx-rtd-theme = "*"
164
+ myst-parser = "*"
165
+
160
166
  [build-system]
161
167
  requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
162
168
  build-backend = "poetry_dynamic_versioning.backend"
@@ -193,7 +199,9 @@ filterwarnings = [
193
199
  ]
194
200
  markers = [
195
201
  "network: mark tests that make external network requests",
196
- "slow: mark test as slow to run"
202
+ "slow: mark test as slow to run",
203
+ "no_asserts: tests that don't have meaningful asserts, but are only snapshot comparisons, or historically had print statements, or other non-erroring behavior",
204
+ "strcmp: tests that compare stringified values rather than the values themselves"
197
205
  ]
198
206
 
199
207
  [tool.ruff]
@@ -55,7 +55,8 @@ install_requires = \
55
55
  'watchdog>=0.9.0']
56
56
 
57
57
  extras_require = \
58
- {'black': ['black>=24.0.0'],
58
+ {':python_version < "3.9"': ['typing-extensions>=4.4.0'],
59
+ 'black': ['black>=24.0.0'],
59
60
  'shacl': ['pyshacl>=0.25.0,<0.26.0'],
60
61
  'tests': ['pyshacl>=0.25.0,<0.26.0', 'black>=24.0.0']}
61
62
 
@@ -113,7 +114,7 @@ entry_points = \
113
114
 
114
115
  setup_kwargs = {
115
116
  'name': 'linkml',
116
- 'version': '1.7.7',
117
+ 'version': '1.7.8',
117
118
  'description': 'Linked Open Data Modeling Language',
118
119
  'long_description': '[![Pyversions](https://img.shields.io/pypi/pyversions/linkml.svg)](https://pypi.python.org/pypi/linkml)\n![](https://github.com/linkml/linkml/workflows/Build/badge.svg)\n[![PyPi](https://img.shields.io/pypi/v/linkml.svg)](https://pypi.python.org/pypi/linkml)\n[![badge](https://img.shields.io/badge/launch-binder-579ACA.svg)](https://mybinder.org/v2/gh/linkml/linkml/main?filepath=notebooks)\n[![DOI](https://zenodo.org/badge/13996/linkml/linkml.svg)](https://zenodo.org/badge/latestdoi/13996/linkml/linkml)\n[![PyPIDownloadsTotal](https://pepy.tech/badge/linkml)](https://pepy.tech/project/linkml)\n[![PyPIDownloadsMonth](https://img.shields.io/pypi/dm/linkml?logo=PyPI&color=blue)](https://pypi.org/project/linkml)\n[![codecov](https://codecov.io/gh/linkml/linkml/branch/main/graph/badge.svg?token=WNQNG986UN)](https://codecov.io/gh/linkml/linkml)\n\n\n# LinkML - Linked Data Modeling Language\n\nLinkML is a linked data modeling language following object-oriented and ontological principles. LinkML models are typically authored in YAML, and can be converted to other schema representation formats such as JSON or RDF.\n\nThis repo holds the tools for generating and working with LinkML. For the LinkML schema (metamodel), please see https://github.com/linkml/linkml-model\n\nThe complete documentation for LinkML can be found here:\n\n - [linkml.io/linkml](https://linkml.io/linkml)\n',
119
120
  'author': 'Chris Mungall',
File without changes
File without changes
File without changes
@@ -60,8 +60,8 @@ class JSONLDGenerator(Generator):
60
60
  """Path to a JSONLD context file"""
61
61
 
62
62
  def __post_init__(self) -> None:
63
- super().__post_init__()
64
63
  self.original_schema = deepcopy(self.schema)
64
+ super().__post_init__()
65
65
 
66
66
  def _add_type(self, node: YAMLRoot) -> dict:
67
67
  if self.format == "jsonld":
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes