dsp-tools 0.9.13__py3-none-any.whl → 18.3.0.post13__py3-none-any.whl

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 (348) hide show
  1. dsp_tools/__init__.py +5 -0
  2. dsp_tools/cli/args.py +47 -0
  3. dsp_tools/cli/call_action.py +85 -0
  4. dsp_tools/cli/call_action_files_only.py +101 -0
  5. dsp_tools/cli/call_action_with_network.py +207 -0
  6. dsp_tools/cli/create_parsers.py +479 -0
  7. dsp_tools/cli/entry_point.py +322 -0
  8. dsp_tools/cli/utils.py +87 -0
  9. dsp_tools/clients/CLAUDE.md +420 -0
  10. dsp_tools/clients/authentication_client.py +14 -0
  11. dsp_tools/clients/authentication_client_live.py +66 -0
  12. dsp_tools/clients/connection.py +35 -0
  13. dsp_tools/clients/connection_live.py +233 -0
  14. dsp_tools/clients/fuseki_metrics.py +60 -0
  15. dsp_tools/clients/group_user_clients.py +35 -0
  16. dsp_tools/clients/group_user_clients_live.py +181 -0
  17. dsp_tools/clients/legal_info_client.py +23 -0
  18. dsp_tools/clients/legal_info_client_live.py +132 -0
  19. dsp_tools/clients/list_client.py +49 -0
  20. dsp_tools/clients/list_client_live.py +166 -0
  21. dsp_tools/clients/metadata_client.py +24 -0
  22. dsp_tools/clients/metadata_client_live.py +47 -0
  23. dsp_tools/clients/ontology_clients.py +49 -0
  24. dsp_tools/clients/ontology_create_client_live.py +166 -0
  25. dsp_tools/clients/ontology_get_client_live.py +80 -0
  26. dsp_tools/clients/permissions_client.py +68 -0
  27. dsp_tools/clients/project_client.py +16 -0
  28. dsp_tools/clients/project_client_live.py +66 -0
  29. dsp_tools/commands/create/communicate_problems.py +24 -0
  30. dsp_tools/commands/create/create.py +134 -0
  31. dsp_tools/commands/create/create_on_server/cardinalities.py +111 -0
  32. dsp_tools/commands/create/create_on_server/classes.py +99 -0
  33. dsp_tools/commands/create/create_on_server/complete_ontologies.py +116 -0
  34. dsp_tools/commands/create/create_on_server/default_permissions.py +134 -0
  35. dsp_tools/commands/create/create_on_server/group_users.py +165 -0
  36. dsp_tools/commands/create/create_on_server/lists.py +163 -0
  37. dsp_tools/commands/create/create_on_server/mappers.py +12 -0
  38. dsp_tools/commands/create/create_on_server/onto_utils.py +74 -0
  39. dsp_tools/commands/create/create_on_server/ontology.py +52 -0
  40. dsp_tools/commands/create/create_on_server/project.py +68 -0
  41. dsp_tools/commands/create/create_on_server/properties.py +119 -0
  42. dsp_tools/commands/create/exceptions.py +29 -0
  43. dsp_tools/commands/create/lists_only.py +66 -0
  44. dsp_tools/commands/create/models/create_problems.py +87 -0
  45. dsp_tools/commands/create/models/parsed_ontology.py +88 -0
  46. dsp_tools/commands/create/models/parsed_project.py +81 -0
  47. dsp_tools/commands/create/models/rdf_ontology.py +12 -0
  48. dsp_tools/commands/create/models/server_project_info.py +100 -0
  49. dsp_tools/commands/create/parsing/parse_lists.py +45 -0
  50. dsp_tools/commands/create/parsing/parse_ontology.py +243 -0
  51. dsp_tools/commands/create/parsing/parse_project.py +149 -0
  52. dsp_tools/commands/create/parsing/parsing_utils.py +40 -0
  53. dsp_tools/commands/create/project_validate.py +595 -0
  54. dsp_tools/commands/create/serialisation/ontology.py +119 -0
  55. dsp_tools/commands/create/serialisation/project.py +44 -0
  56. dsp_tools/commands/excel2json/CLAUDE.md +101 -0
  57. dsp_tools/commands/excel2json/json_header.py +321 -0
  58. dsp_tools/commands/excel2json/lists/__init__.py +0 -0
  59. dsp_tools/commands/excel2json/lists/compliance_checks.py +292 -0
  60. dsp_tools/commands/excel2json/lists/make_lists.py +247 -0
  61. dsp_tools/commands/excel2json/lists/models/__init__.py +0 -0
  62. dsp_tools/commands/excel2json/lists/models/deserialise.py +30 -0
  63. dsp_tools/commands/excel2json/lists/models/input_error.py +216 -0
  64. dsp_tools/commands/excel2json/lists/models/serialise.py +57 -0
  65. dsp_tools/commands/excel2json/lists/utils.py +81 -0
  66. dsp_tools/commands/excel2json/models/__init__.py +0 -0
  67. dsp_tools/commands/excel2json/models/input_error.py +416 -0
  68. dsp_tools/commands/excel2json/models/json_header.py +175 -0
  69. dsp_tools/commands/excel2json/models/list_node_name.py +16 -0
  70. dsp_tools/commands/excel2json/models/ontology.py +76 -0
  71. dsp_tools/commands/excel2json/old_lists.py +328 -0
  72. dsp_tools/commands/excel2json/project.py +280 -0
  73. dsp_tools/commands/excel2json/properties.py +370 -0
  74. dsp_tools/commands/excel2json/resources.py +336 -0
  75. dsp_tools/commands/excel2json/utils.py +352 -0
  76. dsp_tools/commands/excel2xml/__init__.py +7 -0
  77. dsp_tools/commands/excel2xml/excel2xml_cli.py +523 -0
  78. dsp_tools/commands/excel2xml/excel2xml_lib.py +1953 -0
  79. dsp_tools/commands/excel2xml/propertyelement.py +47 -0
  80. dsp_tools/commands/get/__init__.py +0 -0
  81. dsp_tools/commands/get/get.py +166 -0
  82. dsp_tools/commands/get/get_permissions.py +257 -0
  83. dsp_tools/commands/get/get_permissions_legacy.py +89 -0
  84. dsp_tools/commands/get/legacy_models/__init__.py +0 -0
  85. dsp_tools/commands/get/legacy_models/context.py +318 -0
  86. dsp_tools/commands/get/legacy_models/group.py +241 -0
  87. dsp_tools/commands/get/legacy_models/helpers.py +47 -0
  88. dsp_tools/commands/get/legacy_models/listnode.py +390 -0
  89. dsp_tools/commands/get/legacy_models/model.py +12 -0
  90. dsp_tools/commands/get/legacy_models/ontology.py +324 -0
  91. dsp_tools/commands/get/legacy_models/project.py +366 -0
  92. dsp_tools/commands/get/legacy_models/propertyclass.py +417 -0
  93. dsp_tools/commands/get/legacy_models/resourceclass.py +676 -0
  94. dsp_tools/commands/get/legacy_models/user.py +438 -0
  95. dsp_tools/commands/get/models/__init__.py +0 -0
  96. dsp_tools/commands/get/models/permissions_models.py +10 -0
  97. dsp_tools/commands/id2iri.py +258 -0
  98. dsp_tools/commands/ingest_xmlupload/__init__.py +0 -0
  99. dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +178 -0
  100. dsp_tools/commands/ingest_xmlupload/create_resources/__init__.py +0 -0
  101. dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +69 -0
  102. dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +166 -0
  103. dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +121 -0
  104. dsp_tools/commands/ingest_xmlupload/ingest_files/__init__.py +0 -0
  105. dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +64 -0
  106. dsp_tools/commands/ingest_xmlupload/upload_files/__init__.py +0 -0
  107. dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +20 -0
  108. dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +57 -0
  109. dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +66 -0
  110. dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +67 -0
  111. dsp_tools/commands/resume_xmlupload/__init__.py +0 -0
  112. dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +96 -0
  113. dsp_tools/commands/start_stack.py +428 -0
  114. dsp_tools/commands/update_legal/CLAUDE.md +344 -0
  115. dsp_tools/commands/update_legal/__init__.py +0 -0
  116. dsp_tools/commands/update_legal/core.py +182 -0
  117. dsp_tools/commands/update_legal/csv_operations.py +135 -0
  118. dsp_tools/commands/update_legal/models.py +87 -0
  119. dsp_tools/commands/update_legal/xml_operations.py +247 -0
  120. dsp_tools/commands/validate_data/CLAUDE.md +159 -0
  121. dsp_tools/commands/validate_data/__init__.py +0 -0
  122. dsp_tools/commands/validate_data/constants.py +59 -0
  123. dsp_tools/commands/validate_data/mappers.py +143 -0
  124. dsp_tools/commands/validate_data/models/__init__.py +0 -0
  125. dsp_tools/commands/validate_data/models/api_responses.py +45 -0
  126. dsp_tools/commands/validate_data/models/input_problems.py +119 -0
  127. dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
  128. dsp_tools/commands/validate_data/models/validation.py +106 -0
  129. dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
  130. dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
  131. dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
  132. dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
  133. dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
  134. dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
  135. dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
  136. dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
  137. dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
  138. dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
  139. dsp_tools/commands/validate_data/sparql/cardinality_shacl.py +209 -0
  140. dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
  141. dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
  142. dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
  143. dsp_tools/commands/validate_data/utils.py +59 -0
  144. dsp_tools/commands/validate_data/validate_data.py +283 -0
  145. dsp_tools/commands/validate_data/validation/__init__.py +0 -0
  146. dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
  147. dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
  148. dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
  149. dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
  150. dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
  151. dsp_tools/commands/xmlupload/__init__.py +0 -0
  152. dsp_tools/commands/xmlupload/iri_resolver.py +21 -0
  153. dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
  154. dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
  155. dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
  156. dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
  157. dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
  158. dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
  159. dsp_tools/commands/xmlupload/models/__init__.py +0 -0
  160. dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
  161. dsp_tools/commands/xmlupload/models/formatted_text_value.py +10 -0
  162. dsp_tools/commands/xmlupload/models/ingest.py +143 -0
  163. dsp_tools/commands/xmlupload/models/input_problems.py +58 -0
  164. dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
  165. dsp_tools/commands/xmlupload/models/permission.py +45 -0
  166. dsp_tools/commands/xmlupload/models/permissions_parsed.py +93 -0
  167. dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
  168. dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
  169. dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
  170. dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
  171. dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
  172. dsp_tools/commands/xmlupload/models/upload_clients.py +14 -0
  173. dsp_tools/commands/xmlupload/models/upload_state.py +20 -0
  174. dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
  175. dsp_tools/commands/xmlupload/prepare_xml_input/ark2iri.py +55 -0
  176. dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
  177. dsp_tools/commands/xmlupload/prepare_xml_input/iiif_uri_validator.py +50 -0
  178. dsp_tools/commands/xmlupload/prepare_xml_input/list_client.py +120 -0
  179. dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
  180. dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
  181. dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
  182. dsp_tools/commands/xmlupload/resource_create_client.py +25 -0
  183. dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
  184. dsp_tools/commands/xmlupload/stash/__init__.py +0 -0
  185. dsp_tools/commands/xmlupload/stash/analyse_circular_reference_graph.py +236 -0
  186. dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
  187. dsp_tools/commands/xmlupload/stash/graph_models.py +87 -0
  188. dsp_tools/commands/xmlupload/stash/stash_circular_references.py +68 -0
  189. dsp_tools/commands/xmlupload/stash/stash_models.py +109 -0
  190. dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +106 -0
  191. dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +196 -0
  192. dsp_tools/commands/xmlupload/upload_config.py +76 -0
  193. dsp_tools/commands/xmlupload/write_diagnostic_info.py +27 -0
  194. dsp_tools/commands/xmlupload/xmlupload.py +516 -0
  195. dsp_tools/config/__init__.py +0 -0
  196. dsp_tools/config/logger_config.py +69 -0
  197. dsp_tools/config/warnings_config.py +32 -0
  198. dsp_tools/error/__init__.py +0 -0
  199. dsp_tools/error/custom_warnings.py +39 -0
  200. dsp_tools/error/exceptions.py +204 -0
  201. dsp_tools/error/problems.py +10 -0
  202. dsp_tools/error/xmllib_errors.py +20 -0
  203. dsp_tools/error/xmllib_warnings.py +54 -0
  204. dsp_tools/error/xmllib_warnings_util.py +159 -0
  205. dsp_tools/error/xsd_validation_error_msg.py +19 -0
  206. dsp_tools/legacy_models/__init__.py +0 -0
  207. dsp_tools/legacy_models/datetimestamp.py +81 -0
  208. dsp_tools/legacy_models/langstring.py +253 -0
  209. dsp_tools/legacy_models/projectContext.py +49 -0
  210. dsp_tools/py.typed +0 -0
  211. dsp_tools/resources/schema/data.xsd +648 -0
  212. dsp_tools/resources/schema/lists-only.json +72 -0
  213. dsp_tools/resources/schema/project.json +1258 -0
  214. dsp_tools/resources/schema/properties-only.json +874 -0
  215. dsp_tools/resources/schema/resources-only.json +140 -0
  216. dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
  217. dsp_tools/resources/start-stack/docker-compose.override.yml +11 -0
  218. dsp_tools/resources/start-stack/docker-compose.yml +88 -0
  219. dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
  220. dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
  221. dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
  222. dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
  223. dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
  224. dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
  225. dsp_tools/utils/__init__.py +0 -0
  226. dsp_tools/utils/ansi_colors.py +32 -0
  227. dsp_tools/utils/data_formats/__init__.py +0 -0
  228. dsp_tools/utils/data_formats/date_util.py +166 -0
  229. dsp_tools/utils/data_formats/iri_util.py +30 -0
  230. dsp_tools/utils/data_formats/shared.py +81 -0
  231. dsp_tools/utils/data_formats/uri_util.py +76 -0
  232. dsp_tools/utils/fuseki_bloating.py +63 -0
  233. dsp_tools/utils/json_parsing.py +22 -0
  234. dsp_tools/utils/rdf_constants.py +42 -0
  235. dsp_tools/utils/rdflib_utils.py +10 -0
  236. dsp_tools/utils/replace_id_with_iri.py +66 -0
  237. dsp_tools/utils/request_utils.py +238 -0
  238. dsp_tools/utils/xml_parsing/__init__.py +0 -0
  239. dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
  240. dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
  241. dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
  242. dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
  243. dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
  244. dsp_tools/xmllib/CLAUDE.md +302 -0
  245. dsp_tools/xmllib/__init__.py +49 -0
  246. dsp_tools/xmllib/general_functions.py +877 -0
  247. dsp_tools/xmllib/internal/__init__.py +0 -0
  248. dsp_tools/xmllib/internal/checkers.py +162 -0
  249. dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
  250. dsp_tools/xmllib/internal/constants.py +46 -0
  251. dsp_tools/xmllib/internal/input_converters.py +155 -0
  252. dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
  253. dsp_tools/xmllib/internal/serialise_resource.py +177 -0
  254. dsp_tools/xmllib/internal/serialise_values.py +152 -0
  255. dsp_tools/xmllib/internal/type_aliases.py +11 -0
  256. dsp_tools/xmllib/models/__init__.py +0 -0
  257. dsp_tools/xmllib/models/config_options.py +28 -0
  258. dsp_tools/xmllib/models/date_formats.py +48 -0
  259. dsp_tools/xmllib/models/dsp_base_resources.py +1542 -0
  260. dsp_tools/xmllib/models/internal/__init__.py +0 -0
  261. dsp_tools/xmllib/models/internal/file_values.py +172 -0
  262. dsp_tools/xmllib/models/internal/geometry.py +162 -0
  263. dsp_tools/xmllib/models/internal/migration_metadata.py +55 -0
  264. dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
  265. dsp_tools/xmllib/models/internal/values.py +342 -0
  266. dsp_tools/xmllib/models/licenses/__init__.py +0 -0
  267. dsp_tools/xmllib/models/licenses/other.py +59 -0
  268. dsp_tools/xmllib/models/licenses/recommended.py +107 -0
  269. dsp_tools/xmllib/models/permissions.py +41 -0
  270. dsp_tools/xmllib/models/res.py +1782 -0
  271. dsp_tools/xmllib/models/root.py +348 -0
  272. dsp_tools/xmllib/value_checkers.py +434 -0
  273. dsp_tools/xmllib/value_converters.py +777 -0
  274. dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
  275. dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
  276. dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
  277. dsp_tools-18.3.0.post13.dist-info/entry_points.txt +3 -0
  278. dsp_tools-0.9.13.dist-info/LICENSE +0 -674
  279. dsp_tools-0.9.13.dist-info/METADATA +0 -144
  280. dsp_tools-0.9.13.dist-info/RECORD +0 -71
  281. dsp_tools-0.9.13.dist-info/WHEEL +0 -5
  282. dsp_tools-0.9.13.dist-info/entry_points.txt +0 -3
  283. dsp_tools-0.9.13.dist-info/top_level.txt +0 -1
  284. dsplib/models/connection.py +0 -272
  285. dsplib/models/group.py +0 -296
  286. dsplib/models/helpers.py +0 -505
  287. dsplib/models/langstring.py +0 -277
  288. dsplib/models/listnode.py +0 -578
  289. dsplib/models/model.py +0 -20
  290. dsplib/models/ontology.py +0 -448
  291. dsplib/models/permission.py +0 -112
  292. dsplib/models/project.py +0 -547
  293. dsplib/models/propertyclass.py +0 -505
  294. dsplib/models/resource.py +0 -366
  295. dsplib/models/resourceclass.py +0 -810
  296. dsplib/models/sipi.py +0 -30
  297. dsplib/models/user.py +0 -731
  298. dsplib/models/value.py +0 -1000
  299. dsplib/utils/knora-data-schema.xsd +0 -454
  300. dsplib/utils/knora-schema-lists.json +0 -83
  301. dsplib/utils/knora-schema.json +0 -434
  302. dsplib/utils/onto_commons.py +0 -24
  303. dsplib/utils/onto_create_lists.py +0 -73
  304. dsplib/utils/onto_create_ontology.py +0 -442
  305. dsplib/utils/onto_get.py +0 -58
  306. dsplib/utils/onto_validate.py +0 -33
  307. dsplib/utils/xml_upload.py +0 -539
  308. dsplib/widgets/doublepassword.py +0 -80
  309. knora/MLS-import-libraries.py +0 -84
  310. knora/dsp_tools.py +0 -96
  311. knora/dsplib/models/connection.py +0 -272
  312. knora/dsplib/models/group.py +0 -296
  313. knora/dsplib/models/helpers.py +0 -506
  314. knora/dsplib/models/langstring.py +0 -277
  315. knora/dsplib/models/listnode.py +0 -578
  316. knora/dsplib/models/model.py +0 -20
  317. knora/dsplib/models/ontology.py +0 -448
  318. knora/dsplib/models/permission.py +0 -112
  319. knora/dsplib/models/project.py +0 -583
  320. knora/dsplib/models/propertyclass.py +0 -505
  321. knora/dsplib/models/resource.py +0 -416
  322. knora/dsplib/models/resourceclass.py +0 -811
  323. knora/dsplib/models/sipi.py +0 -35
  324. knora/dsplib/models/user.py +0 -731
  325. knora/dsplib/models/value.py +0 -1000
  326. knora/dsplib/utils/knora-data-schema.xsd +0 -464
  327. knora/dsplib/utils/knora-schema-lists.json +0 -83
  328. knora/dsplib/utils/knora-schema.json +0 -444
  329. knora/dsplib/utils/onto_commons.py +0 -24
  330. knora/dsplib/utils/onto_create_lists.py +0 -73
  331. knora/dsplib/utils/onto_create_ontology.py +0 -451
  332. knora/dsplib/utils/onto_get.py +0 -58
  333. knora/dsplib/utils/onto_validate.py +0 -33
  334. knora/dsplib/utils/xml_upload.py +0 -540
  335. knora/dsplib/widgets/doublepassword.py +0 -80
  336. knora/knora.py +0 -2108
  337. knora/test.py +0 -99
  338. knora/testit.py +0 -76
  339. knora/xml2knora.py +0 -633
  340. {dsplib → dsp_tools/cli}/__init__.py +0 -0
  341. {dsplib/models → dsp_tools/clients}/__init__.py +0 -0
  342. {dsplib/utils → dsp_tools/commands}/__init__.py +0 -0
  343. {dsplib/widgets → dsp_tools/commands/create}/__init__.py +0 -0
  344. {knora → dsp_tools/commands/create/create_on_server}/__init__.py +0 -0
  345. {knora/dsplib → dsp_tools/commands/create/models}/__init__.py +0 -0
  346. {knora/dsplib/models → dsp_tools/commands/create/parsing}/__init__.py +0 -0
  347. {knora/dsplib/utils → dsp_tools/commands/create/serialisation}/__init__.py +0 -0
  348. {knora/dsplib/widgets → dsp_tools/commands/excel2json}/__init__.py +0 -0
@@ -0,0 +1,4 @@
1
+ ---
2
+ # Take the latest release from:
3
+ # https://github.com/dasch-swiss/shacl-cli/releases
4
+ image: "daschswiss/shacl-cli:v0.0.5"
@@ -0,0 +1,99 @@
1
+ @prefix sh: <http://www.w3.org/ns/shacl#> .
2
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
3
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
4
+ @prefix owl: <http://www.w3.org/2002/07/owl#> .
5
+ @prefix knora-api: <http://api.knora.org/ontology/knora-api/v2#> .
6
+
7
+ @prefix api-shapes: <http://api.knora.org/ontology/knora-api/shapes/v2#> .
8
+
9
+
10
+ api-shapes:FindMissingMaxCardinality_Seqnum_OntologyShape
11
+ a sh:NodeShape ;
12
+ sh:targetClass owl:Class ;
13
+ sh:sparql [
14
+ a sh:SPARQLConstraint ;
15
+ sh:select """
16
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
17
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
18
+ PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
19
+
20
+ SELECT $this ?path WHERE {
21
+ $this a owl:Class ;
22
+ rdfs:subClassOf ?restriction .
23
+ ?restriction a owl:Restriction ;
24
+ owl:onProperty ?path .
25
+
26
+ ?path rdfs:subPropertyOf* knora-api:seqnum .
27
+
28
+ FILTER NOT EXISTS {
29
+ ?restriction owl:maxCardinality|owl:cardinality 1
30
+ }
31
+ }
32
+ """ ;
33
+ sh:message "seqnum must either have cardinality 1 or 0-1."
34
+ ] ;
35
+ sh:severity sh:Violation .
36
+
37
+
38
+ api-shapes:FindMissingSeqnum_OntologyShape
39
+ a sh:NodeShape ;
40
+ sh:targetClass owl:Class ;
41
+ sh:sparql [
42
+ a sh:SPARQLConstraint ;
43
+ sh:select """
44
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
45
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
46
+ PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
47
+
48
+ SELECT $this ?path WHERE {
49
+
50
+ $this a owl:Class ;
51
+ rdfs:subClassOf ?restrictionIsPartOf .
52
+ ?restrictionIsPartOf a owl:Restriction ;
53
+ owl:onProperty ?path .
54
+ ?path rdfs:subPropertyOf* knora-api:isPartOf .
55
+
56
+ FILTER NOT EXISTS {
57
+ $this a owl:Class ;
58
+ rdfs:subClassOf ?restrictionSeqnum .
59
+ ?restrictionSeqnum a owl:Restriction ;
60
+ owl:onProperty ?seqnumProp .
61
+ ?seqnumProp rdfs:subPropertyOf* knora-api:seqnum .
62
+ }
63
+ }
64
+ """ ;
65
+ sh:message "A class with a cardinality for isPartOf also requires a cardinality for seqnum."
66
+ ] ;
67
+ sh:severity sh:Violation .
68
+
69
+
70
+ api-shapes:FindMissingIsPartOf_OntologyShape
71
+ a sh:NodeShape ;
72
+ sh:targetClass owl:Class ;
73
+ sh:sparql [
74
+ a sh:SPARQLConstraint ;
75
+ sh:select """
76
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
77
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
78
+ PREFIX knora-api: <http://api.knora.org/ontology/knora-api/v2#>
79
+
80
+ SELECT $this ?path WHERE {
81
+
82
+ $this a owl:Class ;
83
+ rdfs:subClassOf ?restrictionSeqnum .
84
+ ?restrictionSeqnum a owl:Restriction ;
85
+ owl:onProperty ?path .
86
+ ?path rdfs:subPropertyOf* knora-api:seqnum .
87
+
88
+ FILTER NOT EXISTS {
89
+ $this a owl:Class ;
90
+ rdfs:subClassOf ?restrictionIsPartOf .
91
+ ?restrictionIsPartOf a owl:Restriction ;
92
+ owl:onProperty ?isPartOfProp .
93
+ ?isPartOfProp rdfs:subPropertyOf* knora-api:isPartOf .
94
+ }
95
+ }
96
+ """ ;
97
+ sh:message "A class with a cardinality for seqnum also requires a cardinality for isPartOf."
98
+ ] ;
99
+ sh:severity sh:Violation .
File without changes
@@ -0,0 +1,32 @@
1
+ # These are ANSI escape codes which can be used to configure the print output on the terminal
2
+ # http://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html
3
+ # The semicolon separates different configurations
4
+
5
+ # All codes must start with an escape sequence, it may differ in different languages, in Python "\u001b[" works
6
+ SEQUENCE_START = "\u001b["
7
+
8
+ # the "m" at the end signals,
9
+ # that the configuration code is finished and after that the string that should be printed starts
10
+ SEQUENCE_END = "m"
11
+
12
+ # reset to the default setting of the console
13
+ RESET_TO_DEFAULT = f"{SEQUENCE_START}0{SEQUENCE_END}"
14
+
15
+ BOLD = f"{SEQUENCE_START}1{SEQUENCE_END}" # 1 (bold) ; 32 (green)
16
+
17
+ # If you want to change for example both the text color and the background color you can combine the sequences
18
+ # for example: BACKGROUND_BOLD_MAGENTA + YELLOW -> magenta background with yellow text
19
+
20
+ # Colored Text
21
+ BOLD_GREEN = f"{SEQUENCE_START}1;32{SEQUENCE_END}" # 1 (bold) ; 32 (green)
22
+ BOLD_RED = f"{SEQUENCE_START}1;31{SEQUENCE_END}" # 1 (bold) ; 31 (red)
23
+ BOLD_CYAN = f"{SEQUENCE_START}1;36{SEQUENCE_END}" # 1 (bold) ; 36 (cyan)
24
+ BOLD_YELLOW = f"{SEQUENCE_START}1;33{SEQUENCE_END}" # 1 (bold) ; 33 (yellow)
25
+ YELLOW = f"{SEQUENCE_START}0;33{SEQUENCE_END}" # 0 (normal font) ; 33 (yellow)
26
+ RED = f"{SEQUENCE_START}0;31{SEQUENCE_END}" # 0 (normal font) ; 31 (red)
27
+
28
+ # Colored Background
29
+ BACKGROUND_BOLD_RED = f"{SEQUENCE_START}1;41{SEQUENCE_END}" # 1 (bold) ; 41 (background red)
30
+ BACKGROUND_BOLD_YELLOW = f"{SEQUENCE_START}1;43{SEQUENCE_END}" # 1 (bold) ; 43 (background yellow)
31
+ BACKGROUND_BOLD_GREEN = f"{SEQUENCE_START}1;42{SEQUENCE_END}" # 1 (bold) ; 42 (background green)
32
+ BACKGROUND_BOLD_CYAN = f"{SEQUENCE_START}1;46{SEQUENCE_END}" # 1 (bold) ; 46 (background cyan)
File without changes
@@ -0,0 +1,166 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+ from typing import cast
6
+
7
+ import regex
8
+
9
+ from dsp_tools.error.exceptions import BaseError
10
+
11
+ _calendar = r"GREGORIAN|JULIAN|ISLAMIC"
12
+ _era = r"CE|BCE|BC|AD"
13
+ _year = r"\d{1,4}"
14
+ _month = r"\d{1,2}"
15
+ _day = r"\d{1,2}"
16
+ _full_date_pattern = rf"""
17
+ ^
18
+ (?:({_calendar}):)? # optional calendar
19
+ (?:({_era}):)? # optional era
20
+ ({_year}(?:-{_month})?(?:-{_day})?) # date
21
+ (?::({_era}))? # optional era
22
+ (?::({_year}(?:-{_month})?(?:-{_day})?))? # optional date
23
+ $
24
+ """
25
+ _single_date_pattern = rf"^({_year})(?:-({_month}))?(?:-({_day}))?$"
26
+
27
+
28
+ class Calendar(Enum):
29
+ """Enum for calendar types."""
30
+
31
+ GREGORIAN = "GREGORIAN"
32
+ ISLAMIC = "ISLAMIC"
33
+ JULIAN = "JULIAN"
34
+
35
+ @staticmethod
36
+ def from_string(s: str) -> Calendar:
37
+ """Parses a string into a calendar type, potentially failing with a BaseError."""
38
+ match s:
39
+ case "GREGORIAN":
40
+ return Calendar.GREGORIAN
41
+ case "ISLAMIC":
42
+ return Calendar.ISLAMIC
43
+ case "JULIAN":
44
+ return Calendar.JULIAN
45
+ case _:
46
+ raise BaseError(f"Invalid calendar type: {s}")
47
+
48
+
49
+ class Era(Enum):
50
+ """Enum for era types."""
51
+
52
+ AD = "AD"
53
+ BC = "BC"
54
+ BCE = "BCE"
55
+ CE = "CE"
56
+
57
+ @staticmethod
58
+ def from_string(s: str) -> Era:
59
+ """Parses a string into an era type, potentially failing with a BaseError."""
60
+ match s:
61
+ case "AD":
62
+ return Era.AD
63
+ case "BC":
64
+ return Era.BC
65
+ case "BCE":
66
+ return Era.BCE
67
+ case "CE":
68
+ return Era.CE
69
+ case _:
70
+ raise BaseError(f"Invalid era type: {s}")
71
+
72
+
73
+ class DayMonthYearEra(Enum):
74
+ DAY = "Day"
75
+ MONTH = "Month"
76
+ YEAR = "Year"
77
+ ERA = "Era"
78
+
79
+
80
+ class StartEnd(Enum):
81
+ START = "Start"
82
+ END = "End"
83
+
84
+
85
+ @dataclass(frozen=True)
86
+ class SingleDate:
87
+ """Information about a single date."""
88
+
89
+ era: Era | None
90
+ year: int
91
+ month: int | None
92
+ day: int | None
93
+
94
+
95
+ @dataclass(frozen=True)
96
+ class Date:
97
+ """Information about a date."""
98
+
99
+ calendar: Calendar
100
+ start: SingleDate
101
+ end: SingleDate | None
102
+
103
+
104
+ def parse_date_string(s: str) -> Date:
105
+ """Parse a date string into a Date object.
106
+
107
+ Args:
108
+ s: date string
109
+
110
+ Returns:
111
+ Date object
112
+
113
+ Raises:
114
+ BaseError: if the date string cannot be parsed
115
+ """
116
+
117
+ calendar, start_era, start_date, end_era, end_date = _split_date_string(s)
118
+ calendar_enum = Calendar.from_string(calendar or "GREGORIAN")
119
+ if not end_date:
120
+ end_date = start_date
121
+ if calendar_enum != Calendar.ISLAMIC:
122
+ if not start_era:
123
+ start_era = "CE"
124
+ if end_date and not end_era:
125
+ end_era = start_era
126
+ start_era_enum = Era.from_string(start_era) if start_era else None
127
+ end_era_enum = Era.from_string(end_era) if end_era else None
128
+ start = _parse_single_date(start_date, start_era_enum)
129
+ end = _parse_single_date(end_date, end_era_enum) if end_date else None
130
+
131
+ return Date(calendar_enum, start, end)
132
+
133
+
134
+ def is_full_date(s: str) -> bool:
135
+ """
136
+ Check if a string is a full DSP date string of the scheme calendar:epoch:yyyy-mm-dd:epoch:yyyy-mm-dd.
137
+ """
138
+ return bool(regex.search(_full_date_pattern, s, flags=regex.VERBOSE))
139
+
140
+
141
+ def _split_date_string(s: str) -> tuple[str | None, str | None, str, str | None, str | None]:
142
+ date_match = regex.search(_full_date_pattern, s, flags=regex.VERBOSE)
143
+ if not date_match:
144
+ raise BaseError(f"Could not parse date: {s}")
145
+ date_groups = date_match.groups()
146
+ match date_groups:
147
+ case ("ISLAMIC", start_era, _, end_era, _) if start_era or end_era:
148
+ raise BaseError(f"ISLAMIC calendar does not support eras: {s}")
149
+ case (str() | None, str() | None, str(), str() | None, str() | None):
150
+ return cast(tuple[str | None, str | None, str, str | None, str | None], date_groups)
151
+ case _:
152
+ raise BaseError(f"Could not parse date: {s}")
153
+
154
+
155
+ def _parse_single_date(date: str, era: Era | None) -> SingleDate:
156
+ date_match = regex.search(_single_date_pattern, date)
157
+ if not date_match:
158
+ raise BaseError(f"Could not parse date: {date}")
159
+ match date_match.groups():
160
+ case (str() as year, str() | None as month, str() | None as day):
161
+ y = int(year)
162
+ m = int(month) if month else None
163
+ d = int(day) if day else None
164
+ return SingleDate(era, y, m, d)
165
+ case _:
166
+ raise BaseError(f"Could not parse date: {date}")
@@ -0,0 +1,30 @@
1
+ import regex
2
+
3
+ _iri_pattern = r"^(http)s?://[\w\.\-~]*(:\d{,6})?(/[\w\-~]+)*(#[\w\-~]*)?"
4
+ _resource_iri_pattern = r"https?://rdfh.ch/[a-fA-F0-9]{4}/[\w-]{22}"
5
+
6
+
7
+ def is_iri(s: str) -> bool:
8
+ """Checks whether a string is a valid IRI."""
9
+ return regex.fullmatch(_iri_pattern, s) is not None
10
+
11
+
12
+ def is_resource_iri(s: str) -> bool:
13
+ """Checks whether a string is a valid resource IRI."""
14
+ return regex.fullmatch(_resource_iri_pattern, s) is not None
15
+
16
+
17
+ def from_dsp_iri_to_prefixed_iri(iri: str) -> str:
18
+ dsp_iri_re = r".+\/(.+?)\/v2#(.+)$"
19
+ if not (found := regex.search(dsp_iri_re, iri)):
20
+ return iri
21
+ return f"{found.group(1)}:{found.group(2)}"
22
+
23
+
24
+ def make_dsp_ontology_prefix(api_url: str, shortcode: str, onto_name: str) -> str:
25
+ api_fixed = convert_api_url_for_correct_iri_namespace_construction(api_url)
26
+ return f"{api_fixed}/ontology/{shortcode}/{onto_name}/v2#"
27
+
28
+
29
+ def convert_api_url_for_correct_iri_namespace_construction(api_url: str) -> str:
30
+ return regex.sub(r"^https", "http", api_url)
@@ -0,0 +1,81 @@
1
+ from __future__ import annotations
2
+
3
+ import unicodedata
4
+ from typing import Any
5
+ from typing import Optional
6
+ from typing import TypeGuard
7
+
8
+ import pandas as pd
9
+ import regex
10
+
11
+ from dsp_tools.commands.excel2xml.propertyelement import PropertyElement
12
+
13
+
14
+ def simplify_name(value: str) -> str:
15
+ """
16
+ Simplifies a given value in order to use it as node name
17
+
18
+ Args:
19
+ value: The value to be simplified
20
+
21
+ Returns:
22
+ str: The simplified value
23
+ """
24
+ simplified_value = value.lower()
25
+
26
+ # normalize characters (p.ex. ä becomes a)
27
+ simplified_value = unicodedata.normalize("NFKD", simplified_value)
28
+
29
+ # replace forward slash and whitespace with a dash
30
+ simplified_value = regex.sub("[/\\s]+", "-", simplified_value)
31
+
32
+ # delete all characters which are not letters, numbers or dashes
33
+ simplified_value = regex.sub("[^A-Za-z0-9\\-]+", "", simplified_value)
34
+
35
+ return simplified_value
36
+
37
+
38
+ def check_notna(value: Optional[Any]) -> TypeGuard[Any]:
39
+ """
40
+ Check a value if it is usable in the context of data archiving. A value is considered usable if it is
41
+ - a number (integer or float, but not np.nan)
42
+ - a boolean
43
+ - a string with at least one Unicode letter (matching the regex ``\\p{L}``) or number, or at least one _, !, or ?
44
+ (The strings `None`, `<NA>`, `N/A`, and `-` are considered invalid.)
45
+ - a PropertyElement whose "value" fulfills the above criteria
46
+
47
+ Args:
48
+ value: any object encountered when analysing data
49
+
50
+ Returns:
51
+ True if the value is usable, False if it is N/A or otherwise unusable
52
+
53
+ Examples:
54
+ >>> check_notna(0) == True
55
+ >>> check_notna(False) == True
56
+ >>> check_notna("œ") == True
57
+ >>> check_notna("0") == True
58
+ >>> check_notna("_") == True
59
+ >>> check_notna("!") == True
60
+ >>> check_notna("?") == True
61
+ >>> check_notna(None) == False
62
+ >>> check_notna("None") == False
63
+ >>> check_notna(<NA>) == False
64
+ >>> check_notna("<NA>") == False
65
+ >>> check_notna("-") == False
66
+ >>> check_notna(" ") == False
67
+ """
68
+
69
+ if isinstance(value, PropertyElement):
70
+ value = value.value
71
+
72
+ if isinstance(value, bool | int) or (
73
+ isinstance(value, float) and pd.notna(value)
74
+ ): # necessary because isinstance(np.nan, float)
75
+ return True
76
+ elif isinstance(value, str):
77
+ return bool(regex.search(r"[\p{L}\d_!?]", value, flags=regex.UNICODE)) and not bool(
78
+ regex.search(r"^(none|<NA>|-|n/a)$", value, flags=regex.IGNORECASE)
79
+ )
80
+ else:
81
+ return False
@@ -0,0 +1,76 @@
1
+ import regex
2
+
3
+
4
+ def is_prod_like_server(server: str) -> bool:
5
+ return server in [
6
+ "https://api.dasch.swiss",
7
+ "https://api.rdu.dasch.swiss",
8
+ "https://api.ls-prod-server.dasch.swiss",
9
+ "https://api.ls-test-server.dasch.swiss",
10
+ "https://api.stage.dasch.swiss",
11
+ ]
12
+
13
+
14
+ def is_uri(s: str) -> bool:
15
+ """Checks if the given string is a valid URI."""
16
+ # URI = scheme ":" ["//" host [":" port]] path ["?" query] ["#" fragment]
17
+ chars_for_path_query_fragment = r"\w_.\-:~%()!@,;/=*&'+"
18
+ scheme = r"(?<scheme>[a-z][a-z0-9+.\-]*)"
19
+ host = r"(?<host>[\w_.\-:~\[\]]+)"
20
+ port = r"(?<port>:\d{0,6})"
21
+ path = rf"(?<path>/[{chars_for_path_query_fragment}]*)"
22
+ query = rf"(?<query>\?[{chars_for_path_query_fragment}]+)"
23
+ fragment = rf"(?<fragment>#[{chars_for_path_query_fragment}]*)"
24
+ m = regex.match(rf"{scheme}:(//{host}{port}?){path}*{query}*{fragment}?", s, flags=regex.UNICODE)
25
+ return m is not None
26
+
27
+
28
+ def is_iiif_uri(uri: str) -> bool:
29
+ """
30
+ Checks if the given URL is a valid IIIF URL.
31
+ It should support all versions of IIIF servers,
32
+ but was constructed with the syntax described in: https://iiif.io/api/image/3.0/#2-uri-syntax.
33
+ IIIF is open to modifications which are not described in the official documentation
34
+ (see https://iiif.io/api/annex/notes/design_principles/#define-success-not-failure).
35
+
36
+ Args:
37
+ uri: The URI to be checked.
38
+
39
+ Returns:
40
+ True if the URI is a valid IIIF URI, False otherwise.
41
+ """
42
+ # {scheme}://{server}/{prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
43
+ split_uri = uri.lower().split("/")
44
+ try:
45
+ region_seg, size_seg, rotation_seg, quality_format_seg = split_uri[-4:]
46
+ except ValueError:
47
+ return False
48
+ # %5E is the URL encoded version of ^ ->
49
+ # because we do change the uri to lower case we need to change that in the regex
50
+ # (\d+(\.\d+)?) -> number, can be integer or float
51
+ # everything needs to be encapsulated in a group
52
+ # otherwise the ^ and $ only apply respectively to the first and last listed in the alternative options
53
+ region_re = (
54
+ r"^(full|square|" # full | square
55
+ r"((pct:)?(\d+(\.\d+)?,){3}(\d+(\.\d+)?)))$" # x,y,w,h | pct:x,y,w,h
56
+ )
57
+ if not regex.search(region_re, region_seg):
58
+ return False
59
+ size_re = (
60
+ r"^((\^|%5e)?max|" # max | ^max
61
+ r"(\^|%5e)?full|" # full | ^full
62
+ r"(\^|%5e)?pct:\d+(\.\d+)?|" # pct:n | ^pct:n
63
+ r"(\^|%5e)?(\d+(\.\d+)?)+(,|%2c)|" # w, | ^w,
64
+ r"(\^|%5e)?,\d+(\.\d+)?|" # ,h | ^,h
65
+ r"(\^|%5e)?!?\d+(\.\d+)?,\d+(\.\d+)?)$" # w,h | ^w,h | !w,h | ^!w,h
66
+ )
67
+ if not regex.search(size_re, size_seg):
68
+ return False
69
+ # rotation -> floating point number 0-360 -> n | !n (positive and negative are allowed)
70
+ rotation_re = r"^!?[+-]?\d+(\.\d+)?$"
71
+ if not regex.search(rotation_re, rotation_seg):
72
+ return False
73
+ # quality -> color | colour | gray | grey | bitonal | default | native
74
+ # format -> jpg | tif | png | gif | jp2 | pdf | webp
75
+ quality_format_re = r"^(colou?r|gr[ae]y|bitonal|default|native)(\.(jpg|tif|png|jp2|gif|pdf|webp))?$"
76
+ return bool(regex.search(quality_format_re, quality_format_seg))
@@ -0,0 +1,63 @@
1
+ from typing import assert_never
2
+
3
+ from loguru import logger
4
+
5
+ from dsp_tools.clients.fuseki_metrics import FusekiBloatingLevel
6
+ from dsp_tools.clients.fuseki_metrics import FusekiMetrics
7
+ from dsp_tools.config.logger_config import LOGGER_SAVEPATH
8
+ from dsp_tools.utils.ansi_colors import BACKGROUND_BOLD_RED
9
+ from dsp_tools.utils.ansi_colors import BOLD_YELLOW
10
+ from dsp_tools.utils.ansi_colors import RESET_TO_DEFAULT
11
+
12
+ _1_GB_IN_BYTES = 1_000_000_000
13
+ WARNING_BLOATING = 10 * _1_GB_IN_BYTES
14
+ CRITICAL_BLOATING = 20 * _1_GB_IN_BYTES
15
+
16
+
17
+ def communicate_fuseki_bloating(fuseki_metrics: FusekiMetrics) -> None:
18
+ size_diff = _analyse_fuseki_sizes(fuseki_metrics)
19
+ bloating_level = _get_bloating_level(size_diff)
20
+ if size_diff is not None:
21
+ rounded = round(size_diff / _1_GB_IN_BYTES, 2)
22
+ else:
23
+ rounded = None
24
+ msg = (
25
+ f"The xmlupload caused the database to use {rounded} GB disk space. "
26
+ f"Please check that your test server has enough disk space for an upload. "
27
+ f"If you have any questions contact the dsp-tools developers at support@dasch.swiss."
28
+ )
29
+ match bloating_level:
30
+ case FusekiBloatingLevel.OK:
31
+ logger.debug(msg)
32
+ case FusekiBloatingLevel.WARNING:
33
+ logger.warning(msg)
34
+ print(f"{BOLD_YELLOW}WARNING: {msg}{RESET_TO_DEFAULT}")
35
+ case FusekiBloatingLevel.CRITICAL:
36
+ logger.warning(msg)
37
+ print(f"{BACKGROUND_BOLD_RED}WARNING: {msg}{RESET_TO_DEFAULT}")
38
+ case FusekiBloatingLevel.CALCULATION_FAILURE:
39
+ msg = (
40
+ "The database bloating size could not be calculated. "
41
+ f"Please contact the dsp-tools developers (at support@dasch.swiss) "
42
+ f"with your logs saved at {LOGGER_SAVEPATH}."
43
+ )
44
+ print(f"{BACKGROUND_BOLD_RED}{msg}{RESET_TO_DEFAULT}")
45
+ logger.error(msg)
46
+ case _:
47
+ assert_never(bloating_level)
48
+
49
+
50
+ def _get_bloating_level(size_diff: int | None) -> FusekiBloatingLevel:
51
+ if size_diff is None:
52
+ return FusekiBloatingLevel.CALCULATION_FAILURE
53
+ if size_diff <= WARNING_BLOATING:
54
+ return FusekiBloatingLevel.OK
55
+ if size_diff <= CRITICAL_BLOATING:
56
+ return FusekiBloatingLevel.WARNING
57
+ return FusekiBloatingLevel.CRITICAL
58
+
59
+
60
+ def _analyse_fuseki_sizes(fuseki_metrics: FusekiMetrics) -> int | None:
61
+ if fuseki_metrics.end_size is not None and fuseki_metrics.start_size is not None:
62
+ return fuseki_metrics.end_size - fuseki_metrics.start_size
63
+ return None
@@ -0,0 +1,22 @@
1
+ import json
2
+ from pathlib import Path
3
+ from typing import Any
4
+ from typing import cast
5
+
6
+ from loguru import logger
7
+
8
+ from dsp_tools.error.exceptions import JSONFileParsingError
9
+ from dsp_tools.error.exceptions import UserFilepathNotFoundError
10
+
11
+
12
+ def parse_json_file(filepath: Path) -> dict[str, Any]:
13
+ if not filepath.exists():
14
+ raise UserFilepathNotFoundError(filepath)
15
+ with open(filepath, encoding="utf-8") as f:
16
+ try:
17
+ loaded = json.load(f)
18
+ return cast(dict[str, Any], loaded)
19
+ except json.JSONDecodeError as e:
20
+ logger.error(e)
21
+ msg = f"The input file '{filepath}' cannot be parsed to a JSON object."
22
+ raise JSONFileParsingError(msg) from None
@@ -0,0 +1,42 @@
1
+ from typing import Union
2
+
3
+ from rdflib import IdentifiedNode
4
+ from rdflib import Literal
5
+ from rdflib import Namespace
6
+ from rdflib import Variable
7
+ from rdflib.term import Node
8
+
9
+ # naming conventions of prefixes and namespaces
10
+
11
+ # a prefix as a string is called [...]_PREFIX
12
+ # a prefix as a rdflib Namespace has no further suffix
13
+
14
+ #####
15
+ # rdflib typing
16
+ type PropertyTypeAlias = Union[IdentifiedNode, Variable]
17
+ type SubjectObjectTypeAlias = Union[IdentifiedNode, Literal, Variable, Node]
18
+
19
+ #####
20
+ # DSP-Namespaces
21
+ KNORA_API_PREFIX = "http://api.knora.org/ontology/knora-api/v2#"
22
+ KNORA_API = Namespace(KNORA_API_PREFIX)
23
+
24
+ KNORA_ADMIN_PREFIX = "http://www.knora.org/ontology/knora-admin#"
25
+
26
+ SALSAH_GUI_PREFIX = "http://api.knora.org/ontology/salsah-gui/v2#"
27
+ SALSAH_GUI = Namespace(SALSAH_GUI_PREFIX)
28
+
29
+
30
+ #####
31
+ # Mappers
32
+
33
+ DSP_NAME_TO_PREFIX = {"knora-api": KNORA_API_PREFIX, "salsah-gui": SALSAH_GUI_PREFIX}
34
+
35
+
36
+ #####
37
+ # For validate-data
38
+ API_SHAPES_PREFIX = "http://api.knora.org/ontology/knora-api/shapes/v2#"
39
+ API_SHAPES = Namespace(API_SHAPES_PREFIX)
40
+ DATA = Namespace("http://data/")
41
+ DASH_PREFIX = "http://datashapes.org/dash#"
42
+ DASH = Namespace(DASH_PREFIX)
@@ -0,0 +1,10 @@
1
+ import json
2
+ from typing import Any
3
+
4
+ from rdflib import Graph
5
+
6
+
7
+ def serialise_json(rdf_graph: Graph) -> list[dict[str, Any]]:
8
+ graph_bytes = rdf_graph.serialize(format="json-ld", encoding="utf-8")
9
+ json_graph: list[dict[str, Any]] = json.loads(graph_bytes)
10
+ return json_graph