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,68 @@
1
+ from copy import deepcopy
2
+
3
+ from dsp_tools.commands.xmlupload.models.formatted_text_value import FormattedTextValue
4
+ from dsp_tools.commands.xmlupload.models.processed.res import ProcessedResource
5
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedLink
6
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedRichtext
7
+ from dsp_tools.commands.xmlupload.stash.stash_models import LinkValueStash
8
+ from dsp_tools.commands.xmlupload.stash.stash_models import LinkValueStashItem
9
+ from dsp_tools.commands.xmlupload.stash.stash_models import StandoffStash
10
+ from dsp_tools.commands.xmlupload.stash.stash_models import StandoffStashItem
11
+ from dsp_tools.commands.xmlupload.stash.stash_models import Stash
12
+
13
+
14
+ def stash_circular_references(resources: list[ProcessedResource], stash_lookup: dict[str, list[str]]) -> Stash | None:
15
+ """Stash the values that would create circular references and remove them from the Resources."""
16
+ stashed_link_values: list[LinkValueStashItem] = []
17
+ stashed_standoff_values: list[StandoffStashItem] = []
18
+
19
+ if not stash_lookup:
20
+ return None
21
+
22
+ for res in resources:
23
+ if res.res_id not in stash_lookup:
24
+ continue
25
+ links, standoff = _process_one_resource(res, stash_lookup)
26
+ stashed_link_values.extend(links)
27
+ stashed_standoff_values.extend(standoff)
28
+
29
+ standoff_stash = StandoffStash.make(stashed_standoff_values)
30
+ link_value_stash = LinkValueStash.make(stashed_link_values)
31
+ return Stash.make(standoff_stash=standoff_stash, link_value_stash=link_value_stash)
32
+
33
+
34
+ def _process_one_resource(
35
+ resource: ProcessedResource,
36
+ stash_lookup: dict[str, list[str]],
37
+ ) -> tuple[list[LinkValueStashItem], list[StandoffStashItem]]:
38
+ stashed_link_values: list[LinkValueStashItem] = []
39
+ stashed_standoff_values: list[StandoffStashItem] = []
40
+
41
+ for val in resource.values.copy():
42
+ if isinstance(val, ProcessedLink):
43
+ if val.value_uuid not in stash_lookup[resource.res_id]:
44
+ continue
45
+ stashed_link_values.append(LinkValueStashItem(resource.res_id, resource.type_iri, val))
46
+ resource.values.remove(val)
47
+ elif isinstance(val, ProcessedRichtext):
48
+ if val.value_uuid not in stash_lookup[resource.res_id]:
49
+ continue
50
+ # val.value is a KnoraStandoffXml text with problematic links.
51
+ # stash it, then replace the problematic text with a UUID
52
+ stashed_standoff_values.append(_stash_standoff(val, resource.res_id, resource.type_iri))
53
+
54
+ return stashed_link_values, stashed_standoff_values
55
+
56
+
57
+ def _stash_standoff(value: ProcessedRichtext, res_id: str, res_type: str) -> StandoffStashItem:
58
+ original_value = deepcopy(value)
59
+ # Replace the content with the UUID
60
+ value.value = FormattedTextValue(value.value_uuid)
61
+ # It is not necessary to add the permissions to the StandoffStashItem.
62
+ # Because when no new permissions are given during an update request,
63
+ # the permissions of the previous value are taken.
64
+ return StandoffStashItem(
65
+ res_id=res_id,
66
+ res_type=res_type,
67
+ value=original_value,
68
+ )
@@ -0,0 +1,109 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from itertools import groupby
5
+
6
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedLink
7
+ from dsp_tools.commands.xmlupload.models.processed.values import ProcessedRichtext
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class StandoffStashItem:
12
+ res_id: str
13
+ res_type: str
14
+ value: ProcessedRichtext
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class StandoffStash:
19
+ """Holds information about a number of stashed XML text values, organized by resource instance."""
20
+
21
+ res_2_stash_items: dict[str, list[StandoffStashItem]]
22
+
23
+ @staticmethod
24
+ def make(items: list[StandoffStashItem]) -> StandoffStash | None:
25
+ """
26
+ Factory method for StandoffStash.
27
+
28
+ Args:
29
+ items: A list of StandoffStashItem.
30
+
31
+ Returns:
32
+ StandoffStash | None: A StandoffStash object or None, if an empty list was passed.
33
+ """
34
+
35
+ def _get_res_id(x: StandoffStashItem) -> str:
36
+ return x.res_id
37
+
38
+ if not items:
39
+ return None
40
+ items = sorted(items, key=_get_res_id)
41
+ grouped_objects = {k: list(vals) for k, vals in groupby(items, key=_get_res_id)}
42
+ return StandoffStash(grouped_objects)
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class LinkValueStashItem:
47
+ """Holds information about a single stashed link value."""
48
+
49
+ res_id: str
50
+ res_type: str
51
+ value: ProcessedLink
52
+
53
+
54
+ @dataclass(frozen=True)
55
+ class LinkValueStash:
56
+ """Holds information about a number of stashed link values (resptr-props), organized by resource instance."""
57
+
58
+ res_2_stash_items: dict[str, list[LinkValueStashItem]]
59
+
60
+ @staticmethod
61
+ def make(items: list[LinkValueStashItem]) -> LinkValueStash | None:
62
+ """
63
+ Factory method for LinkValueStash.
64
+
65
+ Args:
66
+ items: A list of LinkValueStashItem.
67
+
68
+ Returns:
69
+ LinkValueStash | None: A LinkValueStash object or None, if an empty list was passed.
70
+ """
71
+
72
+ def _get_res_id(x: LinkValueStashItem) -> str:
73
+ return x.res_id
74
+
75
+ if not items:
76
+ return None
77
+ items = sorted(items, key=_get_res_id)
78
+ grouped_objects = {k: list(vals) for k, vals in groupby(items, key=_get_res_id)}
79
+ return LinkValueStash(grouped_objects)
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class Stash:
84
+ """Holds a standoff stash and a linkvalue stash"""
85
+
86
+ standoff_stash: StandoffStash | None
87
+ link_value_stash: LinkValueStash | None
88
+
89
+ @staticmethod
90
+ def make(standoff_stash: StandoffStash | None, link_value_stash: LinkValueStash | None) -> Stash | None:
91
+ """
92
+ Factory method for Stash.
93
+
94
+ Args:
95
+ standoff_stash: A StandoffStash object or None.
96
+ link_value_stash: A LinkValueStash object or None.
97
+
98
+ Returns:
99
+ Stash: A Stash object, or None if both inputs are None.
100
+ """
101
+ if standoff_stash or link_value_stash:
102
+ return Stash(standoff_stash, link_value_stash)
103
+ return None
104
+
105
+ def is_empty(self) -> bool:
106
+ """Check if there are any stashed items in this stash"""
107
+ standoff = not self.standoff_stash or not self.standoff_stash.res_2_stash_items
108
+ link = not self.link_value_stash or not self.link_value_stash.res_2_stash_items
109
+ return standoff and link
@@ -0,0 +1,106 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import cast
5
+
6
+ from loguru import logger
7
+ from rdflib import RDF
8
+ from rdflib import BNode
9
+ from rdflib import Graph
10
+ from rdflib import URIRef
11
+ from tqdm import tqdm
12
+
13
+ from dsp_tools.clients.connection import Connection
14
+ from dsp_tools.commands.xmlupload.make_rdf_graph.jsonld_utils import serialise_jsonld_for_value
15
+ from dsp_tools.commands.xmlupload.make_rdf_graph.make_values import make_link_value_graph
16
+ from dsp_tools.commands.xmlupload.models.upload_state import UploadState
17
+ from dsp_tools.commands.xmlupload.stash.stash_models import LinkValueStash
18
+ from dsp_tools.commands.xmlupload.stash.stash_models import LinkValueStashItem
19
+ from dsp_tools.commands.xmlupload.stash.stash_models import Stash
20
+ from dsp_tools.error.exceptions import BaseError
21
+
22
+
23
+ def upload_stashed_resptr_props(
24
+ upload_state: UploadState,
25
+ con: Connection,
26
+ ) -> None:
27
+ """
28
+ After all resources are uploaded, the stashed resptr props must be applied to their resources in DSP.
29
+ The upload state is updated accordingly, as a side effect.
30
+
31
+ Args:
32
+ upload_state: the current state of the upload
33
+ con: connection to DSP
34
+ """
35
+ logger.info("Upload the stashed links...")
36
+ upload_state.pending_stash = cast(Stash, upload_state.pending_stash)
37
+ link_value_stash = cast(LinkValueStash, upload_state.pending_stash.link_value_stash)
38
+ progress_bar = tqdm(
39
+ link_value_stash.res_2_stash_items.copy().items(), desc="Upload the stashed links", dynamic_ncols=True
40
+ )
41
+ for res_id, stash_items in progress_bar:
42
+ res_iri = upload_state.iri_resolver.get(res_id)
43
+ if not res_iri:
44
+ # resource could not be uploaded to DSP, so the stash cannot be uploaded either
45
+ # no action necessary: this resource will remain in nonapplied_resptr_props,
46
+ # which will be handled by the caller
47
+ continue
48
+ logger.info(f" Upload resptrs of resource '{res_id}'...")
49
+ for stash_item in reversed(stash_items):
50
+ # reversed avoids any problems caused by removing from the list we loop over at the same time
51
+ target_iri = upload_state.iri_resolver.get(stash_item.value.value)
52
+ if not target_iri:
53
+ continue
54
+ if _upload_stash_item(stash_item, res_iri, target_iri, con):
55
+ link_value_stash.res_2_stash_items[res_id].remove(stash_item)
56
+ # remove res_id if all stash items were uploaded
57
+ if not link_value_stash.res_2_stash_items[res_id]:
58
+ del link_value_stash.res_2_stash_items[res_id]
59
+
60
+
61
+ def _upload_stash_item(
62
+ stash: LinkValueStashItem,
63
+ res_iri: str,
64
+ target_iri: str,
65
+ con: Connection,
66
+ ) -> bool:
67
+ """
68
+ Upload a single stashed link value to DSP.
69
+
70
+ Args:
71
+ stash: the stashed link value to upload
72
+ res_iri: the iri of the resource
73
+ target_iri: the iri of the target resource
74
+ con: connection to DSP
75
+
76
+ Returns:
77
+ True, if the upload was successful, False otherwise
78
+ """
79
+ graph = _make_link_value_create_graph(stash, res_iri, target_iri)
80
+ payload = serialise_jsonld_for_value(graph, res_iri)
81
+ try:
82
+ con.post(route="/v2/values", data=payload)
83
+ except BaseError as err:
84
+ _log_unable_to_upload_link_value(err.message, stash.res_id, stash.value.prop_iri)
85
+ return False
86
+ logger.debug(f' Successfully uploaded resptr links of "{stash.value.prop_iri}"')
87
+ return True
88
+
89
+
90
+ def _make_link_value_create_graph(
91
+ stash: LinkValueStashItem,
92
+ res_iri_str: str,
93
+ target_iri: str,
94
+ ) -> Graph:
95
+ """This function creates a JSON object that can be sent as an update request to the DSP-API."""
96
+ val_bn = BNode()
97
+ res_iri = URIRef(res_iri_str)
98
+ graph = make_link_value_graph(stash.value, val_bn, res_iri, URIRef(target_iri))
99
+ graph.add((res_iri, RDF.type, URIRef(stash.res_type)))
100
+ return graph
101
+
102
+
103
+ def _log_unable_to_upload_link_value(msg: str, res_id: str, prop_name: str) -> None:
104
+ err_msg = f"Unable to upload the resptr prop of '{prop_name}' of resource '{res_id}'."
105
+ print(f"{datetime.now()}: WARNING: {err_msg} Original error message: {msg}")
106
+ logger.error(err_msg)
@@ -0,0 +1,196 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime
4
+ from typing import Any
5
+ from typing import cast
6
+ from urllib.parse import quote_plus
7
+
8
+ from loguru import logger
9
+ from rdflib import RDF
10
+ from rdflib import Graph
11
+ from rdflib import URIRef
12
+ from tqdm import tqdm
13
+
14
+ from dsp_tools.clients.connection import Connection
15
+ from dsp_tools.commands.xmlupload.iri_resolver import IriResolver
16
+ from dsp_tools.commands.xmlupload.make_rdf_graph.jsonld_utils import serialise_jsonld_for_value
17
+ from dsp_tools.commands.xmlupload.make_rdf_graph.make_values import make_richtext_value_graph
18
+ from dsp_tools.commands.xmlupload.models.upload_state import UploadState
19
+ from dsp_tools.commands.xmlupload.stash.stash_models import StandoffStash
20
+ from dsp_tools.commands.xmlupload.stash.stash_models import StandoffStashItem
21
+ from dsp_tools.commands.xmlupload.stash.stash_models import Stash
22
+ from dsp_tools.error.exceptions import BaseError
23
+
24
+
25
+ def upload_stashed_xml_texts(upload_state: UploadState, con: Connection) -> None:
26
+ """
27
+ After all resources are uploaded, the stashed xml texts must be applied to their resources in DSP.
28
+ The upload state is updated accordingly, as a side effect.
29
+
30
+ Args:
31
+ upload_state: the current state of the upload
32
+ con: connection to DSP
33
+ """
34
+ logger.info("Upload the stashed XML texts...")
35
+ upload_state.pending_stash = cast(Stash, upload_state.pending_stash)
36
+ standoff_stash = cast(StandoffStash, upload_state.pending_stash.standoff_stash)
37
+ progress_bar = tqdm(
38
+ standoff_stash.res_2_stash_items.copy().items(), desc="Upload stashed XML texts", dynamic_ncols=True
39
+ )
40
+ for res_id, stash_items in progress_bar:
41
+ res_iri = upload_state.iri_resolver.get(res_id)
42
+ if not res_iri:
43
+ # resource could not be uploaded to DSP, so the stash cannot be uploaded either
44
+ # no action necessary: this resource will remain in the list of not uploaded stash items,
45
+ # which will be handled by the caller
46
+ continue
47
+ try:
48
+ resource_in_triplestore = con.get(f"/v2/resources/{quote_plus(res_iri)}")
49
+ except BaseError as err:
50
+ _log_unable_to_retrieve_resource(resource=res_id, received_error=err)
51
+ continue
52
+ logger.info(f" Upload XML text(s) of resource '{res_id}'...")
53
+ for stash_item in stash_items:
54
+ value_iri = _get_value_iri(stash_item.value.prop_iri, resource_in_triplestore, stash_item.value.value_uuid)
55
+ if not value_iri:
56
+ continue
57
+ if _upload_stash_item(
58
+ stash_item=stash_item,
59
+ res_iri=res_iri,
60
+ value_iri=value_iri,
61
+ iri_resolver=upload_state.iri_resolver,
62
+ con=con,
63
+ ):
64
+ standoff_stash.res_2_stash_items[res_id].remove(stash_item)
65
+ if not standoff_stash.res_2_stash_items[res_id]:
66
+ standoff_stash.res_2_stash_items.pop(res_id)
67
+
68
+
69
+ def _get_value_iri(
70
+ property_name: str,
71
+ resource: dict[str, Any],
72
+ uuid: str,
73
+ ) -> str | None:
74
+ prefixed_prop = _make_prefixed_prop_from_absolute_iri(property_name)
75
+ values_on_server = resource.get(prefixed_prop)
76
+ if not isinstance(values_on_server, list):
77
+ values_on_server = [values_on_server]
78
+
79
+ # get the IRI of the value that contains the UUID in its text
80
+ text_and_iris = ((v["knora-api:textValueAsXml"], v["@id"]) for v in values_on_server)
81
+ value_iri: str | None = next((iri for text, iri in text_and_iris if uuid in text), None)
82
+ # in case that "value_iri" is None, the value that contains the UUID in its text does not exist in DSP
83
+ # no action necessary: this resource will remain in nonapplied_xml_texts,
84
+ # which will be handled by the caller
85
+ return value_iri
86
+
87
+
88
+ def _make_prefixed_prop_from_absolute_iri(absolute_iri: str) -> str:
89
+ _, onto, prop = absolute_iri.rsplit("/", 2)
90
+ local_name = prop.split("#")[-1]
91
+ return f"{onto}:{local_name}"
92
+
93
+
94
+ def _upload_stash_item(
95
+ stash_item: StandoffStashItem,
96
+ res_iri: str,
97
+ value_iri: str,
98
+ iri_resolver: IriResolver,
99
+ con: Connection,
100
+ ) -> bool:
101
+ """
102
+ Upload a single stashed xml text to DSP.
103
+
104
+ Args:
105
+ stash_item: the stashed text value to upload
106
+ res_iri: the iri of the resource
107
+ value_iri: the iri of the value
108
+ iri_resolver: resolver to map ids from the XML file to IRIs in DSP
109
+ con: connection to DSP
110
+
111
+ Returns:
112
+ True, if the upload was successful, False otherwise
113
+ """
114
+ payload = _serialise_richtext_for_update(
115
+ stash_item=stash_item,
116
+ value_iri_str=value_iri,
117
+ res_iri_str=res_iri,
118
+ iri_resolver=iri_resolver,
119
+ )
120
+ try:
121
+ con.put(route="/v2/values", data=payload)
122
+ except BaseError as err:
123
+ _log_unable_to_upload_xml_resource(err, stash_item.res_id, stash_item.value.prop_iri)
124
+ return False
125
+ logger.debug(f' Successfully uploaded xml text of "{stash_item.value.prop_iri}"')
126
+ return True
127
+
128
+
129
+ def _serialise_richtext_for_update(
130
+ stash_item: StandoffStashItem, value_iri_str: str, res_iri_str: str, iri_resolver: IriResolver
131
+ ) -> dict[str, Any]:
132
+ graph = _make_richtext_update_graph(
133
+ stash_item=stash_item,
134
+ value_iri_str=value_iri_str,
135
+ res_iri_str=res_iri_str,
136
+ iri_resolver=iri_resolver,
137
+ )
138
+ return serialise_jsonld_for_value(graph, res_iri_str)
139
+
140
+
141
+ def _make_richtext_update_graph(
142
+ stash_item: StandoffStashItem, value_iri_str: str, res_iri_str: str, iri_resolver: IriResolver
143
+ ) -> Graph:
144
+ res_iri = URIRef(res_iri_str)
145
+ value_iri = URIRef(value_iri_str)
146
+ val_graph = make_richtext_value_graph(
147
+ val=stash_item.value,
148
+ val_node=value_iri,
149
+ res_node=res_iri,
150
+ iri_resolver=iri_resolver,
151
+ )
152
+ val_graph.add((res_iri, RDF.type, URIRef(stash_item.res_type)))
153
+ return val_graph
154
+
155
+
156
+ def _log_unable_to_retrieve_resource(
157
+ resource: str,
158
+ received_error: BaseError,
159
+ ) -> None:
160
+ """
161
+ This function logs the error if it is not possible to retrieve the resource.
162
+
163
+ Args:
164
+ resource: the resource id
165
+ received_error: the error
166
+ """
167
+ # print the message to keep track of the cause for the failure
168
+ # apart from that; no action is necessary:
169
+ # this resource will remain in nonapplied_xml_texts, which will be handled by the caller
170
+ err_msg = (
171
+ f"Unable to upload XML texts of resource '{resource}', "
172
+ "because the resource cannot be retrieved from the DSP server."
173
+ )
174
+ print(f"{datetime.now()}: WARNING: {err_msg} Original error message: {received_error.message}")
175
+ logger.error(err_msg)
176
+
177
+
178
+ def _log_unable_to_upload_xml_resource(
179
+ received_error: BaseError,
180
+ stashed_resource_id: str,
181
+ prop_name: str,
182
+ ) -> None:
183
+ """
184
+ This function logs if it is not possible to upload a xml resource.
185
+
186
+ Args:
187
+ received_error: Error received
188
+ stashed_resource_id: id of the resource
189
+ prop_name: name of the property
190
+ """
191
+ # print the message to keep track of the cause for the failure
192
+ # apart from that; no action is necessary:
193
+ # this resource will remain in nonapplied_xml_texts, which will be handled by the caller
194
+ err_msg = f"Unable to upload the xml text of '{prop_name}' of resource '{stashed_resource_id}'."
195
+ print(f"{datetime.now()}: WARNING: {err_msg} Original error message: {received_error.message}")
196
+ logger.error(err_msg)
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ from dataclasses import dataclass
5
+ from dataclasses import field
6
+ from pathlib import Path
7
+
8
+ import regex
9
+ from loguru import logger
10
+
11
+ from dsp_tools.cli.args import ValidationSeverity
12
+
13
+
14
+ def _transform_server_url_to_foldername(server: str) -> str:
15
+ """
16
+ Take the server URL and transform it so that it can be used as foldername.
17
+
18
+ Args:
19
+ server: server, e.g. "https://api.test.dasch.swiss/" or "http://0.0.0.0:3333"
20
+
21
+ Returns:
22
+ simplified version, e.g. "test.dasch.swiss" or "localhost"
23
+ """
24
+ server_substitutions = {
25
+ r"https?://": "",
26
+ r"^api\.": "",
27
+ r":\d{2,5}/?$": "",
28
+ r"/$": "",
29
+ r"0.0.0.0": "localhost", # noqa: S104 (hardcoded-bind-all-interfaces)
30
+ }
31
+ for pattern, repl in server_substitutions.items():
32
+ server = regex.sub(pattern, repl, server)
33
+ return server
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class DiagnosticsConfig:
38
+ """Configures all diagnostics for a given upload."""
39
+
40
+ server_as_foldername: str = "unknown"
41
+ save_location: Path = field(default=Path.home() / ".dsp-tools" / "xmluploads")
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class UploadConfig:
46
+ """Configuration for the upload process."""
47
+
48
+ media_previously_uploaded: bool = False
49
+ server: str = "unknown"
50
+ shortcode: str = "unknown"
51
+ diagnostics: DiagnosticsConfig = field(default_factory=DiagnosticsConfig)
52
+ interrupt_after: int | None = None
53
+ skip_iiif_validation: bool = False
54
+ skip_validation: bool = False
55
+ skip_ontology_validation: bool = False
56
+ ignore_duplicate_files_warning: bool = False
57
+ validation_severity: ValidationSeverity = field(default_factory=lambda: ValidationSeverity.INFO)
58
+ id2iri_file: str | None = None
59
+ do_not_request_resource_metadata_from_db: bool = False
60
+
61
+ def with_server_info(
62
+ self,
63
+ server: str,
64
+ shortcode: str,
65
+ ) -> UploadConfig:
66
+ """Create a new UploadConfig with the given server."""
67
+ server_as_foldername = _transform_server_url_to_foldername(server)
68
+ save_location = Path.home() / Path(".dsp-tools") / "xmluploads" / server_as_foldername / "resumable/latest.pkl"
69
+ save_location.parent.mkdir(parents=True, exist_ok=True)
70
+ logger.info(f"{save_location=:}")
71
+ diagnostics: DiagnosticsConfig = dataclasses.replace(
72
+ self.diagnostics,
73
+ server_as_foldername=server_as_foldername,
74
+ save_location=save_location,
75
+ )
76
+ return dataclasses.replace(self, server=server, shortcode=shortcode, diagnostics=diagnostics)
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+
7
+ from loguru import logger
8
+
9
+ from dsp_tools.commands.xmlupload.upload_config import DiagnosticsConfig
10
+
11
+
12
+ def write_id2iri_mapping(id2iri_mapping: dict[str, str], shortcode: str, diagnostics: DiagnosticsConfig) -> None:
13
+ """Writes the mapping of internal IDs to IRIs to a file."""
14
+ timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")
15
+ servername = diagnostics.server_as_foldername
16
+ json_str = json.dumps(id2iri_mapping, ensure_ascii=False, indent=4)
17
+ id2iri_filename_for_user = f"id2iri_{shortcode}_{servername}_{timestamp}.json"
18
+ with open(id2iri_filename_for_user, "w", encoding="utf-8") as f:
19
+ f.write(json_str)
20
+ print(f"{datetime.now()}: The mapping of internal IDs to IRIs was written to {id2iri_filename_for_user}")
21
+ logger.info(f"The mapping of internal IDs to IRIs was written to {id2iri_filename_for_user}")
22
+
23
+ id_2_iri_folder = Path.home() / ".dsp-tools" / "id2iri"
24
+ id_2_iri_folder.mkdir(parents=True, exist_ok=True)
25
+ id2iri_filename_for_user_home = f"id2iri_{timestamp}_{shortcode}_{servername}.json"
26
+ with open(id_2_iri_folder / id2iri_filename_for_user_home, "w", encoding="utf-8") as f:
27
+ f.write(json_str)