shacl2code 0.0.14__tar.gz → 0.0.16__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 (193) hide show
  1. {shacl2code-0.0.14 → shacl2code-0.0.16}/.github/workflows/coverage-generate.yaml +3 -0
  2. {shacl2code-0.0.14 → shacl2code-0.0.16}/.github/workflows/test.yaml +1 -0
  3. {shacl2code-0.0.14 → shacl2code-0.0.16}/PKG-INFO +35 -6
  4. {shacl2code-0.0.14 → shacl2code-0.0.16}/README.md +34 -4
  5. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/__init__.py +2 -1
  6. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/common.py +55 -34
  7. shacl2code-0.0.16/src/shacl2code/lang/cpp.py +224 -0
  8. shacl2code-0.0.16/src/shacl2code/lang/sources/cpp/json.hpp +24765 -0
  9. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/Doxyfile.j2 +2623 -0
  10. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/Makefile.j2 +90 -0
  11. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/api.hpp.j2 +47 -0
  12. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/datetime.cpp.j2 +154 -0
  13. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/datetime.hpp.j2 +105 -0
  14. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/decode.cpp.j2 +56 -0
  15. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/decode.hpp.j2 +299 -0
  16. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/encode.cpp.j2 +106 -0
  17. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/encode.hpp.j2 +342 -0
  18. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/errorhandler.cpp.j2 +64 -0
  19. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/errorhandler.hpp.j2 +141 -0
  20. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/exceptions.hpp.j2 +101 -0
  21. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/extensible.cpp.j2 +199 -0
  22. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/extensible.hpp.j2 +190 -0
  23. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/header.j2 +193 -0
  24. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/jsonld-header.j2 +340 -0
  25. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/jsonld-source.j2 +496 -0
  26. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/link.cpp.j2 +48 -0
  27. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/link.hpp.j2 +54 -0
  28. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/namedindividual.cpp.j2 +71 -0
  29. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/namedindividual.hpp.j2 +109 -0
  30. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/object.cpp.j2 +317 -0
  31. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/object.hpp.j2 +341 -0
  32. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/objectpath.cpp.j2 +106 -0
  33. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/objectpath.hpp.j2 +170 -0
  34. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/objectset.cpp.j2 +340 -0
  35. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/objectset.hpp.j2 +227 -0
  36. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/pkgconfig.pc.j2 +10 -0
  37. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/prop.hpp.j2 +235 -0
  38. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/property.cpp.j2 +478 -0
  39. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/property.hpp.j2 +481 -0
  40. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/propertyvalue.cpp.j2 +65 -0
  41. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/propertyvalue.hpp.j2 +1036 -0
  42. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/ref.hpp.j2 +431 -0
  43. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/refproperty.cpp.j2 +49 -0
  44. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/refproperty.hpp.j2 +210 -0
  45. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/source.j2 +122 -0
  46. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/type.cpp.j2 +39 -0
  47. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/type.hpp.j2 +292 -0
  48. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/util.cpp.j2 +48 -0
  49. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/util.hpp.j2 +37 -0
  50. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/validate.j2 +149 -0
  51. shacl2code-0.0.16/src/shacl2code/lang/templates/cpp/walk.hpp.j2 +86 -0
  52. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/templates/python.j2 +3 -3
  53. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/model.py +9 -1
  54. shacl2code-0.0.16/src/shacl2code/version.py +1 -0
  55. {shacl2code-0.0.14 → shacl2code-0.0.16}/testfixtures/jsonvalidation.py +16 -0
  56. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/conftest.py +16 -1
  57. shacl2code-0.0.16/tests/data/bad-prop-type.ttl +15 -0
  58. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/model/test-context.json +2 -0
  59. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/model/test.ttl +12 -0
  60. shacl2code-0.0.16/tests/expect/cpp/context/Doxyfile +2623 -0
  61. shacl2code-0.0.16/tests/expect/cpp/context/Makefile +106 -0
  62. shacl2code-0.0.16/tests/expect/cpp/context/api.hpp +51 -0
  63. shacl2code-0.0.16/tests/expect/cpp/context/datetime.cpp +143 -0
  64. shacl2code-0.0.16/tests/expect/cpp/context/datetime.hpp +125 -0
  65. shacl2code-0.0.16/tests/expect/cpp/context/decode.cpp +45 -0
  66. shacl2code-0.0.16/tests/expect/cpp/context/decode.hpp +319 -0
  67. shacl2code-0.0.16/tests/expect/cpp/context/encode.cpp +95 -0
  68. shacl2code-0.0.16/tests/expect/cpp/context/encode.hpp +362 -0
  69. shacl2code-0.0.16/tests/expect/cpp/context/errorhandler.cpp +54 -0
  70. shacl2code-0.0.16/tests/expect/cpp/context/errorhandler.hpp +161 -0
  71. shacl2code-0.0.16/tests/expect/cpp/context/exceptions.hpp +121 -0
  72. shacl2code-0.0.16/tests/expect/cpp/context/extensible.cpp +201 -0
  73. shacl2code-0.0.16/tests/expect/cpp/context/extensible.hpp +209 -0
  74. shacl2code-0.0.16/tests/expect/cpp/context/link.cpp +37 -0
  75. shacl2code-0.0.16/tests/expect/cpp/context/link.hpp +74 -0
  76. shacl2code-0.0.16/tests/expect/cpp/context/namedindividual.cpp +60 -0
  77. shacl2code-0.0.16/tests/expect/cpp/context/namedindividual.hpp +128 -0
  78. shacl2code-0.0.16/tests/expect/cpp/context/object.cpp +319 -0
  79. shacl2code-0.0.16/tests/expect/cpp/context/object.hpp +360 -0
  80. shacl2code-0.0.16/tests/expect/cpp/context/objectpath.cpp +96 -0
  81. shacl2code-0.0.16/tests/expect/cpp/context/objectpath.hpp +189 -0
  82. shacl2code-0.0.16/tests/expect/cpp/context/objectset.cpp +327 -0
  83. shacl2code-0.0.16/tests/expect/cpp/context/objectset.hpp +247 -0
  84. shacl2code-0.0.16/tests/expect/cpp/context/prop.hpp +254 -0
  85. shacl2code-0.0.16/tests/expect/cpp/context/property.cpp +467 -0
  86. shacl2code-0.0.16/tests/expect/cpp/context/property.hpp +500 -0
  87. shacl2code-0.0.16/tests/expect/cpp/context/propertyvalue.cpp +54 -0
  88. shacl2code-0.0.16/tests/expect/cpp/context/propertyvalue.hpp +1055 -0
  89. shacl2code-0.0.16/tests/expect/cpp/context/ref.hpp +450 -0
  90. shacl2code-0.0.16/tests/expect/cpp/context/refproperty.cpp +38 -0
  91. shacl2code-0.0.16/tests/expect/cpp/context/refproperty.hpp +229 -0
  92. shacl2code-0.0.16/tests/expect/cpp/context/test-context-jsonld.cpp +25250 -0
  93. shacl2code-0.0.16/tests/expect/cpp/context/test-context-jsonld.hpp +329 -0
  94. shacl2code-0.0.16/tests/expect/cpp/context/test-context-validate.cpp +144 -0
  95. shacl2code-0.0.16/tests/expect/cpp/context/test-context.cpp +830 -0
  96. shacl2code-0.0.16/tests/expect/cpp/context/test-context.hpp +1202 -0
  97. shacl2code-0.0.16/tests/expect/cpp/context/test-context.pc +10 -0
  98. shacl2code-0.0.16/tests/expect/cpp/context/type.cpp +41 -0
  99. shacl2code-0.0.16/tests/expect/cpp/context/type.hpp +311 -0
  100. shacl2code-0.0.16/tests/expect/cpp/context/util.cpp +37 -0
  101. shacl2code-0.0.16/tests/expect/cpp/context/util.hpp +56 -0
  102. shacl2code-0.0.16/tests/expect/cpp/context/walk.hpp +105 -0
  103. shacl2code-0.0.16/tests/expect/cpp/nocontext/Doxyfile +2623 -0
  104. shacl2code-0.0.16/tests/expect/cpp/nocontext/Makefile +106 -0
  105. shacl2code-0.0.16/tests/expect/cpp/nocontext/api.hpp +51 -0
  106. shacl2code-0.0.16/tests/expect/cpp/nocontext/datetime.cpp +143 -0
  107. shacl2code-0.0.16/tests/expect/cpp/nocontext/datetime.hpp +125 -0
  108. shacl2code-0.0.16/tests/expect/cpp/nocontext/decode.cpp +45 -0
  109. shacl2code-0.0.16/tests/expect/cpp/nocontext/decode.hpp +319 -0
  110. shacl2code-0.0.16/tests/expect/cpp/nocontext/encode.cpp +95 -0
  111. shacl2code-0.0.16/tests/expect/cpp/nocontext/encode.hpp +362 -0
  112. shacl2code-0.0.16/tests/expect/cpp/nocontext/errorhandler.cpp +54 -0
  113. shacl2code-0.0.16/tests/expect/cpp/nocontext/errorhandler.hpp +161 -0
  114. shacl2code-0.0.16/tests/expect/cpp/nocontext/exceptions.hpp +121 -0
  115. shacl2code-0.0.16/tests/expect/cpp/nocontext/extensible.cpp +201 -0
  116. shacl2code-0.0.16/tests/expect/cpp/nocontext/extensible.hpp +209 -0
  117. shacl2code-0.0.16/tests/expect/cpp/nocontext/link.cpp +37 -0
  118. shacl2code-0.0.16/tests/expect/cpp/nocontext/link.hpp +74 -0
  119. shacl2code-0.0.16/tests/expect/cpp/nocontext/namedindividual.cpp +60 -0
  120. shacl2code-0.0.16/tests/expect/cpp/nocontext/namedindividual.hpp +128 -0
  121. shacl2code-0.0.16/tests/expect/cpp/nocontext/object.cpp +319 -0
  122. shacl2code-0.0.16/tests/expect/cpp/nocontext/object.hpp +360 -0
  123. shacl2code-0.0.16/tests/expect/cpp/nocontext/objectpath.cpp +96 -0
  124. shacl2code-0.0.16/tests/expect/cpp/nocontext/objectpath.hpp +189 -0
  125. shacl2code-0.0.16/tests/expect/cpp/nocontext/objectset.cpp +326 -0
  126. shacl2code-0.0.16/tests/expect/cpp/nocontext/objectset.hpp +247 -0
  127. shacl2code-0.0.16/tests/expect/cpp/nocontext/prop.hpp +254 -0
  128. shacl2code-0.0.16/tests/expect/cpp/nocontext/property.cpp +467 -0
  129. shacl2code-0.0.16/tests/expect/cpp/nocontext/property.hpp +500 -0
  130. shacl2code-0.0.16/tests/expect/cpp/nocontext/propertyvalue.cpp +54 -0
  131. shacl2code-0.0.16/tests/expect/cpp/nocontext/propertyvalue.hpp +1055 -0
  132. shacl2code-0.0.16/tests/expect/cpp/nocontext/ref.hpp +450 -0
  133. shacl2code-0.0.16/tests/expect/cpp/nocontext/refproperty.cpp +38 -0
  134. shacl2code-0.0.16/tests/expect/cpp/nocontext/refproperty.hpp +229 -0
  135. shacl2code-0.0.16/tests/expect/cpp/nocontext/test-jsonld.cpp +25250 -0
  136. shacl2code-0.0.16/tests/expect/cpp/nocontext/test-jsonld.hpp +329 -0
  137. shacl2code-0.0.16/tests/expect/cpp/nocontext/test-validate.cpp +144 -0
  138. shacl2code-0.0.16/tests/expect/cpp/nocontext/test.cpp +815 -0
  139. shacl2code-0.0.16/tests/expect/cpp/nocontext/test.hpp +1076 -0
  140. shacl2code-0.0.16/tests/expect/cpp/nocontext/test.pc +10 -0
  141. shacl2code-0.0.16/tests/expect/cpp/nocontext/type.cpp +41 -0
  142. shacl2code-0.0.16/tests/expect/cpp/nocontext/type.hpp +311 -0
  143. shacl2code-0.0.16/tests/expect/cpp/nocontext/util.cpp +37 -0
  144. shacl2code-0.0.16/tests/expect/cpp/nocontext/util.hpp +56 -0
  145. shacl2code-0.0.16/tests/expect/cpp/nocontext/walk.hpp +105 -0
  146. {shacl2code-0.0.14/tests/expect/jsonschema → shacl2code-0.0.16/tests/expect/jsonschema/context}/test-context.json +62 -0
  147. {shacl2code-0.0.14/tests/expect/jsonschema → shacl2code-0.0.16/tests/expect/jsonschema/nocontext}/test.json +62 -0
  148. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/expect/make_expect.py +7 -7
  149. {shacl2code-0.0.14/tests/expect/python → shacl2code-0.0.16/tests/expect/python/context}/test-context.py +18 -3
  150. {shacl2code-0.0.14/tests/expect/python → shacl2code-0.0.16/tests/expect/python/nocontext}/test.py +18 -3
  151. {shacl2code-0.0.14/tests/expect/raw → shacl2code-0.0.16/tests/expect/raw/context}/test-context.txt +4 -0
  152. {shacl2code-0.0.14/tests/expect/raw → shacl2code-0.0.16/tests/expect/raw/nocontext}/test.txt +2 -0
  153. shacl2code-0.0.16/tests/test_cpp.py +1483 -0
  154. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_jsonschema.py +3 -3
  155. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_model_source.py +2 -2
  156. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_python.py +4 -17
  157. shacl2code-0.0.14/src/shacl2code/version.py +0 -1
  158. {shacl2code-0.0.14 → shacl2code-0.0.16}/.flake8 +0 -0
  159. {shacl2code-0.0.14 → shacl2code-0.0.16}/.github/workflows/coverage-report.yaml +0 -0
  160. {shacl2code-0.0.14 → shacl2code-0.0.16}/.github/workflows/publish.yaml +0 -0
  161. {shacl2code-0.0.14 → shacl2code-0.0.16}/.gitignore +0 -0
  162. {shacl2code-0.0.14 → shacl2code-0.0.16}/LICENSE +0 -0
  163. {shacl2code-0.0.14 → shacl2code-0.0.16}/pyproject.toml +0 -0
  164. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/__init__.py +0 -0
  165. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/__main__.py +0 -0
  166. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/context.py +0 -0
  167. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/jinja.py +0 -0
  168. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/jsonschema.py +0 -0
  169. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/lang.py +0 -0
  170. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/python.py +0 -0
  171. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/lang/templates/jsonschema.j2 +0 -0
  172. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/main.py +0 -0
  173. {shacl2code-0.0.14 → shacl2code-0.0.16}/src/shacl2code/urlcontext.py +0 -0
  174. {shacl2code-0.0.14 → shacl2code-0.0.16}/testfixtures/httpserver.py +0 -0
  175. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/abort.j2 +0 -0
  176. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/bad-id.j2 +0 -0
  177. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/bad-node-kind.ttl +0 -0
  178. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/bad-pattern-class.ttl +0 -0
  179. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/bad-pattern-integer.ttl +0 -0
  180. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/bad-reference.jsonld +0 -0
  181. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/context-url.j2 +0 -0
  182. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/context.j2 +0 -0
  183. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/missing-range.ttl +0 -0
  184. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/python/bad-object-type-inline.json +0 -0
  185. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/python/bad-object-type-ref-after.json +0 -0
  186. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/python/bad-object-type-ref-before.json +0 -0
  187. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/python/links.json +0 -0
  188. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/data/raw.j2 +0 -0
  189. {shacl2code-0.0.14/tests/data/python → shacl2code-0.0.16/tests/data}/roundtrip.json +0 -0
  190. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_cli.py +0 -0
  191. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_common_jinja.py +0 -0
  192. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_common_prefix.py +0 -0
  193. {shacl2code-0.0.14 → shacl2code-0.0.16}/tests/test_context.py +0 -0
@@ -25,6 +25,9 @@ jobs:
25
25
  uses: actions/setup-python@v4
26
26
  with:
27
27
  python-version: "3.11"
28
+ - name: Install dependencies
29
+ run: |
30
+ sudo apt install -y build-essential doxygen graphviz
28
31
  - name: Install package
29
32
  run: |
30
33
  pip install -e .[dev]
@@ -31,6 +31,7 @@ jobs:
31
31
  python -m pip install --upgrade pip
32
32
  pip install build
33
33
  npm install -g jsonld-cli
34
+ sudo apt install -y build-essential doxygen graphviz
34
35
  - name: Build package
35
36
  run: |
36
37
  python -m build
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: shacl2code
3
- Version: 0.0.14
3
+ Version: 0.0.16
4
4
  Summary: Convert SHACL model file to code bindings
5
5
  Project-URL: Homepage, https://github.com/JPEWdev/shacl2code
6
6
  Project-URL: Repository, https://github.com/JPEWdev/shacl2code.git
7
7
  Project-URL: Issues, https://github.com/JPEWdev/shacl2code/issues
8
8
  Author-email: Joshua Watt <JPEWhacker@gmail.com>
9
- License-File: LICENSE
10
9
  Classifier: Development Status :: 4 - Beta
11
10
  Classifier: Intended Audience :: Developers
12
11
  Classifier: License :: OSI Approved :: MIT License
@@ -183,7 +182,36 @@ from an extensible type.
183
182
  By default, classes generated by `shacl2code` are all instantiable (i.e. they
184
183
  can be created). In some instances, it may be desirable to declare a class as
185
184
  abstract (meaning that it cannot be instantiated, but non-abstract derived
186
- classes can). This can be done with the boolean `isAbstract` property. For
185
+ classes can). There are several ways of marking a class as abstract listed
186
+ below, in order of preference (with the most preferred being first).
187
+
188
+ #### SHACL Validated Abstract Classes
189
+
190
+ A class can be prevented from being directly instantiated using SHACL by adding
191
+ a constraint on the shape that it cannot be of its own type. This can be done
192
+ with the following turtle:
193
+
194
+ ```ttl
195
+
196
+ <MyClass> a owl:Class, sh:NodeShape ;
197
+ # SHACL to prevent a class from being instansiated as this exact type
198
+ sh:property [
199
+ sh:path rdf:type ;
200
+ sh:not [ sh:hasValue <MyClass> ]
201
+ ] .
202
+
203
+ ```
204
+
205
+ `shacl2code` will detect this pattern and generate abstract bindings for
206
+ `MyClass`.
207
+
208
+ This method is most preferred, since it is enforced by SHACL and not just
209
+ `shacl2code` bindings
210
+
211
+ #### shacl2code Annotation
212
+
213
+ `shacl2code` has a custom annotation that can be used to mark a class as
214
+ abstract. This can be done with the boolean `isAbstract` property. For
187
215
  example, the following turtle will declare a class as abstract:
188
216
 
189
217
  ```ttl
@@ -196,9 +224,10 @@ example, the following turtle will declare a class as abstract:
196
224
  The `isAbstract` property is _not_ inherited by derived classes, so any derived
197
225
  classes are automatically concrete unless they indicate otherwise.
198
226
 
199
- Note that for compatibility reasons, it is also possible to define a class as
200
- abstract by declaring it to be of type: `http://spdx.invalid./AbstractClass`,
201
- but this is not preferred.
227
+ #### SPDX Abstract Class Parent
228
+
229
+ It is also possible to define a class as abstract by declaring it to be of
230
+ type: `http://spdx.invalid./AbstractClass`, but this is not preferred.
202
231
 
203
232
  [pytest]: https://www.pytest.org
204
233
  [pytest-cov]: https://pytest-cov.readthedocs.io/en/latest/
@@ -153,7 +153,36 @@ from an extensible type.
153
153
  By default, classes generated by `shacl2code` are all instantiable (i.e. they
154
154
  can be created). In some instances, it may be desirable to declare a class as
155
155
  abstract (meaning that it cannot be instantiated, but non-abstract derived
156
- classes can). This can be done with the boolean `isAbstract` property. For
156
+ classes can). There are several ways of marking a class as abstract listed
157
+ below, in order of preference (with the most preferred being first).
158
+
159
+ #### SHACL Validated Abstract Classes
160
+
161
+ A class can be prevented from being directly instantiated using SHACL by adding
162
+ a constraint on the shape that it cannot be of its own type. This can be done
163
+ with the following turtle:
164
+
165
+ ```ttl
166
+
167
+ <MyClass> a owl:Class, sh:NodeShape ;
168
+ # SHACL to prevent a class from being instansiated as this exact type
169
+ sh:property [
170
+ sh:path rdf:type ;
171
+ sh:not [ sh:hasValue <MyClass> ]
172
+ ] .
173
+
174
+ ```
175
+
176
+ `shacl2code` will detect this pattern and generate abstract bindings for
177
+ `MyClass`.
178
+
179
+ This method is most preferred, since it is enforced by SHACL and not just
180
+ `shacl2code` bindings
181
+
182
+ #### shacl2code Annotation
183
+
184
+ `shacl2code` has a custom annotation that can be used to mark a class as
185
+ abstract. This can be done with the boolean `isAbstract` property. For
157
186
  example, the following turtle will declare a class as abstract:
158
187
 
159
188
  ```ttl
@@ -166,9 +195,10 @@ example, the following turtle will declare a class as abstract:
166
195
  The `isAbstract` property is _not_ inherited by derived classes, so any derived
167
196
  classes are automatically concrete unless they indicate otherwise.
168
197
 
169
- Note that for compatibility reasons, it is also possible to define a class as
170
- abstract by declaring it to be of type: `http://spdx.invalid./AbstractClass`,
171
- but this is not preferred.
198
+ #### SPDX Abstract Class Parent
199
+
200
+ It is also possible to define a class as abstract by declaring it to be of
201
+ type: `http://spdx.invalid./AbstractClass`, but this is not preferred.
172
202
 
173
203
  [pytest]: https://www.pytest.org
174
204
  [pytest-cov]: https://pytest-cov.readthedocs.io/en/latest/
@@ -6,6 +6,7 @@
6
6
  from .lang import LANGUAGES # noqa: F401
7
7
 
8
8
  # All renderers must be imported here to be registered
9
+ from .cpp import CppRender # noqa: F401
9
10
  from .jinja import JinjaRender # noqa: F401
10
- from .python import PythonRender # noqa: F401
11
11
  from .jsonschema import JsonSchemaRender # noqa: F401
12
+ from .python import PythonRender # noqa: F401
@@ -7,9 +7,12 @@ import sys
7
7
  import os
8
8
  from pathlib import Path
9
9
  from contextlib import contextmanager
10
+ import jinja2
10
11
  from jinja2 import Environment, FileSystemLoader, TemplateRuntimeError
12
+ from markupsafe import Markup
11
13
  from rdflib.namespace import SH
12
14
  from ..model import SHACL2CODE
15
+ from ..version import VERSION
13
16
 
14
17
  THIS_DIR = Path(__file__).parent
15
18
 
@@ -19,7 +22,7 @@ class OutputFile(object):
19
22
  self.path = path
20
23
 
21
24
  @contextmanager
22
- def open(self):
25
+ def open(self, mode):
23
26
  if self.path == "-":
24
27
  yield sys.stdout
25
28
  else:
@@ -27,34 +30,15 @@ class OutputFile(object):
27
30
  yield f
28
31
 
29
32
 
30
- class BasicJinjaRender(object):
31
- """
32
- Common Jinja Template Renderer
33
-
34
- Renderers that only use a single Jinja file can derive from this class. For
35
- example:
36
-
37
- @language("my-lang")
38
- class MyRendered(BasicJinjaRenderer):
39
- HELP = "Generates my-lang bindings"
33
+ @jinja2.pass_context
34
+ def include_file(ctx, name):
35
+ env = ctx.environment
36
+ return Markup(env.loader.get_source(env, name)[0])
40
37
 
41
- def __init__(self, args):
42
- super().__init__(args, PATH / TO / TEMPLATE)
43
- """
44
-
45
- def __init__(self, args, template):
46
- self.__output = args.output
47
- self.__template = template
48
38
 
49
- @classmethod
50
- def get_arguments(cls, parser):
51
- parser.add_argument(
52
- "--output",
53
- "-o",
54
- type=OutputFile,
55
- help="Output file or '-' for stdout",
56
- required=True,
57
- )
39
+ class JinjaTemplateRender(object):
40
+ def __init__(self):
41
+ pass
58
42
 
59
43
  def get_additional_render_args(self):
60
44
  return {}
@@ -72,6 +56,7 @@ class BasicJinjaRender(object):
72
56
  env.globals["abort"] = abort_helper
73
57
  env.globals["SHACL2CODE"] = SHACL2CODE
74
58
  env.globals["SH"] = SH
59
+ env.globals["SHACL2CODE_VERSION"] = VERSION
75
60
  template = env.get_template(template.name)
76
61
 
77
62
  render = template.render(
@@ -141,13 +126,49 @@ class BasicJinjaRender(object):
141
126
  env = {
142
127
  "get_all_derived": get_all_derived,
143
128
  "get_all_named_individuals": get_all_named_individuals,
129
+ "include_file": include_file,
144
130
  **self.get_extra_env(),
145
131
  }
146
132
 
147
- with self.__output.open() as f:
148
- self.render(
149
- self.__template,
150
- f,
151
- extra_env=env,
152
- render_args=render_args,
153
- )
133
+ for output, template, args in self.get_outputs():
134
+ with output.open("w") as f:
135
+ self.render(
136
+ template,
137
+ f,
138
+ extra_env=env,
139
+ render_args={**render_args, **args},
140
+ )
141
+
142
+
143
+ class BasicJinjaRender(JinjaTemplateRender):
144
+ """
145
+ Common Jinja Template Renderer
146
+
147
+ Renderers that only use a single Jinja file can derive from this class. For
148
+ example:
149
+
150
+ @language("my-lang")
151
+ class MyRendered(BasicJinjaRenderer):
152
+ HELP = "Generates my-lang bindings"
153
+
154
+ def __init__(self, args):
155
+ super().__init__(args, PATH / TO / TEMPLATE)
156
+ """
157
+
158
+ def __init__(self, args, template):
159
+ super().__init__()
160
+ self.__output = args.output
161
+ self.__template = template
162
+
163
+ @classmethod
164
+ def get_arguments(cls, parser):
165
+ parser.add_argument(
166
+ "--output",
167
+ "-o",
168
+ type=OutputFile,
169
+ help="Output file or '-' for stdout",
170
+ required=True,
171
+ )
172
+
173
+ def get_outputs(self):
174
+ yield self.__output, self.__template, {}
@@ -0,0 +1,224 @@
1
+ #
2
+ # Copyright (c) 2024 Joshua Watt
3
+ #
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ from .common import JinjaTemplateRender
7
+ from .lang import language, TEMPLATE_DIR
8
+ from ..version import VERSION
9
+
10
+ import re
11
+ import textwrap
12
+ from pathlib import Path
13
+
14
+
15
+ def varname(*name):
16
+ name = "_".join(name)
17
+ # Any invalid characters at the beginning of the name are removed (except
18
+ # "@")
19
+ name = re.sub(r"^[^a-zA-Z0-9_@]*", "", name)
20
+ # Any other invalid characters are replaced with "_" (including "@")
21
+ name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
22
+ # Consolidate runs of "_" to a single one
23
+ name = re.sub(r"__+", "_", name)
24
+ return name
25
+
26
+
27
+ def parent_cpp_classes(cls, classes):
28
+ if cls.parent_ids:
29
+ parents = [varname(*classes.get(i).clsname) for i in cls.parent_ids]
30
+ else:
31
+ parents = ["SHACLObject"]
32
+
33
+ if cls.is_extensible:
34
+ parents = [f"SHACLExtensibleObject<{p}>" for p in parents]
35
+
36
+ return parents
37
+
38
+
39
+ def prop_is_list(prop):
40
+ return prop.max_count is None or prop.max_count != 1
41
+
42
+
43
+ def id_str(s):
44
+ return re.sub(r"[^a-zA-Z0-9_]", "_", s)
45
+
46
+
47
+ def comment_wrap(s):
48
+ return "\n".join(["*/", s, "/*"])
49
+
50
+
51
+ @language("cpp")
52
+ class CppRender(JinjaTemplateRender):
53
+ HELP = "C++ Language Bindings"
54
+
55
+ SOURCES = (
56
+ "datetime.cpp",
57
+ "decode.cpp",
58
+ "encode.cpp",
59
+ "errorhandler.cpp",
60
+ "extensible.cpp",
61
+ "link.cpp",
62
+ "namedindividual.cpp",
63
+ "object.cpp",
64
+ "objectpath.cpp",
65
+ "objectset.cpp",
66
+ "property.cpp",
67
+ "propertyvalue.cpp",
68
+ "refproperty.cpp",
69
+ "type.cpp",
70
+ "util.cpp",
71
+ )
72
+
73
+ HEADERS = (
74
+ "api.hpp",
75
+ "datetime.hpp",
76
+ "decode.hpp",
77
+ "encode.hpp",
78
+ "errorhandler.hpp",
79
+ "exceptions.hpp",
80
+ "extensible.hpp",
81
+ "link.hpp",
82
+ "namedindividual.hpp",
83
+ "object.hpp",
84
+ "objectpath.hpp",
85
+ "objectset.hpp",
86
+ "prop.hpp",
87
+ "property.hpp",
88
+ "propertyvalue.hpp",
89
+ "ref.hpp",
90
+ "refproperty.hpp",
91
+ "type.hpp",
92
+ "util.hpp",
93
+ "walk.hpp",
94
+ )
95
+
96
+ def __init__(self, args):
97
+ super().__init__()
98
+ self.basename = args.basename
99
+ self.namespace = args.namespace or id_str(args.basename.name)
100
+ self.lib_version = args.version
101
+ self.description = (
102
+ args.description or f"shacl2code generated binding {args.basename.name}"
103
+ )
104
+ self.macro_prefix = id_str("SHACL2CODE_" + self.basename.name).upper()
105
+
106
+ @classmethod
107
+ def get_arguments(cls, parser):
108
+ parser.add_argument(
109
+ "--output",
110
+ "-o",
111
+ type=Path,
112
+ help="Output file basename",
113
+ dest="basename",
114
+ required=True,
115
+ )
116
+
117
+ parser.add_argument(
118
+ "--namespace",
119
+ "-n",
120
+ help="Output namespace. If unspecified, defaults to output basename",
121
+ )
122
+
123
+ parser.add_argument(
124
+ "--version",
125
+ metavar="MAJOR[.MINOR[.MICRO]]",
126
+ default=VERSION,
127
+ help="Library version",
128
+ )
129
+
130
+ parser.add_argument(
131
+ "--description",
132
+ help="Library description",
133
+ )
134
+
135
+ def get_outputs(self):
136
+ def suffix(s):
137
+ return self.basename.parent / (self.basename.name + s)
138
+
139
+ t = TEMPLATE_DIR / "cpp"
140
+
141
+ for s in self.SOURCES:
142
+ yield self.basename.parent / s, t / (s + ".j2"), {}
143
+
144
+ for s in self.HEADERS:
145
+ guard = f"_{self.macro_prefix}_{id_str(s).upper()}"
146
+ yield self.basename.parent / s, t / (s + ".j2"), {
147
+ "guard_begin": comment_wrap(
148
+ textwrap.dedent(
149
+ f"""\
150
+ #ifndef {guard}
151
+ #define {guard}
152
+ """
153
+ )
154
+ ),
155
+ "guard_end": comment_wrap(f"#endif // {guard}"),
156
+ }
157
+
158
+ yield suffix(".cpp"), t / "source.j2", {}
159
+ yield suffix(".hpp"), t / "header.j2", {
160
+ "headers": self.HEADERS,
161
+ }
162
+ yield suffix("-jsonld.cpp"), t / "jsonld-source.j2", {}
163
+ yield suffix("-jsonld.hpp"), t / "jsonld-header.j2", {}
164
+
165
+ yield self.basename.parent / "Makefile", t / "Makefile.j2", {
166
+ "lib_obj_files": " ".join(
167
+ s.replace(".cpp", ".o")
168
+ for s in self.SOURCES
169
+ + (
170
+ f"{self.basename.name}.cpp",
171
+ f"{self.basename.name}-jsonld.cpp",
172
+ )
173
+ ),
174
+ "headers": self.HEADERS
175
+ + (
176
+ f"{self.basename.name}.hpp",
177
+ f"{self.basename.name}-jsonld.hpp",
178
+ ),
179
+ }
180
+
181
+ yield suffix("-validate.cpp"), t / "validate.j2", {}
182
+ yield suffix(".pc"), t / "pkgconfig.pc.j2", {}
183
+ yield self.basename.parent / "Doxyfile", t / "Doxyfile.j2", {}
184
+
185
+ def get_extra_env(self):
186
+ return {
187
+ "varname": varname,
188
+ "prop_is_list": prop_is_list,
189
+ "parent_cpp_classes": parent_cpp_classes,
190
+ "macro_prefix": self.macro_prefix,
191
+ "api_def_begin": comment_wrap(
192
+ textwrap.dedent(
193
+ f"""\
194
+ #ifndef DOXYGEN_SKIP
195
+ #include "api.hpp"
196
+ // These are so that we don't have to use Jinja templates below since that messes up the formatting
197
+ #define EXPORT {self.macro_prefix}_API
198
+ #define LOCAL {self.macro_prefix}_LOCAL
199
+ #endif // DOXYGEN_SKIP
200
+ """
201
+ )
202
+ ),
203
+ "api_def_end": comment_wrap(
204
+ textwrap.dedent(
205
+ """\
206
+ #undef EXPORT
207
+ #undef LOCAL
208
+ """
209
+ )
210
+ ),
211
+ "ns_begin": comment_wrap(
212
+ "\n".join(f"namespace {n} {{" for n in self.namespace.split("::"))
213
+ ),
214
+ "ns_end": comment_wrap("\n".join("}" for n in self.namespace.split("::"))),
215
+ }
216
+
217
+ def get_additional_render_args(self):
218
+ return {
219
+ "basename": self.basename.name,
220
+ "namespace": self.namespace,
221
+ "nsprefix": f"::{self.namespace}" if self.namespace else "",
222
+ "lib_version": self.lib_version,
223
+ "lib_description": self.description,
224
+ }