dsp-tools 9.1.0.post11__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 (316) hide show
  1. dsp_tools/__init__.py +4 -0
  2. dsp_tools/cli/args.py +36 -0
  3. dsp_tools/cli/call_action.py +51 -231
  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 +156 -58
  7. dsp_tools/cli/entry_point.py +56 -26
  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/{utils → clients}/connection.py +2 -18
  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 +57 -23
  58. dsp_tools/commands/excel2json/{new_lists → lists}/compliance_checks.py +26 -26
  59. dsp_tools/commands/excel2json/{new_lists/make_new_lists.py → lists/make_lists.py} +19 -18
  60. dsp_tools/commands/excel2json/{new_lists → lists}/models/input_error.py +1 -12
  61. dsp_tools/commands/excel2json/{new_lists → lists}/models/serialise.py +9 -5
  62. dsp_tools/commands/excel2json/{new_lists → lists}/utils.py +4 -4
  63. dsp_tools/commands/excel2json/models/input_error.py +31 -11
  64. dsp_tools/commands/excel2json/models/json_header.py +53 -15
  65. dsp_tools/commands/excel2json/models/ontology.py +4 -3
  66. dsp_tools/commands/excel2json/{lists.py → old_lists.py} +26 -112
  67. dsp_tools/commands/excel2json/project.py +78 -34
  68. dsp_tools/commands/excel2json/properties.py +57 -36
  69. dsp_tools/commands/excel2json/resources.py +32 -12
  70. dsp_tools/commands/excel2json/utils.py +20 -1
  71. dsp_tools/commands/excel2xml/__init__.py +2 -2
  72. dsp_tools/commands/excel2xml/excel2xml_cli.py +7 -15
  73. dsp_tools/commands/excel2xml/excel2xml_lib.py +138 -493
  74. dsp_tools/commands/excel2xml/propertyelement.py +5 -5
  75. dsp_tools/commands/{project → get}/get.py +29 -13
  76. dsp_tools/commands/get/get_permissions.py +257 -0
  77. dsp_tools/commands/get/get_permissions_legacy.py +89 -0
  78. dsp_tools/commands/{project/models → get/legacy_models}/context.py +6 -6
  79. dsp_tools/commands/{project/models → get/legacy_models}/group.py +5 -10
  80. dsp_tools/commands/{project/models → get/legacy_models}/listnode.py +5 -35
  81. dsp_tools/commands/{project/models → get/legacy_models}/model.py +1 -1
  82. dsp_tools/commands/{project/models → get/legacy_models}/ontology.py +9 -14
  83. dsp_tools/commands/{project/models → get/legacy_models}/project.py +13 -6
  84. dsp_tools/commands/{project/models → get/legacy_models}/propertyclass.py +9 -16
  85. dsp_tools/commands/{project/models → get/legacy_models}/resourceclass.py +8 -46
  86. dsp_tools/commands/{project/models → get/legacy_models}/user.py +19 -60
  87. dsp_tools/commands/get/models/permissions_models.py +10 -0
  88. dsp_tools/commands/id2iri.py +20 -10
  89. dsp_tools/commands/ingest_xmlupload/bulk_ingest_client.py +81 -56
  90. dsp_tools/commands/ingest_xmlupload/create_resources/apply_ingest_id.py +4 -10
  91. dsp_tools/commands/ingest_xmlupload/create_resources/upload_xml.py +97 -37
  92. dsp_tools/commands/ingest_xmlupload/create_resources/user_information.py +2 -2
  93. dsp_tools/commands/ingest_xmlupload/ingest_files/ingest_files.py +9 -10
  94. dsp_tools/commands/ingest_xmlupload/upload_files/filechecker.py +3 -3
  95. dsp_tools/commands/ingest_xmlupload/upload_files/input_error.py +2 -10
  96. dsp_tools/commands/ingest_xmlupload/upload_files/upload_failures.py +12 -2
  97. dsp_tools/commands/ingest_xmlupload/upload_files/upload_files.py +8 -9
  98. dsp_tools/commands/resume_xmlupload/resume_xmlupload.py +18 -18
  99. dsp_tools/commands/start_stack.py +126 -77
  100. dsp_tools/commands/update_legal/CLAUDE.md +344 -0
  101. dsp_tools/commands/update_legal/__init__.py +0 -0
  102. dsp_tools/commands/update_legal/core.py +182 -0
  103. dsp_tools/commands/update_legal/csv_operations.py +135 -0
  104. dsp_tools/commands/update_legal/models.py +87 -0
  105. dsp_tools/commands/update_legal/xml_operations.py +247 -0
  106. dsp_tools/commands/validate_data/CLAUDE.md +159 -0
  107. dsp_tools/commands/validate_data/__init__.py +0 -0
  108. dsp_tools/commands/validate_data/constants.py +59 -0
  109. dsp_tools/commands/validate_data/mappers.py +143 -0
  110. dsp_tools/commands/validate_data/models/__init__.py +0 -0
  111. dsp_tools/commands/validate_data/models/api_responses.py +45 -0
  112. dsp_tools/commands/validate_data/models/input_problems.py +119 -0
  113. dsp_tools/commands/validate_data/models/rdf_like_data.py +117 -0
  114. dsp_tools/commands/validate_data/models/validation.py +106 -0
  115. dsp_tools/commands/validate_data/prepare_data/__init__.py +0 -0
  116. dsp_tools/commands/validate_data/prepare_data/get_rdf_like_data.py +296 -0
  117. dsp_tools/commands/validate_data/prepare_data/make_data_graph.py +91 -0
  118. dsp_tools/commands/validate_data/prepare_data/prepare_data.py +184 -0
  119. dsp_tools/commands/validate_data/process_validation_report/__init__.py +0 -0
  120. dsp_tools/commands/validate_data/process_validation_report/get_user_validation_message.py +358 -0
  121. dsp_tools/commands/validate_data/process_validation_report/query_validation_result.py +507 -0
  122. dsp_tools/commands/validate_data/process_validation_report/reformat_validation_results.py +150 -0
  123. dsp_tools/commands/validate_data/shacl_cli_validator.py +70 -0
  124. dsp_tools/commands/validate_data/sparql/__init__.py +0 -0
  125. dsp_tools/commands/{xml_validate/sparql/resource_shacl.py → validate_data/sparql/cardinality_shacl.py} +45 -47
  126. dsp_tools/commands/validate_data/sparql/construct_shacl.py +92 -0
  127. dsp_tools/commands/validate_data/sparql/legal_info_shacl.py +36 -0
  128. dsp_tools/commands/validate_data/sparql/value_shacl.py +357 -0
  129. dsp_tools/commands/validate_data/utils.py +59 -0
  130. dsp_tools/commands/validate_data/validate_data.py +283 -0
  131. dsp_tools/commands/validate_data/validation/__init__.py +0 -0
  132. dsp_tools/commands/validate_data/validation/check_duplicate_files.py +55 -0
  133. dsp_tools/commands/validate_data/validation/check_for_unknown_classes.py +67 -0
  134. dsp_tools/commands/validate_data/validation/get_validation_report.py +94 -0
  135. dsp_tools/commands/validate_data/validation/validate_ontology.py +107 -0
  136. dsp_tools/commands/xmlupload/CLAUDE.md +292 -0
  137. dsp_tools/commands/xmlupload/make_rdf_graph/__init__.py +0 -0
  138. dsp_tools/commands/xmlupload/make_rdf_graph/constants.py +63 -0
  139. dsp_tools/commands/xmlupload/make_rdf_graph/jsonld_utils.py +44 -0
  140. dsp_tools/commands/xmlupload/make_rdf_graph/make_file_value.py +77 -0
  141. dsp_tools/commands/xmlupload/make_rdf_graph/make_resource_and_values.py +114 -0
  142. dsp_tools/commands/xmlupload/make_rdf_graph/make_values.py +262 -0
  143. dsp_tools/commands/xmlupload/models/bitstream_info.py +18 -0
  144. dsp_tools/commands/xmlupload/models/formatted_text_value.py +0 -25
  145. dsp_tools/commands/xmlupload/models/ingest.py +56 -70
  146. dsp_tools/commands/xmlupload/models/input_problems.py +6 -14
  147. dsp_tools/commands/xmlupload/models/lookup_models.py +21 -0
  148. dsp_tools/commands/xmlupload/models/permission.py +0 -39
  149. dsp_tools/commands/xmlupload/models/{deserialise/xmlpermission.py → permissions_parsed.py} +2 -2
  150. dsp_tools/commands/xmlupload/models/processed/__init__.py +0 -0
  151. dsp_tools/commands/xmlupload/models/processed/file_values.py +29 -0
  152. dsp_tools/commands/xmlupload/models/processed/res.py +27 -0
  153. dsp_tools/commands/xmlupload/models/processed/values.py +101 -0
  154. dsp_tools/commands/xmlupload/models/rdf_models.py +26 -0
  155. dsp_tools/commands/xmlupload/models/upload_clients.py +3 -3
  156. dsp_tools/commands/xmlupload/models/upload_state.py +2 -4
  157. dsp_tools/commands/xmlupload/prepare_xml_input/__init__.py +0 -0
  158. dsp_tools/commands/xmlupload/{ark2iri.py → prepare_xml_input/ark2iri.py} +1 -1
  159. dsp_tools/commands/xmlupload/prepare_xml_input/get_processed_resources.py +252 -0
  160. dsp_tools/commands/xmlupload/{iiif_uri_validator.py → prepare_xml_input/iiif_uri_validator.py} +2 -14
  161. dsp_tools/commands/xmlupload/{list_client.py → prepare_xml_input/list_client.py} +15 -10
  162. dsp_tools/commands/xmlupload/prepare_xml_input/prepare_xml_input.py +67 -0
  163. dsp_tools/commands/xmlupload/prepare_xml_input/read_validate_xml_file.py +58 -0
  164. dsp_tools/commands/xmlupload/prepare_xml_input/transform_input_values.py +118 -0
  165. dsp_tools/commands/xmlupload/resource_create_client.py +7 -468
  166. dsp_tools/commands/xmlupload/richtext_id2iri.py +37 -0
  167. dsp_tools/commands/xmlupload/stash/{construct_and_analyze_graph.py → analyse_circular_reference_graph.py} +64 -157
  168. dsp_tools/commands/xmlupload/stash/create_info_for_graph.py +53 -0
  169. dsp_tools/commands/xmlupload/stash/graph_models.py +13 -8
  170. dsp_tools/commands/xmlupload/stash/stash_circular_references.py +48 -115
  171. dsp_tools/commands/xmlupload/stash/stash_models.py +4 -9
  172. dsp_tools/commands/xmlupload/stash/upload_stashed_resptr_props.py +34 -40
  173. dsp_tools/commands/xmlupload/stash/upload_stashed_xml_texts.py +98 -108
  174. dsp_tools/commands/xmlupload/upload_config.py +8 -0
  175. dsp_tools/commands/xmlupload/write_diagnostic_info.py +14 -9
  176. dsp_tools/commands/xmlupload/xmlupload.py +214 -192
  177. dsp_tools/config/__init__.py +0 -0
  178. dsp_tools/config/logger_config.py +69 -0
  179. dsp_tools/{utils → config}/warnings_config.py +4 -1
  180. dsp_tools/error/__init__.py +0 -0
  181. dsp_tools/error/custom_warnings.py +39 -0
  182. dsp_tools/error/exceptions.py +204 -0
  183. dsp_tools/error/problems.py +10 -0
  184. dsp_tools/error/xmllib_errors.py +20 -0
  185. dsp_tools/error/xmllib_warnings.py +54 -0
  186. dsp_tools/error/xmllib_warnings_util.py +159 -0
  187. dsp_tools/error/xsd_validation_error_msg.py +19 -0
  188. dsp_tools/legacy_models/__init__.py +0 -0
  189. dsp_tools/{models → legacy_models}/datetimestamp.py +7 -7
  190. dsp_tools/{models → legacy_models}/langstring.py +1 -1
  191. dsp_tools/{models → legacy_models}/projectContext.py +4 -4
  192. dsp_tools/resources/schema/data.xsd +108 -83
  193. dsp_tools/resources/schema/lists-only.json +4 -23
  194. dsp_tools/resources/schema/project.json +80 -35
  195. dsp_tools/resources/schema/properties-only.json +1 -4
  196. dsp_tools/resources/start-stack/docker-compose.override-host.j2 +11 -0
  197. dsp_tools/resources/start-stack/docker-compose.yml +34 -30
  198. dsp_tools/resources/start-stack/dsp-app-config.json +45 -0
  199. dsp_tools/resources/start-stack/dsp-app-config.override-host.j2 +26 -0
  200. dsp_tools/resources/validate_data/api-shapes-resource-cardinalities.ttl +191 -0
  201. dsp_tools/resources/validate_data/api-shapes.ttl +804 -0
  202. dsp_tools/resources/validate_data/shacl-cli-image.yml +4 -0
  203. dsp_tools/resources/validate_data/validate-ontology.ttl +99 -0
  204. dsp_tools/utils/ansi_colors.py +32 -0
  205. dsp_tools/utils/data_formats/__init__.py +0 -0
  206. dsp_tools/utils/{date_util.py → data_formats/date_util.py} +13 -1
  207. dsp_tools/utils/data_formats/iri_util.py +30 -0
  208. dsp_tools/utils/{shared.py → data_formats/shared.py} +1 -35
  209. dsp_tools/utils/{uri_util.py → data_formats/uri_util.py} +12 -2
  210. dsp_tools/utils/fuseki_bloating.py +63 -0
  211. dsp_tools/utils/json_parsing.py +22 -0
  212. dsp_tools/utils/rdf_constants.py +42 -0
  213. dsp_tools/utils/rdflib_utils.py +10 -0
  214. dsp_tools/utils/replace_id_with_iri.py +66 -0
  215. dsp_tools/utils/request_utils.py +238 -0
  216. dsp_tools/utils/xml_parsing/__init__.py +0 -0
  217. dsp_tools/utils/xml_parsing/get_lookups.py +32 -0
  218. dsp_tools/utils/xml_parsing/get_parsed_resources.py +325 -0
  219. dsp_tools/utils/xml_parsing/models/__init__.py +0 -0
  220. dsp_tools/utils/xml_parsing/models/parsed_resource.py +76 -0
  221. dsp_tools/utils/xml_parsing/parse_clean_validate_xml.py +137 -0
  222. dsp_tools/xmllib/CLAUDE.md +302 -0
  223. dsp_tools/xmllib/__init__.py +49 -0
  224. dsp_tools/xmllib/general_functions.py +877 -0
  225. dsp_tools/xmllib/internal/__init__.py +0 -0
  226. dsp_tools/xmllib/internal/checkers.py +162 -0
  227. dsp_tools/xmllib/internal/circumvent_circular_imports.py +36 -0
  228. dsp_tools/xmllib/internal/constants.py +46 -0
  229. dsp_tools/xmllib/internal/input_converters.py +155 -0
  230. dsp_tools/xmllib/internal/serialise_file_value.py +57 -0
  231. dsp_tools/xmllib/internal/serialise_resource.py +177 -0
  232. dsp_tools/xmllib/internal/serialise_values.py +152 -0
  233. dsp_tools/xmllib/internal/type_aliases.py +11 -0
  234. dsp_tools/xmllib/models/config_options.py +28 -0
  235. dsp_tools/xmllib/models/date_formats.py +48 -0
  236. dsp_tools/xmllib/models/dsp_base_resources.py +1380 -400
  237. dsp_tools/xmllib/models/internal/__init__.py +0 -0
  238. dsp_tools/xmllib/models/internal/file_values.py +172 -0
  239. dsp_tools/xmllib/models/internal/geometry.py +162 -0
  240. dsp_tools/xmllib/models/{migration_metadata.py → internal/migration_metadata.py} +14 -10
  241. dsp_tools/xmllib/models/internal/serialise_permissions.py +66 -0
  242. dsp_tools/xmllib/models/internal/values.py +342 -0
  243. dsp_tools/xmllib/models/licenses/__init__.py +0 -0
  244. dsp_tools/xmllib/models/licenses/other.py +59 -0
  245. dsp_tools/xmllib/models/licenses/recommended.py +107 -0
  246. dsp_tools/xmllib/models/permissions.py +41 -0
  247. dsp_tools/xmllib/models/res.py +1782 -0
  248. dsp_tools/xmllib/models/root.py +313 -26
  249. dsp_tools/xmllib/value_checkers.py +310 -47
  250. dsp_tools/xmllib/value_converters.py +765 -8
  251. dsp_tools-18.3.0.post13.dist-info/METADATA +90 -0
  252. dsp_tools-18.3.0.post13.dist-info/RECORD +286 -0
  253. dsp_tools-18.3.0.post13.dist-info/WHEEL +4 -0
  254. {dsp_tools-9.1.0.post11.dist-info → dsp_tools-18.3.0.post13.dist-info}/entry_points.txt +1 -0
  255. dsp_tools/commands/project/create/project_create.py +0 -1107
  256. dsp_tools/commands/project/create/project_create_lists.py +0 -204
  257. dsp_tools/commands/project/create/project_validate.py +0 -453
  258. dsp_tools/commands/project/models/project_definition.py +0 -12
  259. dsp_tools/commands/rosetta.py +0 -124
  260. dsp_tools/commands/template.py +0 -30
  261. dsp_tools/commands/xml_validate/api_connection.py +0 -122
  262. dsp_tools/commands/xml_validate/deserialise_input.py +0 -135
  263. dsp_tools/commands/xml_validate/make_data_rdf.py +0 -193
  264. dsp_tools/commands/xml_validate/models/data_deserialised.py +0 -108
  265. dsp_tools/commands/xml_validate/models/data_rdf.py +0 -214
  266. dsp_tools/commands/xml_validate/models/input_problems.py +0 -191
  267. dsp_tools/commands/xml_validate/models/validation.py +0 -29
  268. dsp_tools/commands/xml_validate/reformat_validaton_result.py +0 -89
  269. dsp_tools/commands/xml_validate/sparql/construct_shapes.py +0 -16
  270. dsp_tools/commands/xml_validate/xml_validate.py +0 -151
  271. dsp_tools/commands/xmlupload/check_consistency_with_ontology.py +0 -253
  272. dsp_tools/commands/xmlupload/models/deserialise/deserialise_value.py +0 -236
  273. dsp_tools/commands/xmlupload/models/deserialise/xmlresource.py +0 -171
  274. dsp_tools/commands/xmlupload/models/namespace_context.py +0 -39
  275. dsp_tools/commands/xmlupload/models/ontology_lookup_models.py +0 -161
  276. dsp_tools/commands/xmlupload/models/ontology_problem_models.py +0 -178
  277. dsp_tools/commands/xmlupload/models/serialise/jsonld_serialiser.py +0 -40
  278. dsp_tools/commands/xmlupload/models/serialise/serialise_value.py +0 -51
  279. dsp_tools/commands/xmlupload/ontology_client.py +0 -92
  280. dsp_tools/commands/xmlupload/project_client.py +0 -91
  281. dsp_tools/commands/xmlupload/read_validate_xml_file.py +0 -99
  282. dsp_tools/models/custom_warnings.py +0 -31
  283. dsp_tools/models/exceptions.py +0 -90
  284. dsp_tools/resources/0100-template-repo/template.json +0 -45
  285. dsp_tools/resources/0100-template-repo/template.xml +0 -27
  286. dsp_tools/resources/start-stack/docker-compose-validation.yml +0 -5
  287. dsp_tools/resources/start-stack/start-stack-config.yml +0 -4
  288. dsp_tools/resources/xml_validate/api-shapes.ttl +0 -411
  289. dsp_tools/resources/xml_validate/replace_namespace.xslt +0 -61
  290. dsp_tools/utils/connection_live.py +0 -383
  291. dsp_tools/utils/iri_util.py +0 -14
  292. dsp_tools/utils/logger_config.py +0 -41
  293. dsp_tools/utils/set_encoder.py +0 -20
  294. dsp_tools/utils/xml_utils.py +0 -145
  295. dsp_tools/utils/xml_validation.py +0 -197
  296. dsp_tools/utils/xml_validation_models.py +0 -68
  297. dsp_tools/xmllib/models/file_values.py +0 -78
  298. dsp_tools/xmllib/models/resource.py +0 -415
  299. dsp_tools/xmllib/models/values.py +0 -428
  300. dsp_tools-9.1.0.post11.dist-info/METADATA +0 -130
  301. dsp_tools-9.1.0.post11.dist-info/RECORD +0 -167
  302. dsp_tools-9.1.0.post11.dist-info/WHEEL +0 -4
  303. dsp_tools-9.1.0.post11.dist-info/licenses/LICENSE +0 -674
  304. /dsp_tools/{commands/excel2json/new_lists → clients}/__init__.py +0 -0
  305. /dsp_tools/commands/{excel2json/new_lists/models → create}/__init__.py +0 -0
  306. /dsp_tools/commands/{project → create/create_on_server}/__init__.py +0 -0
  307. /dsp_tools/commands/{project/create → create/models}/__init__.py +0 -0
  308. /dsp_tools/commands/{project/models → create/parsing}/__init__.py +0 -0
  309. /dsp_tools/commands/{xml_validate → create/serialisation}/__init__.py +0 -0
  310. /dsp_tools/commands/{xml_validate/models → excel2json/lists}/__init__.py +0 -0
  311. /dsp_tools/commands/{xml_validate/sparql → excel2json/lists/models}/__init__.py +0 -0
  312. /dsp_tools/commands/excel2json/{new_lists → lists}/models/deserialise.py +0 -0
  313. /dsp_tools/commands/{xmlupload/models/deserialise → get}/__init__.py +0 -0
  314. /dsp_tools/commands/{xmlupload/models/serialise → get/legacy_models}/__init__.py +0 -0
  315. /dsp_tools/commands/{project/models → get/legacy_models}/helpers.py +0 -0
  316. /dsp_tools/{models → commands/get/models}/__init__.py +0 -0
@@ -0,0 +1,1782 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Collection
4
+ from dataclasses import dataclass
5
+ from dataclasses import field
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from dsp_tools.error.xmllib_warnings import MessageInfo
10
+ from dsp_tools.error.xmllib_warnings_util import emit_xmllib_input_type_mismatch_warning
11
+ from dsp_tools.error.xmllib_warnings_util import raise_xmllib_input_error
12
+ from dsp_tools.xmllib.internal.input_converters import check_and_fix_collection_input
13
+ from dsp_tools.xmllib.internal.input_converters import check_and_fix_is_non_empty_string
14
+ from dsp_tools.xmllib.models.config_options import NewlineReplacement
15
+ from dsp_tools.xmllib.models.internal.file_values import AbstractFileValue
16
+ from dsp_tools.xmllib.models.internal.file_values import FileValue
17
+ from dsp_tools.xmllib.models.internal.file_values import IIIFUri
18
+ from dsp_tools.xmllib.models.internal.file_values import Metadata
19
+ from dsp_tools.xmllib.models.internal.migration_metadata import MigrationMetadata
20
+ from dsp_tools.xmllib.models.internal.values import BooleanValue
21
+ from dsp_tools.xmllib.models.internal.values import ColorValue
22
+ from dsp_tools.xmllib.models.internal.values import DateValue
23
+ from dsp_tools.xmllib.models.internal.values import DecimalValue
24
+ from dsp_tools.xmllib.models.internal.values import GeonameValue
25
+ from dsp_tools.xmllib.models.internal.values import IntValue
26
+ from dsp_tools.xmllib.models.internal.values import LinkValue
27
+ from dsp_tools.xmllib.models.internal.values import ListValue
28
+ from dsp_tools.xmllib.models.internal.values import Richtext
29
+ from dsp_tools.xmllib.models.internal.values import SimpleText
30
+ from dsp_tools.xmllib.models.internal.values import TimeValue
31
+ from dsp_tools.xmllib.models.internal.values import UriValue
32
+ from dsp_tools.xmllib.models.internal.values import Value
33
+ from dsp_tools.xmllib.models.licenses.recommended import License
34
+ from dsp_tools.xmllib.models.permissions import Permissions
35
+ from dsp_tools.xmllib.value_checkers import is_nonempty_value
36
+ from dsp_tools.xmllib.value_checkers import is_valid_resource_id
37
+
38
+ LIST_SEPARATOR = "\n - "
39
+
40
+
41
+ @dataclass
42
+ class Resource:
43
+ res_id: str
44
+ restype: str
45
+ label: str
46
+ values: list[Value] = field(default_factory=list)
47
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS
48
+ file_value: AbstractFileValue | None = None
49
+ migration_metadata: MigrationMetadata | None = None
50
+
51
+ @staticmethod
52
+ def create_new(
53
+ res_id: str,
54
+ restype: str,
55
+ label: str,
56
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
57
+ ) -> Resource:
58
+ """
59
+ Create a new resource.
60
+
61
+ Tip:
62
+ Use the helper function [`make_xsd_compatible_id()`](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/general-functions/#xmllib.general_functions.make_xsd_compatible_id)
63
+ to transform the resource ID into a format that meets the requirements for an XML ID.
64
+
65
+ Args:
66
+ res_id: resource ID
67
+ restype: resource type
68
+ label: resource label
69
+ permissions: optional permissions of this resource
70
+
71
+ Returns:
72
+ Resource
73
+
74
+ Examples:
75
+ ```python
76
+ resource = xmllib.Resource.create_new(
77
+ res_id="ID",
78
+ restype=":ResourceType",
79
+ label="label",
80
+ )
81
+ ```
82
+
83
+ ```python
84
+ # resource with restricted permissions
85
+ resource = xmllib.Resource.create_new(
86
+ res_id="ID",
87
+ restype=":ResourceType",
88
+ label="label",
89
+ permissions=xmllib.Permissions.PRIVATE,
90
+ )
91
+ ```
92
+ """
93
+ if not is_valid_resource_id(res_id):
94
+ res_id = str(res_id)
95
+ emit_xmllib_input_type_mismatch_warning(
96
+ expected_type="xsd:ID", value=res_id, res_id=res_id, value_field="resource ID"
97
+ )
98
+ if not is_nonempty_value(restype):
99
+ restype = str(restype)
100
+ emit_xmllib_input_type_mismatch_warning(
101
+ expected_type="resource type", value=restype, res_id=res_id, value_field="restype"
102
+ )
103
+ lbl = check_and_fix_is_non_empty_string(value=label, res_id=res_id, value_field="label")
104
+
105
+ return Resource(
106
+ res_id=res_id,
107
+ restype=restype,
108
+ label=lbl,
109
+ permissions=permissions,
110
+ )
111
+
112
+ #######################
113
+ # BooleanValue
114
+ #######################
115
+
116
+ def add_bool(
117
+ self,
118
+ prop_name: str,
119
+ value: bool | str | int | float,
120
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
121
+ comment: str | None = None,
122
+ ) -> Resource:
123
+ """
124
+ Add a boolean value to the resource.
125
+
126
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#boolean)
127
+
128
+ Conversions:
129
+ - The conversion is case-insensitive, meaning that the words can also be capitalised.
130
+ - `false`, `0`, `0.0`, `no`, `non`, `nein` -> `false`
131
+ - `true`, `1`, `1.0`, `yes`, `oui`, `ja` -> `true`
132
+
133
+ Args:
134
+ prop_name: name of the property
135
+ value: value to add
136
+ permissions: optional permissions of this value
137
+ comment: optional comment
138
+
139
+ Returns:
140
+ The original resource, with the added value
141
+
142
+ Examples:
143
+ ```python
144
+ resource = resource.add_bool(
145
+ prop_name=":propName",
146
+ value=True
147
+ )
148
+ ```
149
+ """
150
+ self.values.append(
151
+ BooleanValue.new(
152
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
153
+ )
154
+ )
155
+ return self
156
+
157
+ def add_bool_optional(
158
+ self,
159
+ prop_name: str,
160
+ value: Any,
161
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
162
+ comment: str | None = None,
163
+ ) -> Resource:
164
+ """
165
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
166
+
167
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#boolean)
168
+
169
+ Conversions:
170
+ - The conversion is case-insensitive, meaning that the words can also be capitalised.
171
+ - `false`, `0`, `0.0`, `no`, `non`, `nein` -> `false`
172
+ - `true`, `1`, `1.0`, `yes`, `oui`, `ja` -> `true`
173
+
174
+ Args:
175
+ prop_name: name of the property
176
+ value: value to add or empty value
177
+ permissions: optional permissions of this value
178
+ comment: optional comment
179
+
180
+ Returns:
181
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
182
+
183
+ Examples:
184
+ ```python
185
+ resource = resource.add_bool_optional(
186
+ prop_name=":propName",
187
+ value=True
188
+ )
189
+ ```
190
+
191
+ ```python
192
+ resource = resource.add_bool_optional(
193
+ prop_name=":propName",
194
+ value=None,
195
+ )
196
+ ```
197
+ """
198
+ if is_nonempty_value(value):
199
+ self.add_bool(value=value, prop_name=prop_name, permissions=permissions, comment=comment)
200
+ return self
201
+
202
+ #######################
203
+ # ColorValue
204
+ #######################
205
+
206
+ def add_color(
207
+ self,
208
+ prop_name: str,
209
+ value: str,
210
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
211
+ comment: str | None = None,
212
+ ) -> Resource:
213
+ """
214
+ Add a color value to the resource.
215
+
216
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#color)
217
+
218
+ Args:
219
+ prop_name: name of the property
220
+ value: value to add
221
+ permissions: optional permissions of this value
222
+ comment: optional comment
223
+
224
+ Returns:
225
+ The original resource, with the added value
226
+
227
+ Examples:
228
+ ```python
229
+ resource = resource.add_color(
230
+ prop_name=":propName",
231
+ value="#00ff66",
232
+ )
233
+ ```
234
+ """
235
+ self.values.append(
236
+ ColorValue.new(
237
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
238
+ )
239
+ )
240
+ return self
241
+
242
+ def add_color_multiple(
243
+ self,
244
+ prop_name: str,
245
+ values: Collection[str],
246
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
247
+ comment: str | None = None,
248
+ ) -> Resource:
249
+ """
250
+ Add several color values to the resource.
251
+
252
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#color)
253
+
254
+ Args:
255
+ prop_name: name of the property
256
+ values: values to add
257
+ permissions: optional permissions of this value
258
+ comment: optional comment
259
+
260
+ Returns:
261
+ The original resource, with the added values
262
+
263
+ Examples:
264
+ ```python
265
+ resource = resource.add_color_multiple(
266
+ prop_name=":propName",
267
+ values=["#00ff66", "#00ff55"],
268
+ )
269
+ ```
270
+ """
271
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
272
+ for v in vals:
273
+ self.add_color(prop_name, v, permissions, comment)
274
+ return self
275
+
276
+ def add_color_optional(
277
+ self,
278
+ prop_name: str,
279
+ value: Any,
280
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
281
+ comment: str | None = None,
282
+ ) -> Resource:
283
+ """
284
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
285
+
286
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#color)
287
+
288
+ Args:
289
+ prop_name: name of the property
290
+ value: value to add or empty value
291
+ permissions: optional permissions of this value
292
+ comment: optional comment
293
+
294
+ Returns:
295
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
296
+
297
+ Examples:
298
+ ```python
299
+ resource = resource.add_color_optional(
300
+ prop_name=":propName",
301
+ value="#00ff66",
302
+ )
303
+ ```
304
+
305
+ ```python
306
+ resource = resource.add_color_optional(
307
+ prop_name=":propName",
308
+ value=None,
309
+ )
310
+ ```
311
+ """
312
+ if is_nonempty_value(value):
313
+ self.add_color(prop_name, value, permissions, comment)
314
+ return self
315
+
316
+ #######################
317
+ # DateValue
318
+ #######################
319
+
320
+ def add_date(
321
+ self,
322
+ prop_name: str,
323
+ value: str,
324
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
325
+ comment: str | None = None,
326
+ ) -> Resource:
327
+ """
328
+ Add a date value to the resource.
329
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#date)
330
+
331
+ Tip:
332
+ Use one of the helper functions [`reformat_date()`](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/general-functions/#xmllib.general_functions.reformat_date)
333
+ or [`find_dates_in_string()`](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/general-functions/#xmllib.general_functions.find_dates_in_string)
334
+ to transform a date into the DSP conform format.
335
+
336
+ Args:
337
+ prop_name: name of the property
338
+ value: value to add
339
+ permissions: optional permissions of this value
340
+ comment: optional comment
341
+
342
+ Returns:
343
+ The original resource, with the added value
344
+
345
+ Examples:
346
+ ```python
347
+ resource = resource.add_date(
348
+ prop_name=":propName",
349
+ value="GREGORIAN:CE:2014-01-31:CE:2014-01-31",
350
+ )
351
+ ```
352
+ """
353
+ self.values.append(
354
+ DateValue.new(
355
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
356
+ )
357
+ )
358
+ return self
359
+
360
+ def add_date_multiple(
361
+ self,
362
+ prop_name: str,
363
+ values: Collection[str],
364
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
365
+ comment: str | None = None,
366
+ ) -> Resource:
367
+ """
368
+ Add several date values to the resource.
369
+
370
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#date)
371
+
372
+ Args:
373
+ prop_name: name of the property
374
+ values: values to add
375
+ permissions: optional permissions of this value
376
+ comment: optional comment
377
+
378
+ Returns:
379
+ The original resource, with the added values
380
+
381
+ Examples:
382
+ ```python
383
+ resource = resource.add_date_multiple(
384
+ prop_name=":propName",
385
+ values=["GREGORIAN:CE:2014-01-31:CE:2014-01-31", "CE:1849:CE:1850"],
386
+ )
387
+ ```
388
+ """
389
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
390
+ for v in vals:
391
+ self.add_date(prop_name, v, permissions, comment)
392
+ return self
393
+
394
+ def add_date_optional(
395
+ self,
396
+ prop_name: str,
397
+ value: Any,
398
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
399
+ comment: str | None = None,
400
+ ) -> Resource:
401
+ """
402
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
403
+
404
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#date)
405
+
406
+ Args:
407
+ prop_name: name of the property
408
+ value: value to add or empty value
409
+ permissions: optional permissions of this value
410
+ comment: optional comment
411
+
412
+ Returns:
413
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
414
+
415
+ Examples:
416
+ ```python
417
+ resource = resource.add_date_optional(
418
+ prop_name=":propName",
419
+ value="CE:1849:CE:1850",
420
+ )
421
+ ```
422
+
423
+ ```python
424
+ resource = resource.add_date_optional(
425
+ prop_name=":propName",
426
+ value=None,
427
+ )
428
+ ```
429
+ """
430
+ if is_nonempty_value(value):
431
+ self.add_date(prop_name, value, permissions, comment)
432
+ return self
433
+
434
+ #######################
435
+ # DecimalValue
436
+ #######################
437
+
438
+ def add_decimal(
439
+ self,
440
+ prop_name: str,
441
+ value: float | int | str,
442
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
443
+ comment: str | None = None,
444
+ ) -> Resource:
445
+ """
446
+ Add a decimal value to the resource.
447
+ If the value is provided as string, it must be convertible to integer or float.
448
+
449
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#decimal)
450
+
451
+ Args:
452
+ prop_name: name of the property
453
+ value: value to add
454
+ permissions: optional permissions of this value
455
+ comment: optional comment
456
+
457
+ Returns:
458
+ The original resource, with the added value
459
+
460
+ Examples:
461
+ ```python
462
+ resource = resource.add_decimal(
463
+ prop_name=":propName",
464
+ value=1.4,
465
+ )
466
+ ```
467
+ """
468
+ self.values.append(
469
+ DecimalValue.new(
470
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
471
+ )
472
+ )
473
+ return self
474
+
475
+ def add_decimal_multiple(
476
+ self,
477
+ prop_name: str,
478
+ values: Collection[float | int | str],
479
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
480
+ comment: str | None = None,
481
+ ) -> Resource:
482
+ """
483
+ Add several decimal values to the resource.
484
+ If the values are provided as string, they must be convertible to integer or float.
485
+
486
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#decimal)
487
+
488
+ Args:
489
+ prop_name: name of the property
490
+ values: values to add
491
+ permissions: optional permissions of this value
492
+ comment: optional comment
493
+
494
+ Returns:
495
+ The original resource, with the added values
496
+
497
+ Examples:
498
+ ```python
499
+ resource = resource.add_decimal_multiple(
500
+ prop_name=":propName",
501
+ values=[1.4, 2.9],
502
+ )
503
+ ```
504
+ """
505
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
506
+ for v in vals:
507
+ self.add_decimal(prop_name, v, permissions, comment)
508
+ return self
509
+
510
+ def add_decimal_optional(
511
+ self,
512
+ prop_name: str,
513
+ value: Any,
514
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
515
+ comment: str | None = None,
516
+ ) -> Resource:
517
+ """
518
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
519
+ If the value is provided as string, it must be convertible to integer or float.
520
+
521
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#decimal)
522
+
523
+ Args:
524
+ prop_name: name of the property
525
+ value: value to add or empty value
526
+ permissions: optional permissions of this value
527
+ comment: optional comment
528
+
529
+ Returns:
530
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
531
+
532
+ Examples:
533
+ ```python
534
+ resource = resource.add_decimal_optional(
535
+ prop_name=":propName",
536
+ value=1.0,
537
+ )
538
+ ```
539
+
540
+ ```python
541
+ resource = resource.add_decimal_optional(
542
+ prop_name=":propName",
543
+ value=None,
544
+ )
545
+ ```
546
+ """
547
+ if is_nonempty_value(value):
548
+ self.add_decimal(prop_name, value, permissions, comment)
549
+ return self
550
+
551
+ #######################
552
+ # GeonameValue
553
+ #######################
554
+
555
+ def add_geoname(
556
+ self,
557
+ prop_name: str,
558
+ value: int | str,
559
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
560
+ comment: str | None = None,
561
+ ) -> Resource:
562
+ """
563
+ Add a [geonames.org](https://www.geonames.org/) value to the resource.
564
+ The [geonames.org](https://www.geonames.org/) identifier must be provided as integer
565
+ or string that is convertible to integer.
566
+
567
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#geoname)
568
+
569
+
570
+ Args:
571
+ prop_name: name of the property
572
+ value: value to add
573
+ permissions: optional permissions of this value
574
+ comment: optional comment
575
+
576
+ Returns:
577
+ The original resource, with the added value
578
+
579
+ Examples:
580
+ ```python
581
+ resource = resource.add_geoname(
582
+ prop_name=":propName",
583
+ value="2761369",
584
+ )
585
+ ```
586
+ """
587
+ self.values.append(
588
+ GeonameValue.new(
589
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
590
+ )
591
+ )
592
+ return self
593
+
594
+ def add_geoname_multiple(
595
+ self,
596
+ prop_name: str,
597
+ values: Collection[int | str],
598
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
599
+ comment: str | None = None,
600
+ ) -> Resource:
601
+ """
602
+ Add several [geonames.org](https://www.geonames.org/) values to the resource.
603
+ The [geonames.org](https://www.geonames.org/) identifiers must be provided as integers
604
+ or strings that are convertible to integers.
605
+
606
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#geoname)
607
+
608
+ Args:
609
+ prop_name: name of the property
610
+ values: values to add
611
+ permissions: optional permissions of this value
612
+ comment: optional comment
613
+
614
+ Returns:
615
+ The original resource, with the added values
616
+
617
+ Examples:
618
+ ```python
619
+ resource = resource.add_geoname_multiple(
620
+ prop_name=":propName",
621
+ values=["2761369", "2661604"],
622
+ )
623
+ ```
624
+ """
625
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
626
+ for v in vals:
627
+ self.add_geoname(prop_name, v, permissions, comment)
628
+ return self
629
+
630
+ def add_geoname_optional(
631
+ self,
632
+ prop_name: str,
633
+ value: Any,
634
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
635
+ comment: str | None = None,
636
+ ) -> Resource:
637
+ """
638
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
639
+ The [geonames.org](https://www.geonames.org/) identifier must be provided as integer
640
+ or string that is convertible to integer.
641
+
642
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#geoname)
643
+
644
+ Args:
645
+ prop_name: name of the property
646
+ value: value to add or empty value
647
+ permissions: optional permissions of this value
648
+ comment: optional comment
649
+
650
+ Returns:
651
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
652
+
653
+ Examples:
654
+ ```python
655
+ resource = resource.add_geoname_optional(
656
+ prop_name=":propName",
657
+ value="2661604",
658
+ )
659
+ ```
660
+
661
+ ```python
662
+ resource = resource.add_geoname_optional(
663
+ prop_name=":propName",
664
+ value=None,
665
+ )
666
+ ```
667
+ """
668
+ if is_nonempty_value(value):
669
+ self.add_geoname(prop_name, value, permissions, comment)
670
+ return self
671
+
672
+ #######################
673
+ # IntValue
674
+ #######################
675
+
676
+ def add_integer(
677
+ self,
678
+ prop_name: str,
679
+ value: int | str,
680
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
681
+ comment: str | None = None,
682
+ ) -> Resource:
683
+ """
684
+ Add an integer value to the resource.
685
+ If the value is provided as string, it must be convertible to integer.
686
+
687
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#integer)
688
+
689
+ Args:
690
+ prop_name: name of the property
691
+ value: value to add
692
+ permissions: optional permissions of this value
693
+ comment: optional comment
694
+
695
+ Returns:
696
+ The original resource, with the added value
697
+
698
+ Examples:
699
+ ```python
700
+ resource = resource.add_integer(
701
+ prop_name=":propName",
702
+ value=399,
703
+ )
704
+ ```
705
+ """
706
+ self.values.append(
707
+ IntValue.new(
708
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
709
+ )
710
+ )
711
+ return self
712
+
713
+ def add_integer_multiple(
714
+ self,
715
+ prop_name: str,
716
+ values: Collection[int | str],
717
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
718
+ comment: str | None = None,
719
+ ) -> Resource:
720
+ """
721
+ Add several integer values to the resource.
722
+ If the values are provided as string, they must be convertible to integer.
723
+
724
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#integer)
725
+
726
+ Args:
727
+ prop_name: name of the property
728
+ values: values to add
729
+ permissions: optional permissions of this value
730
+ comment: optional comment
731
+
732
+ Returns:
733
+ The original resource, with the added values
734
+
735
+ Examples:
736
+ ```python
737
+ resource = resource.add_integer_multiple(
738
+ prop_name=":propName",
739
+ values=[24, "66"],
740
+ )
741
+ ```
742
+ """
743
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
744
+ for v in vals:
745
+ self.add_integer(prop_name, v, permissions, comment)
746
+ return self
747
+
748
+ def add_integer_optional(
749
+ self,
750
+ prop_name: str,
751
+ value: Any,
752
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
753
+ comment: str | None = None,
754
+ ) -> Resource:
755
+ """
756
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
757
+ If the value is provided as string, it must be convertible to integer.
758
+
759
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#integer)
760
+
761
+ Args:
762
+ prop_name: name of the property
763
+ value: value to add or empty value
764
+ permissions: optional permissions of this value
765
+ comment: optional comment
766
+
767
+ Returns:
768
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
769
+
770
+ Examples:
771
+ ```python
772
+ resource = resource.add_integer_optional(
773
+ prop_name=":propName",
774
+ value="2604",
775
+ )
776
+ ```
777
+
778
+ ```python
779
+ resource = resource.add_integer_optional(
780
+ prop_name=":propName",
781
+ value=None,
782
+ )
783
+ ```
784
+ """
785
+ if is_nonempty_value(value):
786
+ self.add_integer(prop_name, value, permissions, comment)
787
+ return self
788
+
789
+ #######################
790
+ # LinkValue
791
+ #######################
792
+
793
+ def add_link(
794
+ self,
795
+ prop_name: str,
796
+ value: str,
797
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
798
+ comment: str | None = None,
799
+ ) -> Resource:
800
+ """
801
+ Add a link value to the resource, in the form of an ID of another resource.
802
+
803
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#resptr)
804
+
805
+ Args:
806
+ prop_name: name of the property
807
+ value: target resource ID
808
+ permissions: optional permissions of this value
809
+ comment: optional comment
810
+
811
+ Returns:
812
+ The original resource, with the added value
813
+
814
+ Examples:
815
+ ```python
816
+ resource = resource.add_link(
817
+ prop_name=":propName",
818
+ value="target_resource_id",
819
+ )
820
+ ```
821
+ """
822
+ self.values.append(
823
+ LinkValue.new(
824
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
825
+ )
826
+ )
827
+ return self
828
+
829
+ def add_link_multiple(
830
+ self,
831
+ prop_name: str,
832
+ values: Collection[str],
833
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
834
+ comment: str | None = None,
835
+ ) -> Resource:
836
+ """
837
+ Add several link values to the resource, in the form of IDs of other resources.
838
+
839
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#resptr)
840
+
841
+ Args:
842
+ prop_name: name of the property
843
+ values: list of target resources IDs
844
+ permissions: optional permissions of this value
845
+ comment: optional comment
846
+
847
+ Returns:
848
+ The original resource, with the added values
849
+
850
+ Examples:
851
+ ```python
852
+ resource = resource.add_link_multiple(
853
+ prop_name=":propName",
854
+ values=["target_resource_id_1", "target_resource_id_2"],
855
+ )
856
+ ```
857
+ """
858
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
859
+ for v in vals:
860
+ self.add_link(prop_name, v, permissions, comment)
861
+ return self
862
+
863
+ def add_link_optional(
864
+ self,
865
+ prop_name: str,
866
+ value: Any,
867
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
868
+ comment: str | None = None,
869
+ ) -> Resource:
870
+ """
871
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
872
+ If non-empty, the value must be an ID of another resource.
873
+
874
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#resptr)
875
+
876
+ Args:
877
+ prop_name: name of the property
878
+ value: target resource ID or empty value
879
+ permissions: optional permissions of this value
880
+ comment: optional comment
881
+
882
+ Returns:
883
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
884
+
885
+ Examples:
886
+ ```python
887
+ resource = resource.add_link_optional(
888
+ prop_name=":propName",
889
+ value="target_resource_id",
890
+ )
891
+ ```
892
+
893
+ ```python
894
+ resource = resource.add_link_optional(
895
+ prop_name=":propName",
896
+ value=None,
897
+ )
898
+ ```
899
+ """
900
+ if is_nonempty_value(value):
901
+ self.add_link(prop_name, value, permissions, comment)
902
+ return self
903
+
904
+ #######################
905
+ # ListValue
906
+ #######################
907
+
908
+ def add_list(
909
+ self,
910
+ prop_name: str,
911
+ list_name: str | int | float,
912
+ value: str | int | float,
913
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
914
+ comment: str | None = None,
915
+ ) -> Resource:
916
+ """
917
+ Add a list value to the resource, i.e. a name of a list node.
918
+
919
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#list)
920
+
921
+ Tip:
922
+ Use the helper [`ListLookup`](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/general-functions/#xmllib.general_functions.ListLookup)
923
+ to retrieve the correct list name based on the label.
924
+
925
+ Args:
926
+ prop_name: name of the property
927
+ list_name: name of the list (N.B. not the label, but the name of the list)
928
+ value: name of a list node (N.B. not the label, but the name of the list node)
929
+ permissions: optional permissions of this value
930
+ comment: optional comment
931
+
932
+ Returns:
933
+ The original resource, with the added value
934
+
935
+ Examples:
936
+ ```python
937
+ resource = resource.add_list(
938
+ prop_name=":propName",
939
+ list_name="listName",
940
+ value="nodeName",
941
+ )
942
+ ```
943
+ """
944
+ self.values.append(
945
+ ListValue.new(
946
+ value=value,
947
+ list_name=list_name,
948
+ prop_name=prop_name,
949
+ permissions=permissions,
950
+ comment=comment,
951
+ resource_id=self.res_id,
952
+ )
953
+ )
954
+ return self
955
+
956
+ def add_list_multiple(
957
+ self,
958
+ prop_name: str,
959
+ list_name: str | int | float,
960
+ values: Collection[str | int | float],
961
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
962
+ comment: str | None = None,
963
+ ) -> Resource:
964
+ """
965
+ Add several list values to the resource, i.e. names of list nodes.
966
+
967
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#list)
968
+
969
+ Args:
970
+ prop_name: name of the property
971
+ list_name: name of the list (N.B. not the label, but the name of the list)
972
+ values: names of list nodes (N.B. not the labels, but the names of the list nodes)
973
+ permissions: optional permissions of this value
974
+ comment: optional comment
975
+
976
+ Returns:
977
+ The original resource, with the added values
978
+
979
+ Examples:
980
+ ```python
981
+ resource = resource.add_list_multiple(
982
+ prop_name=":propName",
983
+ list_name="listName",
984
+ values=["nodeName_1", "nodeName_2"],
985
+ )
986
+ ```
987
+ """
988
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
989
+ for v in vals:
990
+ self.add_list(prop_name, list_name, v, permissions, comment)
991
+ return self
992
+
993
+ def add_list_optional(
994
+ self,
995
+ prop_name: str,
996
+ list_name: str | int | float,
997
+ value: Any,
998
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
999
+ comment: str | None = None,
1000
+ ) -> Resource:
1001
+ """
1002
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
1003
+
1004
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#list)
1005
+
1006
+ Args:
1007
+ prop_name: name of the property
1008
+ list_name: name of the list (N.B. not the label, but the name of the list)
1009
+ value: name of a list node (N.B. not the label, but the name of the list node) or empty value
1010
+ permissions: optional permissions of this value
1011
+ comment: optional comment
1012
+
1013
+ Returns:
1014
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
1015
+
1016
+ Examples:
1017
+ ```python
1018
+ resource = resource.add_list_optional(
1019
+ prop_name=":propName",
1020
+ list_name="listName",
1021
+ value="nodeName",
1022
+ )
1023
+ ```
1024
+
1025
+ ```python
1026
+ resource = resource.add_list_optional(
1027
+ prop_name=":propName",
1028
+ list_name="listName",
1029
+ value=None,
1030
+ )
1031
+ ```
1032
+ """
1033
+ if is_nonempty_value(value):
1034
+ self.add_list(prop_name, list_name, value, permissions, comment)
1035
+ return self
1036
+
1037
+ #######################
1038
+ # TextValue: SimpleText
1039
+ #######################
1040
+
1041
+ def add_simpletext(
1042
+ self,
1043
+ prop_name: str,
1044
+ value: str,
1045
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1046
+ comment: str | None = None,
1047
+ ) -> Resource:
1048
+ """
1049
+ Add a simple text value to the resource.
1050
+
1051
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1052
+
1053
+ Args:
1054
+ prop_name: name of the property
1055
+ value: value to add
1056
+ permissions: optional permissions of this value
1057
+ comment: optional comment
1058
+
1059
+ Returns:
1060
+ The original resource, with the added value
1061
+
1062
+ Examples:
1063
+ ```python
1064
+ resource = resource.add_simpletext(
1065
+ prop_name=":propName",
1066
+ value="text",
1067
+ )
1068
+ ```
1069
+ """
1070
+ self.values.append(
1071
+ SimpleText.new(
1072
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
1073
+ )
1074
+ )
1075
+ return self
1076
+
1077
+ def add_simpletext_multiple(
1078
+ self,
1079
+ prop_name: str,
1080
+ values: Collection[str],
1081
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1082
+ comment: str | None = None,
1083
+ ) -> Resource:
1084
+ """
1085
+ Add several simple text values to the resource.
1086
+
1087
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1088
+
1089
+ Args:
1090
+ prop_name: name of the property
1091
+ values: values to add
1092
+ permissions: optional permissions of this value
1093
+ comment: optional comment
1094
+
1095
+ Returns:
1096
+ The original resource, with the added values
1097
+
1098
+ Examples:
1099
+ ```python
1100
+ resource = resource.add_simpletext_multiple(
1101
+ prop_name=":propName",
1102
+ values=["text 1", "text 2"],
1103
+ )
1104
+ ```
1105
+ """
1106
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
1107
+ for v in vals:
1108
+ self.add_simpletext(prop_name, v, permissions, comment)
1109
+ return self
1110
+
1111
+ def add_simpletext_optional(
1112
+ self,
1113
+ prop_name: str,
1114
+ value: Any,
1115
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1116
+ comment: str | None = None,
1117
+ ) -> Resource:
1118
+ """
1119
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
1120
+
1121
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1122
+
1123
+ Args:
1124
+ prop_name: name of the property
1125
+ value: value to add or empty value
1126
+ permissions: optional permissions of this value
1127
+ comment: optional comment
1128
+
1129
+ Returns:
1130
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
1131
+
1132
+ Examples:
1133
+ ```python
1134
+ resource = resource.add_simpletext_optional(
1135
+ prop_name=":propName",
1136
+ value="text",
1137
+ )
1138
+ ```
1139
+
1140
+ ```python
1141
+ resource = resource.add_simpletext_optional(
1142
+ prop_name=":propName",
1143
+ value=None,
1144
+ )
1145
+ ```
1146
+ """
1147
+ if is_nonempty_value(value):
1148
+ self.add_simpletext(prop_name, value, permissions, comment)
1149
+ return self
1150
+
1151
+ #######################
1152
+ # TextValue: Textarea
1153
+ #######################
1154
+
1155
+ def add_textarea(
1156
+ self,
1157
+ prop_name: str,
1158
+ value: str,
1159
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1160
+ comment: str | None = None,
1161
+ ) -> Resource:
1162
+ """
1163
+ Add a textarea value to the resource.
1164
+
1165
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1166
+
1167
+ Args:
1168
+ prop_name: name of the property
1169
+ value: value to add
1170
+ permissions: optional permissions of this value
1171
+ comment: optional comment
1172
+
1173
+ Returns:
1174
+ The original resource, with the added value
1175
+
1176
+ Examples:
1177
+ ```python
1178
+ resource = resource.add_textarea(
1179
+ prop_name=":propName",
1180
+ value="text",
1181
+ )
1182
+ ```
1183
+ """
1184
+ self.add_simpletext(prop_name, value, permissions, comment)
1185
+ return self
1186
+
1187
+ def add_textarea_multiple(
1188
+ self,
1189
+ prop_name: str,
1190
+ values: Collection[str],
1191
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1192
+ comment: str | None = None,
1193
+ ) -> Resource:
1194
+ """
1195
+ Add several textarea values to the resource.
1196
+
1197
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1198
+
1199
+ Args:
1200
+ prop_name: name of the property
1201
+ values: values to add
1202
+ permissions: optional permissions of this value
1203
+ comment: optional comment
1204
+
1205
+ Returns:
1206
+ The original resource, with the added values
1207
+
1208
+ Examples:
1209
+ ```python
1210
+ resource = resource.add_textarea_multiple(
1211
+ prop_name=":propName",
1212
+ values=["text 1", "text 2"],
1213
+ )
1214
+ ```
1215
+ """
1216
+ self.add_simpletext_multiple(prop_name, values, permissions, comment)
1217
+ return self
1218
+
1219
+ def add_textarea_optional(
1220
+ self,
1221
+ prop_name: str,
1222
+ value: Any,
1223
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1224
+ comment: str | None = None,
1225
+ ) -> Resource:
1226
+ """
1227
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
1228
+
1229
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1230
+
1231
+ Args:
1232
+ prop_name: name of the property
1233
+ value: value to add or empty value
1234
+ permissions: optional permissions of this value
1235
+ comment: optional comment
1236
+
1237
+ Returns:
1238
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
1239
+
1240
+ Examples:
1241
+ ```python
1242
+ resource = resource.add_textarea_optional(
1243
+ prop_name=":propName",
1244
+ value="text",
1245
+ )
1246
+ ```
1247
+
1248
+ ```python
1249
+ resource = resource.add_textarea_optional(
1250
+ prop_name=":propName",
1251
+ value=None,
1252
+ )
1253
+ ```
1254
+ """
1255
+ self.add_simpletext_optional(prop_name, value, permissions, comment)
1256
+ return self
1257
+
1258
+ #######################
1259
+ # TextValue: Richtext
1260
+ #######################
1261
+
1262
+ def add_richtext(
1263
+ self,
1264
+ prop_name: str,
1265
+ value: str,
1266
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1267
+ comment: str | None = None,
1268
+ newline_replacement: NewlineReplacement = NewlineReplacement.LINEBREAK,
1269
+ ) -> Resource:
1270
+ """
1271
+ Add a rich text value to the resource.
1272
+ Rich text values must be provided as strings, potentially containing DSP Standard Standoff Markup XML tags
1273
+ as [documented here.](https://docs.dasch.swiss/latest/DSP-API/03-endpoints/api-v2/text/standard-standoff/)
1274
+ Only the documented tags are allowed.
1275
+
1276
+ Conversions:
1277
+ By default, replace newline characters inside the text value with `<br/>`, which preserves the linebreak.
1278
+ Without this replacement, the newline would disappear, because `\\n` is meaningless in an XML file.
1279
+ [Click here for more details](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/value-converters/#xmllib.value_converters.replace_newlines_with_tags)
1280
+
1281
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1282
+
1283
+ Args:
1284
+ prop_name: name of the property
1285
+ value: value to add
1286
+ permissions: optional permissions of this value
1287
+ comment: optional comment
1288
+ newline_replacement: options how to deal with `\\n` inside the text value. Default: replace with `<br/>`
1289
+
1290
+ Returns:
1291
+ The original resource, with the added value
1292
+
1293
+ Examples:
1294
+ ```python
1295
+ resource = resource.add_richtext(
1296
+ prop_name=":propName",
1297
+ value="line 1\\nline 2",
1298
+ )
1299
+ ```
1300
+
1301
+ ```python
1302
+ # changing the replacement options for newlines `\\n`
1303
+ resource = resource.add_richtext(
1304
+ prop_name=":propName",
1305
+ value="line 1\\nline 2",
1306
+ newline_replacement=xmllib.NewlineReplacement.PARAGRAPH,
1307
+ )
1308
+ ```
1309
+ """
1310
+ self.values.append(
1311
+ Richtext.new(
1312
+ value=value,
1313
+ prop_name=prop_name,
1314
+ permissions=permissions,
1315
+ comment=comment,
1316
+ resource_id=self.res_id,
1317
+ newline_replacement=newline_replacement,
1318
+ )
1319
+ )
1320
+ return self
1321
+
1322
+ def add_richtext_multiple(
1323
+ self,
1324
+ prop_name: str,
1325
+ values: Collection[str],
1326
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1327
+ comment: str | None = None,
1328
+ newline_replacement: NewlineReplacement = NewlineReplacement.LINEBREAK,
1329
+ ) -> Resource:
1330
+ """
1331
+ Add several rich text values to the resource.
1332
+ Rich text values must be provided as strings, potentially containing DSP Standard Standoff Markup XML tags
1333
+ as [documented here.](https://docs.dasch.swiss/latest/DSP-API/03-endpoints/api-v2/text/standard-standoff/)
1334
+ Only the documented tags are allowed.
1335
+
1336
+ Conversions:
1337
+ By default, replace newline characters inside the text value with `<br/>`, which preserves the linebreak.
1338
+ Without this replacement, the newline would disappear, because `\\n` is meaningless in an XML file.
1339
+ [Click here for more details](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/value-converters/#xmllib.value_converters.replace_newlines_with_tags)
1340
+
1341
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1342
+
1343
+ Args:
1344
+ prop_name: name of the property
1345
+ values: values to add
1346
+ permissions: optional permissions of this value
1347
+ comment: optional comment
1348
+ newline_replacement: options how to deal with `\\n` inside the text value. Default: replace with `<br/>`
1349
+
1350
+ Returns:
1351
+ The original resource, with the added values
1352
+
1353
+ Examples:
1354
+ ```python
1355
+ resource = resource.add_richtext_multiple(
1356
+ prop_name=":propName",
1357
+ values=["<strong>Bold text</strong>", "text 2"],
1358
+ )
1359
+ ```
1360
+ """
1361
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
1362
+ self.values.extend(
1363
+ [
1364
+ Richtext.new(
1365
+ value=v,
1366
+ prop_name=prop_name,
1367
+ permissions=permissions,
1368
+ comment=comment,
1369
+ resource_id=self.res_id,
1370
+ newline_replacement=newline_replacement,
1371
+ )
1372
+ for v in vals
1373
+ ]
1374
+ )
1375
+ return self
1376
+
1377
+ def add_richtext_optional(
1378
+ self,
1379
+ prop_name: str,
1380
+ value: Any,
1381
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1382
+ comment: str | None = None,
1383
+ newline_replacement: NewlineReplacement = NewlineReplacement.LINEBREAK,
1384
+ ) -> Resource:
1385
+ """
1386
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
1387
+ Rich text values must be provided as strings, potentially containing DSP Standard Standoff Markup XML tags
1388
+ as [documented here.](https://docs.dasch.swiss/latest/DSP-API/03-endpoints/api-v2/text/standard-standoff/)
1389
+ Only the documented tags are allowed.
1390
+
1391
+ Conversions:
1392
+ By default, replace newline characters inside the text value with `<br/>`, which preserves the linebreak.
1393
+ Without this replacement, the newline would disappear, because `\\n` is meaningless in an XML file.
1394
+ [Click here for more details](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/value-converters/#xmllib.value_converters.replace_newlines_with_tags)
1395
+
1396
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#text)
1397
+
1398
+ Args:
1399
+ prop_name: name of the property
1400
+ value: value to add or empty value
1401
+ permissions: optional permissions of this value
1402
+ comment: optional comment
1403
+ newline_replacement: options how to deal with `\\n` inside the text value. Default: replace with `<br/>`
1404
+
1405
+ Returns:
1406
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
1407
+
1408
+ Examples:
1409
+ ```python
1410
+ resource = resource.add_richtext_optional(
1411
+ prop_name=":propName",
1412
+ value="<strong>Bold text</strong>",
1413
+ )
1414
+ ```
1415
+
1416
+ ```python
1417
+ resource = resource.add_richtext_optional(
1418
+ prop_name=":propName",
1419
+ value=None,
1420
+ )
1421
+ ```
1422
+ """
1423
+ if is_nonempty_value(value):
1424
+ return self.add_richtext(prop_name, value, permissions, comment, newline_replacement)
1425
+ return self
1426
+
1427
+ #######################
1428
+ # TimeValue
1429
+ #######################
1430
+
1431
+ def add_time(
1432
+ self,
1433
+ prop_name: str,
1434
+ value: str,
1435
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1436
+ comment: str | None = None,
1437
+ ) -> Resource:
1438
+ """
1439
+ Add a time value to the resource.
1440
+
1441
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#time)
1442
+
1443
+ Args:
1444
+ prop_name: name of the property
1445
+ value: value to add
1446
+ permissions: optional permissions of this value
1447
+ comment: optional comment
1448
+
1449
+ Returns:
1450
+ The original resource, with the added value
1451
+
1452
+ Examples:
1453
+ ```python
1454
+ resource = resource.add_time(
1455
+ prop_name=":propName",
1456
+ value="2019-10-23T13:45:12Z",
1457
+ )
1458
+ ```
1459
+ """
1460
+ self.values.append(
1461
+ TimeValue.new(
1462
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
1463
+ )
1464
+ )
1465
+ return self
1466
+
1467
+ def add_time_multiple(
1468
+ self,
1469
+ prop_name: str,
1470
+ values: Collection[str],
1471
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1472
+ comment: str | None = None,
1473
+ ) -> Resource:
1474
+ """
1475
+ Add several time values to the resource.
1476
+
1477
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#time)
1478
+
1479
+ Args:
1480
+ prop_name: name of the property
1481
+ values: values to add
1482
+ permissions: optional permissions of this value
1483
+ comment: optional comment
1484
+
1485
+ Returns:
1486
+ The original resource, with the added values
1487
+
1488
+ Examples:
1489
+ ```python
1490
+ resource = resource.add_time_multiple(
1491
+ prop_name=":propName",
1492
+ values=["2019-10-23T13:45:12Z", "2009-10-10T12:00:00-05:00"],
1493
+ )
1494
+ ```
1495
+ """
1496
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
1497
+ for v in vals:
1498
+ self.add_time(prop_name, v, permissions, comment)
1499
+ return self
1500
+
1501
+ def add_time_optional(
1502
+ self,
1503
+ prop_name: str,
1504
+ value: Any,
1505
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1506
+ comment: str | None = None,
1507
+ ) -> Resource:
1508
+ """
1509
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
1510
+
1511
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#time)
1512
+
1513
+ Args:
1514
+ prop_name: name of the property
1515
+ value: value to add or empty value
1516
+ permissions: optional permissions of this value
1517
+ comment: optional comment
1518
+
1519
+ Returns:
1520
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
1521
+
1522
+ Examples:
1523
+ ```python
1524
+ resource = resource.add_time_optional(
1525
+ prop_name=":propName",
1526
+ value="2019-10-23T13:45:12Z",
1527
+ )
1528
+ ```
1529
+
1530
+ ```python
1531
+ resource = resource.add_time_optional(
1532
+ prop_name=":propName",
1533
+ value=None,
1534
+ )
1535
+ ```
1536
+ """
1537
+ if is_nonempty_value(value):
1538
+ self.add_time(prop_name, value, permissions, comment)
1539
+ return self
1540
+
1541
+ #######################
1542
+ # UriValue
1543
+ #######################
1544
+
1545
+ def add_uri(
1546
+ self,
1547
+ prop_name: str,
1548
+ value: str,
1549
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1550
+ comment: str | None = None,
1551
+ ) -> Resource:
1552
+ """
1553
+ Add a URI value to the resource.
1554
+
1555
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#uri)
1556
+
1557
+ Args:
1558
+ prop_name: name of the property
1559
+ value: value to add
1560
+ permissions: optional permissions of this value
1561
+ comment: optional comment
1562
+
1563
+ Returns:
1564
+ The original resource, with the added value
1565
+
1566
+ Examples:
1567
+ ```python
1568
+ resource = resource.add_uri(
1569
+ prop_name=":propName",
1570
+ value="https://dasch.swiss",
1571
+ )
1572
+ ```
1573
+ """
1574
+ self.values.append(
1575
+ UriValue.new(
1576
+ value=value, prop_name=prop_name, permissions=permissions, comment=comment, resource_id=self.res_id
1577
+ )
1578
+ )
1579
+ return self
1580
+
1581
+ def add_uri_multiple(
1582
+ self,
1583
+ prop_name: str,
1584
+ values: Collection[str],
1585
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1586
+ comment: str | None = None,
1587
+ ) -> Resource:
1588
+ """
1589
+ Add several URI values to the resource.
1590
+
1591
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#uri)
1592
+
1593
+ Args:
1594
+ prop_name: name of the property
1595
+ values: values to add
1596
+ permissions: optional permissions of this value
1597
+ comment: optional comment
1598
+
1599
+ Returns:
1600
+ The original resource, with the added values
1601
+
1602
+ Examples:
1603
+ ```python
1604
+ resource = resource.add_uri_multiple(
1605
+ prop_name=":propName",
1606
+ values=["https://dasch.swiss", "https://docs.dasch.swiss"],
1607
+ )
1608
+ ```
1609
+ """
1610
+ vals = check_and_fix_collection_input(values, prop_name, self.res_id)
1611
+ for v in vals:
1612
+ self.add_uri(prop_name, v, permissions, comment)
1613
+ return self
1614
+
1615
+ def add_uri_optional(
1616
+ self,
1617
+ prop_name: str,
1618
+ value: Any,
1619
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1620
+ comment: str | None = None,
1621
+ ) -> Resource:
1622
+ """
1623
+ If the value is not empty, add it to the resource, otherwise return the resource unchanged.
1624
+
1625
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#uri)
1626
+
1627
+ Args:
1628
+ prop_name: name of the property
1629
+ value: value to add or empty value
1630
+ permissions: optional permissions of this value
1631
+ comment: optional comment
1632
+
1633
+ Returns:
1634
+ The original resource, with the added value if it was not empty, else the unchanged original resource.
1635
+
1636
+ Examples:
1637
+ ```python
1638
+ resource = resource.add_uri_optional(
1639
+ prop_name=":propName",
1640
+ value="https://dasch.swiss",
1641
+ )
1642
+ ```
1643
+
1644
+ ```python
1645
+ resource = resource.add_uri_optional(
1646
+ prop_name=":propName",
1647
+ value=None,
1648
+ )
1649
+ ```
1650
+ """
1651
+ if is_nonempty_value(value):
1652
+ self.add_uri(prop_name, value, permissions, comment)
1653
+ return self
1654
+
1655
+ #######################
1656
+ # AbstractFileValue
1657
+ #######################
1658
+
1659
+ def add_file(
1660
+ self,
1661
+ filename: str | Path,
1662
+ license: License | None = None,
1663
+ copyright_holder: str | None = None,
1664
+ authorship: list[str] | None = None,
1665
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1666
+ comment: str | None = None,
1667
+ ) -> Resource:
1668
+ """
1669
+ Add a file (bitstream) to the resource.
1670
+
1671
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#bitstream)
1672
+
1673
+ Args:
1674
+ filename: path to the file
1675
+ license: License of the file (predefined or custom) [see the documentation for the options.](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/licenses/recommended/).
1676
+ A license states the circumstances how you are allowed to share/reuse something.
1677
+ copyright_holder: The person or institution who owns the economic rights of something.
1678
+ authorship: The (natural) person who authored something.
1679
+ permissions: optional permissions of this file
1680
+ comment: optional comment
1681
+
1682
+ Raises:
1683
+ XmllibInputError: If the resource already has a file or IIIF URI value
1684
+
1685
+ Returns:
1686
+ The original resource, with the added value
1687
+
1688
+ Examples:
1689
+ ```python
1690
+ resource = resource.add_file(
1691
+ filename="images/cat.jpg",
1692
+ license=xmllib.LicenseRecommended.DSP.PUBLIC_DOMAIN,
1693
+ copyright_holder="Meow University",
1694
+ authorship=["Kitty Meow"],
1695
+ )
1696
+ ```
1697
+
1698
+ ```python
1699
+ # a file with restricted view permissions
1700
+ resource = resource.add_file(
1701
+ filename="images/dog.jpg",
1702
+ license=xmllib.LicenseRecommended.CC.BY_NC_ND,
1703
+ copyright_holder="Bark University",
1704
+ authorship=["Bark McDog"],
1705
+ permissions=xmllib.Permissions.LIMITED_VIEW,
1706
+ )
1707
+ ```
1708
+ """
1709
+ if self.file_value:
1710
+ msg_info = MessageInfo(
1711
+ f"This resource already contains a file with the name: '{self.file_value.value}'. "
1712
+ f"The new file with the name '{filename}' cannot be added.",
1713
+ resource_id=self.res_id,
1714
+ field="file / iiif-uri",
1715
+ )
1716
+ raise_xmllib_input_error(msg_info)
1717
+ meta = Metadata.new(
1718
+ license=license,
1719
+ copyright_holder=copyright_holder,
1720
+ authorship=authorship,
1721
+ permissions=permissions,
1722
+ resource_id=self.res_id,
1723
+ )
1724
+ self.file_value = FileValue.new(value=filename, metadata=meta, comment=comment, resource_id=self.res_id)
1725
+ return self
1726
+
1727
+ def add_iiif_uri(
1728
+ self,
1729
+ iiif_uri: str,
1730
+ license: License | None = None,
1731
+ copyright_holder: str | None = None,
1732
+ authorship: list[str] | None = None,
1733
+ permissions: Permissions = Permissions.PROJECT_SPECIFIC_PERMISSIONS,
1734
+ comment: str | None = None,
1735
+ ) -> Resource:
1736
+ """
1737
+ Add a IIIF URI to the resource.
1738
+
1739
+ [See XML documentation for details](https://docs.dasch.swiss/latest/DSP-TOOLS/file-formats/xml-data-file/#iiif-uri)
1740
+
1741
+ Args:
1742
+ iiif_uri: valid IIIF URI
1743
+ license: License of the file (predefined or custom) [see the documentation for the options.](https://docs.dasch.swiss/latest/DSP-TOOLS/xmllib-docs/licenses/recommended/).
1744
+ A license states the circumstances how you are allowed to share/reuse something.
1745
+ copyright_holder: The person or institution who owns the economic rights of something.
1746
+ authorship: The (natural) person who authored something.
1747
+ permissions: optional permissions of this file
1748
+ comment: optional comment
1749
+
1750
+ Raises:
1751
+ XmllibInputError: If the resource already has a file or IIIF URI value
1752
+
1753
+ Returns:
1754
+ The original resource, with the added value
1755
+
1756
+ Examples:
1757
+ ```python
1758
+ resource = resource.add_iiif_uri(
1759
+ iiif_uri="https://iiif.wellcomecollection.org/image/b20432033_B0008608.JP2/full/1338%2C/0/default.jpg",
1760
+ license=xmllib.LicenseRecommended.CC.BY_NC,
1761
+ copyright_holder="Wellcome Collection",
1762
+ authorship=["Cavanagh, Annie"]
1763
+ )
1764
+ ```
1765
+ """
1766
+ if self.file_value:
1767
+ msg_info = MessageInfo(
1768
+ f"This resource already contains a file with the name: '{self.file_value.value}'. "
1769
+ f"The new file with the name '{iiif_uri}' cannot be added.",
1770
+ resource_id=self.res_id,
1771
+ field="file / iiif-uri",
1772
+ )
1773
+ raise_xmllib_input_error(msg_info)
1774
+ meta = Metadata.new(
1775
+ license=license,
1776
+ copyright_holder=copyright_holder,
1777
+ authorship=authorship,
1778
+ permissions=permissions,
1779
+ resource_id=self.res_id,
1780
+ )
1781
+ self.file_value = IIIFUri.new(value=iiif_uri, metadata=meta, comment=comment, resource_id=self.res_id)
1782
+ return self