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
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
  from pathlib import Path
3
5
  from typing import Any
@@ -5,14 +7,16 @@ from typing import Any
5
7
  import regex
6
8
 
7
9
  from dsp_tools.commands.excel2json.json_header import get_json_header
8
- from dsp_tools.commands.excel2json.lists import excel2lists
9
- from dsp_tools.commands.excel2json.new_lists.make_new_lists import new_excel2lists
10
+ from dsp_tools.commands.excel2json.lists.make_lists import excel2lists
11
+ from dsp_tools.commands.excel2json.models.json_header import PermissionsOverrulesPrefixed
12
+ from dsp_tools.commands.excel2json.old_lists import old_excel2lists
10
13
  from dsp_tools.commands.excel2json.properties import excel2properties
11
14
  from dsp_tools.commands.excel2json.resources import excel2resources
12
- from dsp_tools.models.exceptions import UserError
15
+ from dsp_tools.error.exceptions import BaseError
16
+ from dsp_tools.error.exceptions import InputError
13
17
 
14
18
 
15
- def excel2json(
19
+ def old_excel2json(
16
20
  data_model_files: str,
17
21
  path_to_output_file: str,
18
22
  ) -> bool:
@@ -38,16 +42,16 @@ def excel2json(
38
42
  path_to_output_file: path to the file where the output JSON file will be saved
39
43
 
40
44
  Raises:
41
- UserError: if something went wrong
45
+ InputError: if something went wrong
42
46
  BaseError: if something went wrong
43
47
 
44
48
  Returns:
45
49
  True if everything went well
46
50
  """
47
51
 
48
- listfolder, onto_folders = _validate_folder_structure_get_filenames(data_model_files)
52
+ listfolder, onto_folders = _old_validate_folder_structure_and_get_filenames(data_model_files)
49
53
 
50
- overall_success, project = _create_project_json(data_model_files, listfolder, onto_folders)
54
+ overall_success, project = _old_create_project_json(data_model_files, listfolder, onto_folders)
51
55
 
52
56
  with open(path_to_output_file, "w", encoding="utf-8") as f:
53
57
  json.dump(project, f, indent=4, ensure_ascii=False)
@@ -57,17 +61,17 @@ def excel2json(
57
61
  return overall_success
58
62
 
59
63
 
60
- def _validate_folder_structure_get_filenames(data_model_files: str) -> tuple[list[Path], list[Path]]:
64
+ def _old_validate_folder_structure_and_get_filenames(data_model_files: str) -> tuple[list[Path], list[Path]]:
61
65
  if not Path(data_model_files).is_dir():
62
- raise UserError(f"ERROR: {data_model_files} is not a directory.")
66
+ raise InputError(f"ERROR: {data_model_files} is not a directory.")
63
67
  sub_folders = [x for x in Path(data_model_files).glob("*") if _non_hidden(x) and x.is_dir()]
64
68
  files_to_process = []
65
69
  onto_folders, onto_files_to_process = _get_and_validate_onto_folder(Path(data_model_files), sub_folders)
66
70
  files_to_process.extend(onto_files_to_process)
67
- listfolder, lists_to_process = _get_validate_list_folder(data_model_files, sub_folders)
71
+ listfolder, lists_to_process = _old_get_and_validate_list_folder(data_model_files, sub_folders)
68
72
  files_to_process.extend(lists_to_process)
69
73
  if len(onto_folders) + len(listfolder) != len(sub_folders):
70
- raise UserError(
74
+ raise InputError(
71
75
  f"The only allowed subfolders in '{data_model_files}' are 'lists' "
72
76
  "and folders that match the pattern 'onto_name (onto_label)'"
73
77
  )
@@ -78,20 +82,20 @@ def _validate_folder_structure_get_filenames(data_model_files: str) -> tuple[lis
78
82
  return listfolder, onto_folders
79
83
 
80
84
 
81
- def _get_validate_list_folder(data_model_files: str, folder: list[Path]) -> tuple[list[Path], list[str]]:
85
+ def _old_get_and_validate_list_folder(data_model_files: str, folder: list[Path]) -> tuple[list[Path], list[str]]:
82
86
  processed_files: list[str] = []
83
87
  listfolder = [x for x in folder if x.is_dir() and x.name == "lists"]
84
88
  if listfolder:
85
89
  listfolder_contents = [x for x in Path(listfolder[0]).glob("*") if _non_hidden(x)]
86
90
  if not all(regex.search(r"(de|en|fr|it|rm).xlsx", file.name) for file in listfolder_contents):
87
- raise UserError(
91
+ raise InputError(
88
92
  f"The only files allowed in '{data_model_files}/lists' are en.xlsx, de.xlsx, fr.xlsx, it.xlsx, rm.xlsx"
89
93
  )
90
94
  processed_files = [f"{data_model_files}/lists/{file.name}" for file in listfolder_contents]
91
95
  return listfolder, processed_files
92
96
 
93
97
 
94
- def new_excel2json(
98
+ def excel2json(
95
99
  data_model_files: str,
96
100
  path_to_output_file: str,
97
101
  ) -> bool:
@@ -123,26 +127,27 @@ def new_excel2json(
123
127
  True if everything went well
124
128
  """
125
129
 
126
- listfolder, onto_folders = _new_validate_folder_structure_and_get_filenames(Path(data_model_files))
130
+ listfolder, onto_folders = _validate_folder_structure_and_get_filenames(Path(data_model_files))
127
131
 
128
- overall_success, project = _new_create_project_json(data_model_files, onto_folders, listfolder)
132
+ overall_success, project = _create_project_json(data_model_files, onto_folders, listfolder)
129
133
 
130
134
  with open(path_to_output_file, "w", encoding="utf-8") as f:
131
- json.dump(project, f, indent=4, ensure_ascii=False)
135
+ dump_str = json.dumps(project, indent=4, ensure_ascii=False)
136
+ f.write(dump_str)
132
137
 
133
138
  print(f"JSON project file successfully saved at {path_to_output_file}")
134
139
 
135
140
  return overall_success
136
141
 
137
142
 
138
- def _new_validate_folder_structure_and_get_filenames(data_model_files: Path) -> tuple[Path | None, list[Path]]:
143
+ def _validate_folder_structure_and_get_filenames(data_model_files: Path) -> tuple[Path | None, list[Path]]:
139
144
  if not data_model_files.is_dir():
140
- raise UserError(f"ERROR: {data_model_files} is not a directory.")
145
+ raise InputError(f"ERROR: {data_model_files} is not a directory.")
141
146
  folder = [x for x in data_model_files.glob("*") if _non_hidden(x)]
142
147
  processed_files = []
143
148
  onto_folders, processed_onto = _get_and_validate_onto_folder(data_model_files, folder)
144
149
  processed_files.extend(processed_onto)
145
- listfolder, processed_lists = _new_get_and_validate_list_folder(data_model_files)
150
+ listfolder, processed_lists = _get_and_validate_list_folder(data_model_files)
146
151
  processed_files.extend(processed_lists)
147
152
  print("The following files will be processed:")
148
153
  print(*(f" - {file}" for file in processed_files), sep="\n")
@@ -153,13 +158,13 @@ def _get_and_validate_onto_folder(data_model_files: Path, folder: list[Path]) ->
153
158
  processed_files = []
154
159
  onto_folders = [x for x in folder if x.is_dir() and regex.search(r"([\w.-]+) \(([\w.\- ]+)\)", x.name)]
155
160
  if not onto_folders:
156
- raise UserError(
161
+ raise InputError(
157
162
  f"'{data_model_files}' must contain at least one subfolder named after the pattern 'onto_name (onto_label)'"
158
163
  )
159
164
  for onto_folder in onto_folders:
160
165
  contents = sorted([x.name for x in Path(onto_folder).glob("*") if _non_hidden(x)])
161
166
  if contents != ["properties.xlsx", "resources.xlsx"]:
162
- raise UserError(
167
+ raise InputError(
163
168
  f"ERROR: '{data_model_files}/{onto_folder.name}' must contain one file 'properties.xlsx' "
164
169
  "and one file 'resources.xlsx', but nothing else."
165
170
  )
@@ -167,62 +172,99 @@ def _get_and_validate_onto_folder(data_model_files: Path, folder: list[Path]) ->
167
172
  return onto_folders, processed_files
168
173
 
169
174
 
170
- def _new_get_and_validate_list_folder(
175
+ def _get_and_validate_list_folder(
171
176
  data_model_files: Path,
172
177
  ) -> tuple[Path | None, list[str]]:
173
178
  if not (list_dir := (data_model_files / "lists")).is_dir():
174
179
  return None, []
175
180
  processed_files = [str(file) for file in list_dir.glob("*list*.xlsx") if _non_hidden(file)]
176
- return list_dir, processed_files
181
+ return list_dir, sorted(processed_files)
177
182
 
178
183
 
179
184
  def _non_hidden(path: Path) -> bool:
180
185
  return not regex.search(r"^(\.|~\$).+", path.name)
181
186
 
182
187
 
183
- def _create_project_json(
188
+ def _old_create_project_json(
184
189
  data_model_files: str, listfolder: list[Path], onto_folders: list[Path]
185
190
  ) -> tuple[bool, dict[str, Any]]:
186
191
  overall_success = True
187
- lists, success = excel2lists(excelfolder=f"{data_model_files}/lists") if listfolder else (None, True)
192
+ lists, success = old_excel2lists(excelfolder=f"{data_model_files}/lists") if listfolder else (None, True)
188
193
  if not success:
189
194
  overall_success = False
190
- ontologies, success = _get_ontologies(data_model_files, onto_folders)
195
+ ontologies, default_permissions_overrule, success = _get_ontologies(data_model_files, onto_folders)
191
196
  if not success:
192
197
  overall_success = False
193
198
  project = get_json_header(Path(data_model_files) / "json_header.xlsx").to_dict()
199
+ if default_permissions_overrule.non_empty():
200
+ project["project"]["default_permissions_overrule"] = default_permissions_overrule.serialize()
194
201
  if lists:
195
202
  project["project"]["lists"] = lists
196
203
  project["project"]["ontologies"] = ontologies
204
+ project["project"] = _sort_project_dict(project["project"])
197
205
  return overall_success, project
198
206
 
199
207
 
200
- def _new_create_project_json(
208
+ def _create_project_json(
201
209
  data_model_files: str, onto_folders: list[Path], list_folder: Path | None
202
210
  ) -> tuple[bool, dict[str, Any]]:
203
211
  overall_success = True
204
212
  lists = None
205
213
  if list_folder:
206
- lists, success = new_excel2lists(list_folder)
214
+ lists, success = excel2lists(list_folder)
207
215
  if not success:
208
216
  overall_success = False
209
- ontologies, success = _get_ontologies(data_model_files, onto_folders)
217
+ ontologies, default_permissions_overrule, success = _get_ontologies(data_model_files, onto_folders)
210
218
  if not success:
211
219
  overall_success = False
212
220
  project = get_json_header(Path(data_model_files) / "json_header.xlsx").to_dict()
221
+ if default_permissions_overrule.non_empty():
222
+ project["project"]["default_permissions_overrule"] = default_permissions_overrule.serialize()
213
223
  if lists:
214
224
  project["project"]["lists"] = lists
215
225
  project["project"]["ontologies"] = ontologies
226
+ project["project"] = _sort_project_dict(project["project"])
216
227
  return overall_success, project
217
228
 
218
229
 
219
- def _get_ontologies(data_model_files: str, onto_folders: list[Path]) -> tuple[list[dict[str, Any]], bool]:
230
+ def _sort_project_dict(unsorted_project_dict: dict[str, Any]) -> dict[str, Any]:
231
+ # order how the keys should appear in the JSON file
232
+ ordered_keys = [
233
+ "shortcode",
234
+ "shortname",
235
+ "longname",
236
+ "descriptions",
237
+ "keywords",
238
+ "enabled_licenses",
239
+ "default_permissions",
240
+ "default_permissions_overrule",
241
+ "users",
242
+ "groups",
243
+ "lists",
244
+ "ontologies",
245
+ ]
246
+ # filter out unused keys, to prevent a KeyError
247
+ ordered_keys = [key for key in ordered_keys if key in unsorted_project_dict]
248
+ # important - if in the future, more keys are added, they must be added to the list above
249
+ if any(forgotten_keys := [key for key in unsorted_project_dict if key not in ordered_keys]):
250
+ raise BaseError(
251
+ "The list of keys is outdated. During sorting, the following keys would be discarded: "
252
+ + ", ".join(forgotten_keys)
253
+ )
254
+ # do the actual sorting
255
+ return {key: unsorted_project_dict[key] for key in ordered_keys}
256
+
257
+
258
+ def _get_ontologies(
259
+ data_model_files: str, onto_folders: list[Path]
260
+ ) -> tuple[list[dict[str, Any]], PermissionsOverrulesPrefixed, bool]:
220
261
  success = True
221
262
  ontologies = []
263
+ permissions_overrules = PermissionsOverrulesPrefixed(private=[], limited_view=[])
222
264
  for onto_folder in onto_folders:
223
265
  name, label = regex.search(r"([\w.-]+) \(([\w.\- ]+)\)", onto_folder.name).groups() # type: ignore[union-attr]
224
- resources, success1 = excel2resources(f"{data_model_files}/{onto_folder.name}/resources.xlsx")
225
- properties, success2 = excel2properties(f"{data_model_files}/{onto_folder.name}/properties.xlsx")
266
+ resources, r_overrules, success1 = excel2resources(f"{data_model_files}/{onto_folder.name}/resources.xlsx")
267
+ properties, p_overrules, success2 = excel2properties(f"{data_model_files}/{onto_folder.name}/properties.xlsx")
226
268
  if not success1 or not success2:
227
269
  success = False
228
270
  ontologies.append(
@@ -233,4 +275,6 @@ def _get_ontologies(data_model_files: str, onto_folders: list[Path]) -> tuple[li
233
275
  "resources": resources,
234
276
  }
235
277
  )
236
- return ontologies, success
278
+ permissions_overrules.add_overrules(r_overrules, name)
279
+ permissions_overrules.add_overrules(p_overrules, name)
280
+ return ontologies, permissions_overrules, success
@@ -19,13 +19,14 @@ from dsp_tools.commands.excel2json.models.input_error import JsonValidationPrope
19
19
  from dsp_tools.commands.excel2json.models.input_error import MissingValuesProblem
20
20
  from dsp_tools.commands.excel2json.models.input_error import MoreThanOneSheetProblem
21
21
  from dsp_tools.commands.excel2json.models.input_error import PositionInExcel
22
- from dsp_tools.commands.excel2json.models.input_error import Problem
23
22
  from dsp_tools.commands.excel2json.models.input_error import PropertyProblem
23
+ from dsp_tools.commands.excel2json.models.json_header import PermissionsOverrulesUnprefixed
24
24
  from dsp_tools.commands.excel2json.models.ontology import GuiAttributes
25
25
  from dsp_tools.commands.excel2json.models.ontology import OntoProperty
26
26
  from dsp_tools.commands.excel2json.utils import add_optional_columns
27
27
  from dsp_tools.commands.excel2json.utils import check_column_for_duplicate
28
28
  from dsp_tools.commands.excel2json.utils import check_contains_required_columns
29
+ from dsp_tools.commands.excel2json.utils import check_permissions
29
30
  from dsp_tools.commands.excel2json.utils import check_required_values
30
31
  from dsp_tools.commands.excel2json.utils import col_must_or_not_empty_based_on_other_col
31
32
  from dsp_tools.commands.excel2json.utils import find_one_full_cell_in_cols
@@ -33,17 +34,18 @@ from dsp_tools.commands.excel2json.utils import get_comments
33
34
  from dsp_tools.commands.excel2json.utils import get_labels
34
35
  from dsp_tools.commands.excel2json.utils import get_wrong_row_numbers
35
36
  from dsp_tools.commands.excel2json.utils import read_and_clean_all_sheets
36
- from dsp_tools.models.exceptions import InputError
37
+ from dsp_tools.error.exceptions import InputError
38
+ from dsp_tools.error.exceptions import InvalidGuiAttributeError
39
+ from dsp_tools.error.problems import Problem
37
40
 
38
41
  languages = ["en", "de", "fr", "it", "rm"]
39
42
  language_label_col = ["label_en", "label_de", "label_fr", "label_it", "label_rm"]
40
- mandatory_properties = ["name", "object", "gui_element"]
41
43
 
42
44
 
43
45
  def excel2properties(
44
46
  excelfile: str,
45
47
  path_to_output_file: Optional[str] = None,
46
- ) -> tuple[list[dict[str, Any]], bool]:
48
+ ) -> tuple[list[dict[str, Any]], PermissionsOverrulesUnprefixed, bool]:
47
49
  """
48
50
  Converts properties described in an Excel file into a "properties" section which can be inserted into a JSON
49
51
  project file.
@@ -56,8 +58,9 @@ def excel2properties(
56
58
  InputError: if something went wrong
57
59
 
58
60
  Returns:
59
- a tuple consisting of the "properties" section as a Python list,
60
- and the success status (True if everything went well)
61
+ - the "properties" section as a Python list
62
+ - the unprefixed "default_permissions_overrule"
63
+ - the success status (True if everything went well)
61
64
  """
62
65
 
63
66
  property_df = _read_check_property_df(excelfile)
@@ -77,6 +80,7 @@ def excel2properties(
77
80
  "comment_it",
78
81
  "comment_rm",
79
82
  "subject",
83
+ "default_permissions_overrule",
80
84
  }
81
85
  property_df = add_optional_columns(property_df, optional_col_set)
82
86
 
@@ -101,6 +105,7 @@ def excel2properties(
101
105
  raise InputError(msg)
102
106
 
103
107
  serialised_prop = [x.serialise() for x in props]
108
+ default_permissions_overrule = _extract_default_permissions_overrule(property_df)
104
109
 
105
110
  # write final JSON file
106
111
  _validate_properties_section_in_json(properties_list=serialised_prop)
@@ -109,7 +114,7 @@ def excel2properties(
109
114
  json.dump(serialised_prop, file, indent=4, ensure_ascii=False)
110
115
  print(f"properties section was created successfully and written to file '{path_to_output_file}'")
111
116
 
112
- return serialised_prop, True
117
+ return serialised_prop, default_permissions_overrule, True
113
118
 
114
119
 
115
120
  def _check_for_deprecated_syntax(df: pd.DataFrame) -> None:
@@ -176,6 +181,8 @@ def _do_property_excel_compliance(df: pd.DataFrame) -> None:
176
181
  problems.append(col_prob)
177
182
  if missing_vals_check := _check_missing_values_in_row(df=df):
178
183
  problems.append(missing_vals_check)
184
+ if permissions_prob := check_permissions(df=df, allowed_vals=["private"]):
185
+ problems.append(permissions_prob)
179
186
  if any(problems):
180
187
  excel_prob = ExcelFileProblem("properties.xlsx", problems)
181
188
  msg = excel_prob.execute_error_protocol()
@@ -202,7 +209,7 @@ def _check_missing_values_in_row(df: pd.DataFrame) -> None | MissingValuesProble
202
209
 
203
210
 
204
211
  def _check_compliance_gui_attributes(df: pd.DataFrame) -> dict[str, pd.Series[bool]] | None:
205
- mandatory_attributes = ["Spinbox", "List"]
212
+ mandatory_attributes = ["List"]
206
213
  mandatory_check = col_must_or_not_empty_based_on_other_col(
207
214
  df=df,
208
215
  substring_list=mandatory_attributes,
@@ -210,7 +217,18 @@ def _check_compliance_gui_attributes(df: pd.DataFrame) -> dict[str, pd.Series[bo
210
217
  check_empty_colname="gui_attributes",
211
218
  must_have_value=True,
212
219
  )
213
- no_attributes = ["Checkbox", "Date", "Geonames", "Richtext", "TimeStamp"]
220
+ no_attributes = [
221
+ "Checkbox",
222
+ "Colorpicker",
223
+ "Date",
224
+ "Spinbox",
225
+ "Geonames",
226
+ "SimpleText",
227
+ "Textarea",
228
+ "Richtext",
229
+ "TimeStamp",
230
+ "Searchbox",
231
+ ]
214
232
  no_attribute_check = col_must_or_not_empty_based_on_other_col(
215
233
  df=df,
216
234
  substring_list=no_attributes,
@@ -230,11 +248,11 @@ def _get_final_series(
230
248
  case None, None:
231
249
  return None
232
250
  case pd.Series(), pd.Series():
233
- final_series = pd.Series(np.logical_or(mandatory_check, no_attribute_check)) # type: ignore[arg-type, assignment]
251
+ final_series = pd.Series(np.logical_or(mandatory_check, no_attribute_check))
234
252
  case pd.Series(), None:
235
- final_series = mandatory_check # type: ignore[assignment]
253
+ final_series = mandatory_check
236
254
  case None, pd.Series():
237
- final_series = no_attribute_check # type: ignore[assignment]
255
+ final_series = no_attribute_check
238
256
  return final_series
239
257
 
240
258
 
@@ -263,39 +281,31 @@ def _get_gui_attribute(
263
281
  ) -> GuiAttributes | InvalidExcelContentProblem | None:
264
282
  if pd.isnull(df_row["gui_attributes"]):
265
283
  return None
266
- # If the attribute is not in the correct format, a called function may raise an IndexError
267
284
  try:
268
- return _format_gui_attribute(attribute_str=df_row["gui_attributes"])
269
- except IndexError:
285
+ return _unpack_gui_attributes(attribute_str=df_row["gui_attributes"])
286
+ except InvalidGuiAttributeError:
270
287
  return InvalidExcelContentProblem(
271
- expected_content="attribute: value, attribute: value",
288
+ expected_content="The only valid gui-attribute is 'hlist' for the gui-element 'List'.",
272
289
  actual_content=df_row["gui_attributes"],
273
290
  excel_position=PositionInExcel(column="gui_attributes", row=row_num),
274
291
  )
275
292
 
276
293
 
277
- def _format_gui_attribute(attribute_str: str) -> GuiAttributes:
278
- attribute_dict = _unpack_gui_attributes(attribute_str=attribute_str)
279
- return GuiAttributes(
280
- {attrib: _search_convert_numbers_in_str(value_str=val) for attrib, val in attribute_dict.items()}
281
- )
282
-
283
-
284
- def _unpack_gui_attributes(attribute_str: str) -> dict[str, str]:
285
- gui_list = [x.strip() for x in attribute_str.split(",") if x.strip() != ""]
286
- sub_gui_list = [[sub.strip() for sub in x.split(":") if sub.strip() != ""] for x in gui_list]
287
- if any(len(sub) != 2 for sub in sub_gui_list):
288
- raise IndexError
289
- return {sub[0]: sub[1] for sub in sub_gui_list}
294
+ def _unpack_gui_attributes(attribute_str: str) -> GuiAttributes:
295
+ attribute_str = attribute_str.strip()
296
+ if not attribute_str:
297
+ return GuiAttributes({})
298
+ attrib_key, attrib_val = _extract_information_from_single_gui_attribute(attribute_str)
299
+ if attrib_key != "hlist":
300
+ raise InvalidGuiAttributeError("The only valid gui-attribute is 'hlist' for the gui-element 'List'.")
301
+ return GuiAttributes({attrib_key: attrib_val})
290
302
 
291
303
 
292
- def _search_convert_numbers_in_str(value_str: str) -> str | int | float:
293
- if regex.search(r"^\d+$", value_str):
294
- return int(value_str)
295
- elif regex.search(r"^\d+\.\d+$", value_str):
296
- return float(value_str)
297
- else:
298
- return value_str
304
+ def _extract_information_from_single_gui_attribute(attribute_str: str) -> tuple[str, str]:
305
+ attrib_format = r"(\S+)\s*:\s*(.+)"
306
+ if found := regex.search(attrib_format, attribute_str):
307
+ return found.group(1), found.group(2)
308
+ raise InvalidGuiAttributeError("Invalid gui attribute")
299
309
 
300
310
 
301
311
  def _validate_properties_section_in_json(
@@ -347,3 +357,14 @@ def _find_validation_problem(
347
357
  original_msg=validation_error.message,
348
358
  message_path=validation_error.json_path,
349
359
  )
360
+
361
+
362
+ def _extract_default_permissions_overrule(property_df: pd.DataFrame) -> PermissionsOverrulesUnprefixed:
363
+ result = PermissionsOverrulesUnprefixed(private=[], limited_view=[])
364
+ for _, row in property_df.iterrows():
365
+ perm = row.get("default_permissions_overrule")
366
+ if pd.isna(perm):
367
+ continue
368
+ if perm.strip().lower() == "private":
369
+ result.private.append(row["name"])
370
+ return result
@@ -18,18 +18,20 @@ from dsp_tools.commands.excel2json.models.input_error import JsonValidationResou
18
18
  from dsp_tools.commands.excel2json.models.input_error import MandatorySheetsMissingProblem
19
19
  from dsp_tools.commands.excel2json.models.input_error import MissingValuesProblem
20
20
  from dsp_tools.commands.excel2json.models.input_error import PositionInExcel
21
- from dsp_tools.commands.excel2json.models.input_error import Problem
22
21
  from dsp_tools.commands.excel2json.models.input_error import ResourceSheetNotListedProblem
22
+ from dsp_tools.commands.excel2json.models.json_header import PermissionsOverrulesUnprefixed
23
23
  from dsp_tools.commands.excel2json.models.ontology import OntoResource
24
24
  from dsp_tools.commands.excel2json.models.ontology import ResourceCardinality
25
25
  from dsp_tools.commands.excel2json.utils import add_optional_columns
26
26
  from dsp_tools.commands.excel2json.utils import check_column_for_duplicate
27
27
  from dsp_tools.commands.excel2json.utils import check_contains_required_columns
28
+ from dsp_tools.commands.excel2json.utils import check_permissions
28
29
  from dsp_tools.commands.excel2json.utils import find_missing_required_values
29
30
  from dsp_tools.commands.excel2json.utils import get_comments
30
31
  from dsp_tools.commands.excel2json.utils import get_labels
31
32
  from dsp_tools.commands.excel2json.utils import read_and_clean_all_sheets
32
- from dsp_tools.models.exceptions import InputError
33
+ from dsp_tools.error.exceptions import InputError
34
+ from dsp_tools.error.problems import Problem
33
35
 
34
36
  languages = ["en", "de", "fr", "it", "rm"]
35
37
 
@@ -37,7 +39,7 @@ languages = ["en", "de", "fr", "it", "rm"]
37
39
  def excel2resources(
38
40
  excelfile: str,
39
41
  path_to_output_file: Optional[str] = None,
40
- ) -> tuple[list[dict[str, Any]], bool]:
42
+ ) -> tuple[list[dict[str, Any]], PermissionsOverrulesUnprefixed, bool]:
41
43
  """
42
44
  Converts resources described in an Excel file into a "resources" section which can be inserted into a JSON
43
45
  project file.
@@ -48,12 +50,12 @@ def excel2resources(
48
50
  (otherwise, it's only returned as return value)
49
51
 
50
52
  Raises:
51
- UserError: if something went wrong
52
- InputError: is something went wrong
53
+ InputError: if something went wrong
53
54
 
54
55
  Returns:
55
- a tuple consisting of the "resources" section as Python list,
56
- and the success status (True if everything went well)
56
+ - the "resources" section as Python list,
57
+ - the unprefixed "default_permissions_overrule",
58
+ - the success status (True if everything went well)
57
59
  """
58
60
 
59
61
  all_dfs = read_and_clean_all_sheets(excelfile)
@@ -66,6 +68,7 @@ def excel2resources(
66
68
  # transform every row into a resource
67
69
  res = [_row2resource(row, resource_dfs.get(row["name"])) for i, row in classes_df.iterrows()]
68
70
  resources = [x.serialise() for x in res]
71
+ default_permissions_overrule = _extract_default_permissions_overrule(classes_df)
69
72
 
70
73
  # write final "resources" section into a JSON file
71
74
  _validate_resources(resources_list=resources)
@@ -75,7 +78,7 @@ def excel2resources(
75
78
  json.dump(resources, file, indent=4, ensure_ascii=False)
76
79
  print(f"resources section was created successfully and written to file '{path_to_output_file}'")
77
80
 
78
- return resources, True
81
+ return resources, default_permissions_overrule, True
79
82
 
80
83
 
81
84
  def _validate_excel_file(all_dfs: dict[str, pd.DataFrame]) -> ExcelFileProblem | None:
@@ -91,6 +94,8 @@ def _validate_excel_file(all_dfs: dict[str, pd.DataFrame]) -> ExcelFileProblem |
91
94
  problems.append(cls_problem)
92
95
  if sheet_problems := _validate_individual_class_sheets(df_dict):
93
96
  problems.extend(sheet_problems)
97
+ if permissions_prob := check_permissions(df=classes_df, allowed_vals=["private", "limited_view"]):
98
+ problems.append(permissions_prob)
94
99
  if problems:
95
100
  return ExcelFileProblem("resources.xlsx", problems)
96
101
  return None
@@ -153,6 +158,7 @@ def _prepare_classes_df(resource_dfs: dict[str, pd.DataFrame]) -> tuple[pd.DataF
153
158
  "comment_fr",
154
159
  "comment_it",
155
160
  "comment_rm",
161
+ "default_permissions_overrule",
156
162
  },
157
163
  )
158
164
  resource_dfs = {k: add_optional_columns(v, {"gui_order"}) for k, v in resource_dfs.items()}
@@ -173,7 +179,7 @@ def _row2resource(
173
179
  class_df_with_cardinalities: Excel sheet of the individual class
174
180
 
175
181
  Raises:
176
- UserError: if the row or the details sheet contains invalid data
182
+ InputError: if the row or the details sheet contains invalid data
177
183
 
178
184
  Returns:
179
185
  dict object of the resource
@@ -204,9 +210,10 @@ def _create_all_cardinalities(class_name: str, class_df_with_cardinalities: pd.D
204
210
 
205
211
 
206
212
  def _make_one_cardinality(detail_row: pd.Series[str | int]) -> ResourceCardinality:
207
- return ResourceCardinality(
208
- f":{detail_row["property"]}", str(detail_row["cardinality"]).lower(), int(detail_row["gui_order"])
209
- )
213
+ prop_str = str(detail_row["property"])
214
+ knora_props = ["seqnum", "isPartOf"]
215
+ prop = prop_str if ":" in prop_str or prop_str in knora_props else f":{prop_str}"
216
+ return ResourceCardinality(prop, str(detail_row["cardinality"]).lower(), int(detail_row["gui_order"]))
210
217
 
211
218
 
212
219
  def _check_complete_gui_order(class_name: str, class_df_with_cardinalities: pd.DataFrame) -> pd.DataFrame:
@@ -314,3 +321,16 @@ def _find_validation_problem(
314
321
  original_msg=validation_error.message,
315
322
  message_path=validation_error.json_path,
316
323
  )
324
+
325
+
326
+ def _extract_default_permissions_overrule(classes_df: pd.DataFrame) -> PermissionsOverrulesUnprefixed:
327
+ result = PermissionsOverrulesUnprefixed(private=[], limited_view=[])
328
+ for _, row in classes_df.iterrows():
329
+ perm = row.get("default_permissions_overrule")
330
+ if pd.isna(perm):
331
+ continue
332
+ if perm.strip().lower() == "private":
333
+ result.private.append(row["name"])
334
+ elif perm.strip().lower() == "limited_view":
335
+ result.limited_view.append(row["name"])
336
+ return result
@@ -11,11 +11,14 @@ import regex
11
11
  from dsp_tools.commands.excel2json.models.input_error import DuplicateSheetProblem
12
12
  from dsp_tools.commands.excel2json.models.input_error import DuplicatesInColumnProblem
13
13
  from dsp_tools.commands.excel2json.models.input_error import ExcelFileProblem
14
+ from dsp_tools.commands.excel2json.models.input_error import InvalidPermissionsOverrule
15
+ from dsp_tools.commands.excel2json.models.input_error import InvalidPermissionsOverruleProblem
14
16
  from dsp_tools.commands.excel2json.models.input_error import InvalidSheetNameProblem
15
17
  from dsp_tools.commands.excel2json.models.input_error import PositionInExcel
16
18
  from dsp_tools.commands.excel2json.models.input_error import RequiredColumnMissingProblem
17
19
  from dsp_tools.commands.excel2json.models.ontology import LanguageDict
18
- from dsp_tools.models.exceptions import InputError
20
+ from dsp_tools.error.exceptions import InputError
21
+ from dsp_tools.error.exceptions import UserFilepathNotFoundError
19
22
 
20
23
  languages = ["en", "de", "fr", "it", "rm"]
21
24
 
@@ -36,6 +39,8 @@ def read_and_clean_all_sheets(excelfile: str | Path) -> dict[str, pd.DataFrame]:
36
39
  Raises:
37
40
  InputError: If the sheets are not correctly named
38
41
  """
42
+ if not Path(excelfile).exists():
43
+ raise UserFilepathNotFoundError(excelfile)
39
44
  try:
40
45
  df_dict = pd.read_excel(excelfile, sheet_name=None)
41
46
  except ValueError:
@@ -331,3 +336,17 @@ def add_optional_columns(df: pd.DataFrame, optional_col_set: set[str]) -> pd.Dat
331
336
  additional_df = pd.DataFrame(columns=additional_col, index=df.index)
332
337
  df = pd.concat(objs=[df, additional_df], axis=1)
333
338
  return df
339
+
340
+
341
+ def check_permissions(df: pd.DataFrame, allowed_vals: list[str]) -> None | InvalidPermissionsOverruleProblem:
342
+ problems: list[InvalidPermissionsOverrule] = []
343
+ for _, row in df.iterrows():
344
+ if pd.isna(actual_val := row.get("default_permissions_overrule")):
345
+ continue
346
+ if actual_val.strip().lower() not in allowed_vals:
347
+ prob = InvalidPermissionsOverrule(entity_name=row["name"], actual_val=actual_val, allowed_vals=allowed_vals)
348
+ problems.append(prob)
349
+ if problems:
350
+ return InvalidPermissionsOverruleProblem(problems)
351
+ else:
352
+ return None
@@ -3,5 +3,5 @@
3
3
 
4
4
  from dsp_tools.commands.excel2xml.excel2xml_lib import *
5
5
  from dsp_tools.commands.excel2xml.propertyelement import PropertyElement as PropertyElement
6
- from dsp_tools.utils.shared import check_notna as check_notna
7
- from dsp_tools.utils.shared import simplify_name as simplify_name
6
+ from dsp_tools.utils.data_formats.shared import check_notna as check_notna
7
+ from dsp_tools.utils.data_formats.shared import simplify_name as simplify_name