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,119 @@
1
+ from typing import Any
2
+
3
+ from rdflib import OWL
4
+ from rdflib import RDF
5
+ from rdflib import RDFS
6
+ from rdflib import BNode
7
+ from rdflib import Graph
8
+ from rdflib import Literal
9
+ from rdflib import URIRef
10
+
11
+ from dsp_tools.commands.create.create_on_server.mappers import PARSED_CARDINALITY_TO_RDF
12
+ from dsp_tools.commands.create.models.parsed_ontology import ParsedClass
13
+ from dsp_tools.commands.create.models.parsed_ontology import ParsedOntology
14
+ from dsp_tools.commands.create.models.parsed_ontology import ParsedProperty
15
+ from dsp_tools.commands.create.models.parsed_ontology import ParsedPropertyCardinality
16
+ from dsp_tools.utils.rdf_constants import KNORA_API
17
+ from dsp_tools.utils.rdf_constants import KNORA_API_PREFIX
18
+ from dsp_tools.utils.rdf_constants import SALSAH_GUI
19
+ from dsp_tools.utils.rdflib_utils import serialise_json
20
+
21
+
22
+ def serialise_ontology_graph_for_request(parsed_ontology: ParsedOntology, project_iri: str) -> dict[str, Any]:
23
+ onto_graph = {
24
+ f"{KNORA_API_PREFIX}attachedToProject": {"@id": project_iri},
25
+ f"{KNORA_API_PREFIX}ontologyName": parsed_ontology.name,
26
+ str(RDFS.label): parsed_ontology.label,
27
+ }
28
+ if parsed_ontology.comment:
29
+ onto_graph[str(RDFS.comment)] = parsed_ontology.comment
30
+ return onto_graph
31
+
32
+
33
+ def _make_ontology_base_graph(onto_iri: URIRef, last_modification_date: Literal) -> Graph:
34
+ g = Graph()
35
+ g.add((onto_iri, RDF.type, OWL.Ontology))
36
+ g.add((onto_iri, KNORA_API.lastModificationDate, last_modification_date))
37
+ return g
38
+
39
+
40
+ def serialise_cardinality_graph_for_request(
41
+ card: ParsedPropertyCardinality, res_iri: URIRef, onto_iri: URIRef, last_modification_date: Literal
42
+ ) -> dict[str, Any]:
43
+ onto_g = _make_ontology_base_graph(onto_iri, last_modification_date)
44
+ onto_serialised = next(iter(serialise_json(onto_g)))
45
+ card_g = _make_one_cardinality_graph(card, res_iri)
46
+ card_serialised = serialise_json(card_g)
47
+ onto_serialised["@graph"] = card_serialised
48
+ return onto_serialised
49
+
50
+
51
+ def _make_one_cardinality_graph(card: ParsedPropertyCardinality, res_iri: URIRef) -> Graph:
52
+ card_info = PARSED_CARDINALITY_TO_RDF[card.cardinality]
53
+ g = Graph()
54
+ bn_card = BNode()
55
+ g.add((res_iri, RDF.type, OWL.Class))
56
+ g.add((res_iri, RDFS.subClassOf, bn_card))
57
+ g.add((bn_card, RDF.type, OWL.Restriction))
58
+ g.add((bn_card, card_info.owl_property, card_info.cardinality_value))
59
+ g.add((bn_card, OWL.onProperty, URIRef(card.propname)))
60
+ if card.gui_order is not None:
61
+ g.add((bn_card, SALSAH_GUI.guiOrder, Literal(card.gui_order)))
62
+ return g
63
+
64
+
65
+ def serialise_property_graph_for_request(
66
+ prop: ParsedProperty, list_iri: Literal | None, onto_iri: URIRef, last_modification_date: Literal
67
+ ) -> dict[str, Any]:
68
+ onto_g = _make_ontology_base_graph(onto_iri, last_modification_date)
69
+ onto_serialised = next(iter(serialise_json(onto_g)))
70
+ prop_g = _make_one_property_graph(prop, list_iri)
71
+ prop_serialised = serialise_json(prop_g)
72
+ onto_serialised["@graph"] = prop_serialised
73
+ return onto_serialised
74
+
75
+
76
+ def _make_one_property_graph(prop: ParsedProperty, list_iri: Literal | None) -> Graph:
77
+ trips: list[tuple[URIRef, Literal | URIRef]] = [
78
+ (RDF.type, OWL.ObjectProperty),
79
+ (KNORA_API.objectType, URIRef(str(prop.object))),
80
+ (SALSAH_GUI.guiElement, URIRef(str(prop.gui_element))),
81
+ ]
82
+ trips.extend([(RDFS.label, Literal(lbl, lang=lang_tag)) for lang_tag, lbl in prop.labels.items()])
83
+ if prop.comments:
84
+ trips.extend([(RDFS.comment, Literal(cmnt, lang=lang_tag)) for lang_tag, cmnt in prop.comments.items()])
85
+ trips.extend([(RDFS.subPropertyOf, URIRef(supr)) for supr in prop.supers])
86
+ if prop.subject:
87
+ trips.append((KNORA_API.subjectType, URIRef(prop.subject)))
88
+ if list_iri is not None:
89
+ trips.append((SALSAH_GUI.guiAttribute, list_iri))
90
+ prop_iri = URIRef(prop.name)
91
+ g = Graph()
92
+ for p, o in trips:
93
+ g.add((prop_iri, p, o))
94
+ return g
95
+
96
+
97
+ def serialise_class_graph_for_request(
98
+ cls: ParsedClass, onto_iri: URIRef, last_modification_date: Literal
99
+ ) -> dict[str, Any]:
100
+ onto_g = _make_ontology_base_graph(onto_iri, last_modification_date)
101
+ onto_serialised = next(iter(serialise_json(onto_g)))
102
+ cls_g = _make_one_class_graph(cls)
103
+ cls_serialised = serialise_json(cls_g)
104
+ onto_serialised["@graph"] = cls_serialised
105
+ return onto_serialised
106
+
107
+
108
+ def _make_one_class_graph(cls: ParsedClass) -> Graph:
109
+ trips: list[tuple[URIRef, Literal | URIRef]] = [(RDF.type, OWL.Class)]
110
+ trips.extend([(RDFS.label, Literal(lbl, lang=lang_tag)) for lang_tag, lbl in cls.labels.items()])
111
+ trips.extend([(RDFS.subClassOf, URIRef(x)) for x in cls.supers])
112
+ if cls.comments:
113
+ trips.extend([(RDFS.comment, Literal(cmnt, lang=lang_tag)) for lang_tag, cmnt in cls.comments.items()])
114
+
115
+ cls_iri = URIRef(cls.name)
116
+ g = Graph()
117
+ for p, o in trips:
118
+ g.add((cls_iri, p, o))
119
+ return g
@@ -0,0 +1,44 @@
1
+ from typing import Any
2
+
3
+ from dsp_tools.commands.create.models.parsed_project import ParsedGroup
4
+ from dsp_tools.commands.create.models.parsed_project import ParsedProjectMetadata
5
+ from dsp_tools.commands.create.models.parsed_project import ParsedUser
6
+
7
+
8
+ def serialise_one_group(group: ParsedGroup, project_iri: str) -> dict[str, Any]:
9
+ return {
10
+ "name": group.name,
11
+ "descriptions": [{"value": desc.text, "language": desc.lang} for desc in group.descriptions],
12
+ "project": project_iri,
13
+ "status": True,
14
+ "selfjoin": False,
15
+ }
16
+
17
+
18
+ def serialise_one_user_for_creation(user: ParsedUser) -> dict[str, Any]:
19
+ return {
20
+ "username": user.username,
21
+ "email": user.email,
22
+ "givenName": user.given_name,
23
+ "familyName": user.family_name,
24
+ "password": user.password,
25
+ "lang": user.lang,
26
+ "status": True,
27
+ "systemAdmin": False,
28
+ }
29
+
30
+
31
+ def serialise_project(project: ParsedProjectMetadata) -> dict[str, Any]:
32
+ descriptions = [{"value": value, "language": lang} for lang, value in project.descriptions.items()]
33
+ info = {
34
+ "shortcode": project.shortcode,
35
+ "shortname": project.shortname,
36
+ "longname": project.longname,
37
+ "description": descriptions,
38
+ "keywords": project.keywords,
39
+ "status": True,
40
+ "selfjoin": False,
41
+ }
42
+ if project.enabled_licenses:
43
+ info["enabledLicenses"] = project.enabled_licenses
44
+ return info
@@ -0,0 +1,101 @@
1
+ # Excel2JSON Module
2
+
3
+ This module converts Excel files into JSON project files for DSP-TOOLS.
4
+
5
+ ## Module Structure
6
+
7
+ ### Core Functions
8
+
9
+ - `excel2json/project.py` - Main entry point that orchestrates the conversion of Excel files to complete JSON project files
10
+ - `excel2json/properties.py` - Converts property definitions from Excel to JSON format
11
+ - `excel2json/resources.py` - Converts resource class definitions from Excel to JSON format
12
+ - `excel2json/json_header.py` - Processes project metadata from Excel
13
+ - `excel2json/lists.py` - Handles list definitions (hierarchical vocabularies)
14
+
15
+ ### Models
16
+
17
+ - `models/ontology.py` - Data models for ontology elements (OntoProperty, OntoResource, etc.)
18
+ - `models/json_header.py` - Data models for project header information
19
+ - `models/input_error.py` - Error handling and validation models
20
+ - `lists/models/` - Models specific to list processing
21
+
22
+ ### Utilities
23
+
24
+ - `utils.py` - Shared utility functions for Excel processing
25
+ - `lists/utils.py` - List-specific utilities
26
+ - `lists/compliance_checks.py` - Validation logic for list structures
27
+
28
+ ## Key Design Patterns
29
+
30
+ ### Excel Processing Pipeline
31
+
32
+ 1. **Read and Clean** - Excel files are read and cleaned using pandas
33
+ 2. **Validate Structure** - Column presence and data integrity checks
34
+ 3. **Parse Rows** - Individual rows converted to model objects
35
+ 4. **Serialize** - Model objects converted to JSON format
36
+ 5. **Validate Output** - JSON schema validation against DSP specifications
37
+
38
+ ### Error Handling
39
+
40
+ - Comprehensive error collection during parsing
41
+ - Position tracking for Excel cell-level error reporting
42
+ - Structured error models for different error types
43
+ - Non-blocking validation (collect all errors before failing)
44
+
45
+ ### Optional Columns
46
+
47
+ - If the user has omitted optional Excel columns, the python code adds these columns to the pandas df,
48
+ using the `add_optional_columns()` utility
49
+ - Missing optional columns are added as empty to maintain consistent DataFrame structure
50
+ - Optional fields in models are handled with `foo | None` types
51
+
52
+ ## Testing Strategy
53
+
54
+ ### Unit Tests
55
+
56
+ - Test individual parsing functions with minimal data
57
+ - Mock DataFrame inputs for isolated testing
58
+ - Test error conditions and edge cases
59
+ - Test model serialization/deserialization
60
+
61
+ ### Integration Tests
62
+
63
+ - Test with real Excel files from testdata
64
+ - End-to-end conversion validation
65
+ - JSON schema compliance testing
66
+
67
+ ## Column Processing Pattern
68
+
69
+ When adding new optional columns:
70
+
71
+ 1. **Define Column** - Add column name to expected columns list
72
+ 2. **Add to Optional** - Use `add_optional_columns()` to handle missing optional columns
73
+ 3. **Parse in Row Handler** - Extract value in `_get_*_from_row()` functions
74
+ 4. **Update Model** - Add field to corresponding dataclass model
75
+ 5. **Serialize** - Include in `serialise()` method when present
76
+ 6. **Test** - Unit and integration tests for new functionality
77
+
78
+ ## Common Patterns
79
+
80
+ ### Reading Excel Files
81
+
82
+ ```python
83
+ df_dict = read_and_clean_all_sheets(excel_file)
84
+ df = add_optional_columns(df, optional_columns)
85
+ ```
86
+
87
+ ### Parsing Optional Values
88
+
89
+ ```python
90
+ value = None if pd.isna(row["optional_column"]) else str(row["optional_column"]).strip()
91
+ ```
92
+
93
+ ### Model Serialization
94
+
95
+ ```python
96
+ def serialise(self) -> dict[str, Any]:
97
+ result = {"required_field": self.required_field}
98
+ if self.optional_field:
99
+ result["optional_field"] = self.optional_field
100
+ return result
101
+ ```
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from pathlib import Path
4
5
 
5
6
  import pandas as pd
@@ -13,23 +14,24 @@ from dsp_tools.commands.excel2json.models.input_error import InvalidExcelContent
13
14
  from dsp_tools.commands.excel2json.models.input_error import MissingValuesProblem
14
15
  from dsp_tools.commands.excel2json.models.input_error import MoreThanOneRowProblem
15
16
  from dsp_tools.commands.excel2json.models.input_error import PositionInExcel
16
- from dsp_tools.commands.excel2json.models.input_error import Problem
17
17
  from dsp_tools.commands.excel2json.models.input_error import RequiredColumnMissingProblem
18
18
  from dsp_tools.commands.excel2json.models.json_header import Descriptions
19
19
  from dsp_tools.commands.excel2json.models.json_header import EmptyJsonHeader
20
20
  from dsp_tools.commands.excel2json.models.json_header import FilledJsonHeader
21
21
  from dsp_tools.commands.excel2json.models.json_header import JsonHeader
22
22
  from dsp_tools.commands.excel2json.models.json_header import Keywords
23
+ from dsp_tools.commands.excel2json.models.json_header import Licenses
23
24
  from dsp_tools.commands.excel2json.models.json_header import Prefixes
24
25
  from dsp_tools.commands.excel2json.models.json_header import Project
25
26
  from dsp_tools.commands.excel2json.models.json_header import User
26
- from dsp_tools.commands.excel2json.models.json_header import UserRole
27
27
  from dsp_tools.commands.excel2json.models.json_header import Users
28
28
  from dsp_tools.commands.excel2json.utils import check_contains_required_columns
29
29
  from dsp_tools.commands.excel2json.utils import find_missing_required_values
30
30
  from dsp_tools.commands.excel2json.utils import read_and_clean_all_sheets
31
- from dsp_tools.models.exceptions import InputError
32
- from dsp_tools.utils.uri_util import is_uri
31
+ from dsp_tools.error.custom_warnings import DspToolsFutureWarning
32
+ from dsp_tools.error.exceptions import InputError
33
+ from dsp_tools.error.problems import Problem
34
+ from dsp_tools.utils.data_formats.uri_util import is_uri
33
35
 
34
36
 
35
37
  def get_json_header(excel_filepath: Path) -> JsonHeader:
@@ -59,6 +61,7 @@ def get_json_header(excel_filepath: Path) -> JsonHeader:
59
61
 
60
62
 
61
63
  def _do_all_checks(df_dict: dict[str, pd.DataFrame]) -> ExcelFileProblem | None:
64
+ _futurewarning_about_inexistent_license_info(df_dict)
62
65
  if file_problems := _check_if_sheets_are_filled_and_exist(df_dict):
63
66
  return file_problems
64
67
  sheet_problems: list[Problem] = []
@@ -70,6 +73,9 @@ def _do_all_checks(df_dict: dict[str, pd.DataFrame]) -> ExcelFileProblem | None:
70
73
  sheet_problems.append(description_problem)
71
74
  if keywords_problem := _check_keywords(df_dict["keywords"]):
72
75
  sheet_problems.append(keywords_problem)
76
+ if (licenses_df := df_dict.get("licenses")) is not None:
77
+ if license_problem := _check_licenses(licenses_df):
78
+ sheet_problems.append(license_problem)
73
79
  if (user_df := df_dict.get("users")) is not None:
74
80
  if user_problems := _check_all_users(user_df):
75
81
  sheet_problems.append(user_problems)
@@ -78,6 +84,15 @@ def _do_all_checks(df_dict: dict[str, pd.DataFrame]) -> ExcelFileProblem | None:
78
84
  return None
79
85
 
80
86
 
87
+ def _futurewarning_about_inexistent_license_info(df_dict: dict[str, pd.DataFrame]) -> None:
88
+ if df_dict.get("licenses") is None:
89
+ msg = (
90
+ "The json_header.xlsx file does not have a sheet containing the enabled licenses. "
91
+ "Please note that this will become mandatory in the future."
92
+ )
93
+ warnings.warn(DspToolsFutureWarning(msg))
94
+
95
+
81
96
  def _check_if_sheets_are_filled_and_exist(df_dict: dict[str, pd.DataFrame]) -> ExcelFileProblem | None:
82
97
  expected_sheets = ["prefixes", "project", "description", "keywords"]
83
98
 
@@ -117,7 +132,7 @@ def _check_prefixes(df: pd.DataFrame) -> ExcelSheetProblem | None:
117
132
 
118
133
  def _check_project_sheet(df: pd.DataFrame) -> ExcelSheetProblem | None:
119
134
  problems: list[Problem] = []
120
- cols = {"shortcode", "shortname", "longname"}
135
+ cols = {"shortcode", "shortname", "longname", "default_permissions"}
121
136
  if missing_cols := check_contains_required_columns(df, cols):
122
137
  problems.append(missing_cols)
123
138
  if len(df) > 1:
@@ -126,6 +141,14 @@ def _check_project_sheet(df: pd.DataFrame) -> ExcelSheetProblem | None:
126
141
  return ExcelSheetProblem("project", problems)
127
142
  if missing_values := find_missing_required_values(df, list(cols)):
128
143
  return ExcelSheetProblem("project", [MissingValuesProblem(missing_values)])
144
+ perm_value = str(df.loc[0, "default_permissions"]).strip().lower()
145
+ if perm_value not in ["public", "private"]:
146
+ prob = InvalidExcelContentProblem(
147
+ expected_content="One of: public, private",
148
+ actual_content=perm_value,
149
+ excel_position=PositionInExcel(column="default_permissions", row=2),
150
+ )
151
+ return ExcelSheetProblem("project", [prob])
129
152
  return None
130
153
 
131
154
 
@@ -148,13 +171,20 @@ def _check_keywords(df: pd.DataFrame) -> ExcelSheetProblem | None:
148
171
  return None
149
172
 
150
173
 
174
+ def _check_licenses(df: pd.DataFrame) -> ExcelSheetProblem | None:
175
+ if missing_cols := check_contains_required_columns(df, {"enabled"}):
176
+ return ExcelSheetProblem("licenses", [missing_cols])
177
+ return None
178
+
179
+
151
180
  def _check_all_users(df: pd.DataFrame) -> ExcelSheetProblem | None:
152
181
  if not len(df) > 0:
153
182
  return None
154
- columns = ["username", "email", "givenname", "familyname", "password", "lang", "role"]
155
- if missing_cols := check_contains_required_columns(df, set(columns)):
183
+ required_columns = ["username", "email", "givenname", "password", "familyname", "lang", "role"]
184
+ if missing_cols := check_contains_required_columns(df, set(required_columns)):
156
185
  return ExcelSheetProblem("users", [missing_cols])
157
- if missing_vals := find_missing_required_values(df, columns):
186
+ required_values = ["username", "email", "givenname", "familyname", "lang", "role"]
187
+ if missing_vals := find_missing_required_values(df, required_values):
158
188
  return ExcelSheetProblem("users", [MissingValuesProblem(missing_vals)])
159
189
  problems: list[Problem] = []
160
190
  for i, row in df.iterrows():
@@ -198,10 +228,10 @@ def _check_email(email: str, row_num: int) -> InvalidExcelContentProblem | None:
198
228
 
199
229
 
200
230
  def _check_role(value: str, row_num: int) -> InvalidExcelContentProblem | None:
201
- possible_roles = ["projectadmin", "systemadmin", "projectmember"]
231
+ possible_roles = ["projectadmin", "projectmember"]
202
232
  if value.lower() not in possible_roles:
203
233
  return InvalidExcelContentProblem(
204
- expected_content="One of: projectadmin, systemadmin, projectmember",
234
+ expected_content="One of: projectadmin, projectmember",
205
235
  actual_content=value,
206
236
  excel_position=PositionInExcel(column="role", row=row_num),
207
237
  )
@@ -224,18 +254,25 @@ def _extract_project(df_dict: dict[str, pd.DataFrame]) -> Project:
224
254
  project_df = df_dict["project"]
225
255
  extracted_description = _extract_descriptions(df_dict["description"])
226
256
  extracted_keywords = _extract_keywords(df_dict["keywords"])
257
+ if (lic_df := df_dict.get("licenses")) is not None:
258
+ extracted_licenses = _extract_licenses(lic_df)
259
+ else:
260
+ extracted_licenses = Licenses([])
227
261
  all_users = None
228
262
  if (user_df := df_dict.get("users")) is not None:
229
263
  if len(user_df) > 0:
230
264
  all_users = _extract_users(user_df)
231
265
  shortcode = str(project_df.loc[0, "shortcode"]).zfill(4)
266
+ default_permissions = str(project_df.loc[0, "default_permissions"]).strip().lower()
232
267
  return Project(
233
268
  shortcode=shortcode,
234
269
  shortname=str(project_df.loc[0, "shortname"]),
235
270
  longname=str(project_df.loc[0, "longname"]),
236
271
  descriptions=extracted_description,
237
272
  keywords=extracted_keywords,
273
+ licenses=extracted_licenses,
238
274
  users=all_users,
275
+ default_permissions=default_permissions,
239
276
  )
240
277
 
241
278
 
@@ -256,6 +293,11 @@ def _extract_keywords(df: pd.DataFrame) -> Keywords:
256
293
  return Keywords(keywords)
257
294
 
258
295
 
296
+ def _extract_licenses(df: pd.DataFrame) -> Licenses:
297
+ licenses = list({x for x in df["enabled"] if not pd.isna(x)})
298
+ return Licenses(licenses)
299
+
300
+
259
301
  def _extract_users(df: pd.DataFrame) -> Users:
260
302
  users = []
261
303
  for _, row in df.iterrows():
@@ -265,23 +307,15 @@ def _extract_users(df: pd.DataFrame) -> Users:
265
307
 
266
308
 
267
309
  def _extract_one_user(row: pd.Series[str]) -> User:
268
- user_role = _get_role(row["role"])
310
+ isProjectAdmin = row["role"].lower() == "projectadmin"
311
+ if pd.isna(pw := row["password"]):
312
+ pw = None
269
313
  return User(
270
314
  username=row["username"],
271
315
  email=row["email"],
272
316
  givenName=row["givenname"],
273
317
  familyName=row["familyname"],
274
- password=row["password"],
318
+ password=pw,
275
319
  lang=row["lang"],
276
- role=user_role,
320
+ isProjectAdmin=isProjectAdmin,
277
321
  )
278
-
279
-
280
- def _get_role(value: str) -> UserRole:
281
- match value.lower():
282
- case "projectadmin":
283
- return UserRole(project_admin=True)
284
- case "systemadmin":
285
- return UserRole(sys_admin=True)
286
- case _:
287
- return UserRole()
@@ -9,32 +9,32 @@ import pandas as pd
9
9
  import regex
10
10
  from loguru import logger
11
11
 
12
+ from dsp_tools.commands.excel2json.lists.models.deserialise import Columns
13
+ from dsp_tools.commands.excel2json.lists.models.deserialise import ExcelSheet
14
+ from dsp_tools.commands.excel2json.lists.models.input_error import CollectedSheetProblems
15
+ from dsp_tools.commands.excel2json.lists.models.input_error import DuplicateIDProblem
16
+ from dsp_tools.commands.excel2json.lists.models.input_error import DuplicatesCustomIDInProblem
17
+ from dsp_tools.commands.excel2json.lists.models.input_error import DuplicatesInSheetProblem
18
+ from dsp_tools.commands.excel2json.lists.models.input_error import DuplicatesListNameProblem
19
+ from dsp_tools.commands.excel2json.lists.models.input_error import ListCreationProblem
20
+ from dsp_tools.commands.excel2json.lists.models.input_error import ListInformation
21
+ from dsp_tools.commands.excel2json.lists.models.input_error import ListSheetComplianceProblem
22
+ from dsp_tools.commands.excel2json.lists.models.input_error import ListSheetContentProblem
23
+ from dsp_tools.commands.excel2json.lists.models.input_error import MinimumRowsProblem
24
+ from dsp_tools.commands.excel2json.lists.models.input_error import MissingExpectedColumn
25
+ from dsp_tools.commands.excel2json.lists.models.input_error import MissingNodeColumn
26
+ from dsp_tools.commands.excel2json.lists.models.input_error import MissingNodeTranslationProblem
27
+ from dsp_tools.commands.excel2json.lists.models.input_error import MissingTranslationsSheetProblem
28
+ from dsp_tools.commands.excel2json.lists.models.input_error import MultipleListPerSheetProblem
29
+ from dsp_tools.commands.excel2json.lists.models.input_error import NodesPerRowProblem
30
+ from dsp_tools.commands.excel2json.lists.models.input_error import SheetProblem
31
+ from dsp_tools.commands.excel2json.lists.utils import get_columns_of_preferred_lang
32
+ from dsp_tools.commands.excel2json.lists.utils import get_hierarchy_nums
33
+ from dsp_tools.commands.excel2json.lists.utils import get_lang_string_from_column_name
12
34
  from dsp_tools.commands.excel2json.models.input_error import PositionInExcel
13
- from dsp_tools.commands.excel2json.models.input_error import Problem
14
- from dsp_tools.commands.excel2json.new_lists.models.deserialise import Columns
15
- from dsp_tools.commands.excel2json.new_lists.models.deserialise import ExcelSheet
16
- from dsp_tools.commands.excel2json.new_lists.models.input_error import CollectedSheetProblems
17
- from dsp_tools.commands.excel2json.new_lists.models.input_error import DuplicateIDProblem
18
- from dsp_tools.commands.excel2json.new_lists.models.input_error import DuplicatesCustomIDInProblem
19
- from dsp_tools.commands.excel2json.new_lists.models.input_error import DuplicatesInSheetProblem
20
- from dsp_tools.commands.excel2json.new_lists.models.input_error import DuplicatesListNameProblem
21
- from dsp_tools.commands.excel2json.new_lists.models.input_error import ListCreationProblem
22
- from dsp_tools.commands.excel2json.new_lists.models.input_error import ListInformation
23
- from dsp_tools.commands.excel2json.new_lists.models.input_error import ListSheetComplianceProblem
24
- from dsp_tools.commands.excel2json.new_lists.models.input_error import ListSheetContentProblem
25
- from dsp_tools.commands.excel2json.new_lists.models.input_error import MinimumRowsProblem
26
- from dsp_tools.commands.excel2json.new_lists.models.input_error import MissingExpectedColumn
27
- from dsp_tools.commands.excel2json.new_lists.models.input_error import MissingNodeColumn
28
- from dsp_tools.commands.excel2json.new_lists.models.input_error import MissingNodeTranslationProblem
29
- from dsp_tools.commands.excel2json.new_lists.models.input_error import MissingTranslationsSheetProblem
30
- from dsp_tools.commands.excel2json.new_lists.models.input_error import MultipleListPerSheetProblem
31
- from dsp_tools.commands.excel2json.new_lists.models.input_error import NodesPerRowProblem
32
- from dsp_tools.commands.excel2json.new_lists.models.input_error import SheetProblem
33
- from dsp_tools.commands.excel2json.new_lists.utils import get_columns_of_preferred_lang
34
- from dsp_tools.commands.excel2json.new_lists.utils import get_hierarchy_nums
35
- from dsp_tools.commands.excel2json.new_lists.utils import get_lang_string_from_column_name
36
- from dsp_tools.models.custom_warnings import DspToolsUserWarning
37
- from dsp_tools.models.exceptions import InputError
35
+ from dsp_tools.error.custom_warnings import DspToolsUserWarning
36
+ from dsp_tools.error.exceptions import InputError
37
+ from dsp_tools.error.problems import Problem
38
38
 
39
39
 
40
40
  def make_all_excel_compliance_checks(sheet_list: list[ExcelSheet]) -> None:
@@ -277,7 +277,7 @@ def _check_for_erroneous_entries_one_column_level(
277
277
  def _check_for_erroneous_entries_one_grouped_df(
278
278
  group: pd.DataFrame, target_cols: list[str]
279
279
  ) -> list[NodesPerRowProblem]:
280
- problems = []
280
+ problems: list[NodesPerRowProblem] = []
281
281
  first_col = min(group.index)
282
282
  # The first row is the current parent node. The remaining columns in that row must be empty.
283
283
  if not group.loc[first_col, target_cols[1:]].isna().all():
@@ -9,20 +9,20 @@ from typing import Optional
9
9
  import pandas as pd
10
10
  import regex
11
11
 
12
- from dsp_tools.commands.excel2json.lists import validate_lists_section_with_schema
13
- from dsp_tools.commands.excel2json.new_lists.compliance_checks import make_all_excel_compliance_checks
14
- from dsp_tools.commands.excel2json.new_lists.models.deserialise import Columns
15
- from dsp_tools.commands.excel2json.new_lists.models.deserialise import ExcelSheet
16
- from dsp_tools.commands.excel2json.new_lists.models.serialise import ListNode
17
- from dsp_tools.commands.excel2json.new_lists.models.serialise import ListRoot
18
- from dsp_tools.commands.excel2json.new_lists.utils import get_column_info
19
- from dsp_tools.commands.excel2json.new_lists.utils import get_columns_of_preferred_lang
20
- from dsp_tools.commands.excel2json.new_lists.utils import get_lang_string_from_column_name
12
+ from dsp_tools.commands.excel2json.lists.compliance_checks import make_all_excel_compliance_checks
13
+ from dsp_tools.commands.excel2json.lists.models.deserialise import Columns
14
+ from dsp_tools.commands.excel2json.lists.models.deserialise import ExcelSheet
15
+ from dsp_tools.commands.excel2json.lists.models.serialise import ListNode
16
+ from dsp_tools.commands.excel2json.lists.models.serialise import ListRoot
17
+ from dsp_tools.commands.excel2json.lists.utils import get_column_info
18
+ from dsp_tools.commands.excel2json.lists.utils import get_columns_of_preferred_lang
19
+ from dsp_tools.commands.excel2json.lists.utils import get_lang_string_from_column_name
20
+ from dsp_tools.commands.excel2json.old_lists import validate_lists_section_with_schema
21
21
  from dsp_tools.commands.excel2json.utils import add_optional_columns
22
22
  from dsp_tools.commands.excel2json.utils import read_and_clean_all_sheets
23
23
 
24
24
 
25
- def new_excel2lists(
25
+ def excel2lists(
26
26
  excelfolder: str | Path,
27
27
  path_to_output_file: Optional[Path] = None,
28
28
  ) -> tuple[list[dict[str, Any]], bool]:
@@ -132,7 +132,7 @@ def _remove_duplicate_ids_in_all_excels(duplicate_ids: list[str], sheet_list: li
132
132
  df = sheet.df
133
133
  for i, row in df.iterrows():
134
134
  if row["id"] in duplicate_ids and pd.isna(row["id (optional)"]):
135
- df.at[i, "id"] = _construct_non_duplicate_id_string(df.iloc[int(str(i))], sheet.col_info.preferred_lang)
135
+ df.loc[i, "id"] = _construct_non_duplicate_id_string(row, sheet.col_info.preferred_lang) # type: ignore[index]
136
136
  all_sheets.append(
137
137
  ExcelSheet(excel_name=sheet.excel_name, sheet_name=sheet.sheet_name, col_info=sheet.col_info, df=df)
138
138
  )
@@ -150,8 +150,8 @@ def _resolve_duplicate_ids_keep_custom_change_auto_id_one_df(df: pd.DataFrame, p
150
150
  """If there are duplicates in the id column, the auto_id is changed, the custom ID remains the same."""
151
151
  if (duplicate_filter := df["id"].duplicated(keep=False)).any():
152
152
  for i in duplicate_filter.index[duplicate_filter]:
153
- if pd.isna(df.at[i, "id (optional)"]):
154
- df.loc[i, "id"] = _construct_non_duplicate_id_string(df.iloc[i], preferred_language)
153
+ if pd.isna(df.loc[i, "id (optional)"]):
154
+ df.loc[i, "id"] = _construct_non_duplicate_id_string(df.loc[i], preferred_language)
155
155
  return df
156
156
 
157
157
 
@@ -167,7 +167,7 @@ def _create_auto_id_one_df(df: pd.DataFrame, preferred_language: str) -> pd.Data
167
167
  if pd.isna(row["id (optional)"]):
168
168
  for col in column_names:
169
169
  if pd.notna(row[col]):
170
- df.at[i, "auto_id"] = row[col]
170
+ df.loc[i, "auto_id"] = row[col] # type: ignore[index]
171
171
  break
172
172
  df = _resolve_duplicate_ids_for_auto_id_one_df(df, preferred_language)
173
173
  return df
@@ -177,7 +177,7 @@ def _resolve_duplicate_ids_for_auto_id_one_df(df: pd.DataFrame, preferred_langua
177
177
  """In case the auto_id is not unique; both auto_ids get a new ID by joining the node names of all the ancestors."""
178
178
  if (duplicate_filter := df["auto_id"].dropna().duplicated(keep=False)).any():
179
179
  for i in duplicate_filter.index[duplicate_filter]:
180
- df.at[i, "auto_id"] = _construct_non_duplicate_id_string(df.iloc[i], preferred_language)
180
+ df.loc[i, "auto_id"] = _construct_non_duplicate_id_string(df.loc[i], preferred_language)
181
181
  return df
182
182
 
183
183
 
@@ -190,17 +190,18 @@ def _construct_non_duplicate_id_string(row: pd.Series[Any], preferred_language:
190
190
 
191
191
 
192
192
  def _make_serialised_lists(sheet_list: list[ExcelSheet]) -> list[dict[str, Any]]:
193
- all_lists = []
193
+ all_lists: list[ListRoot] = []
194
194
  for sheet in sheet_list:
195
195
  all_lists.append(_make_one_list(sheet))
196
+ all_lists = sorted(all_lists, key=lambda x: x.id_)
196
197
  return [list_.to_dict() for list_ in all_lists]
197
198
 
198
199
 
199
200
  def _make_one_list(sheet: ExcelSheet) -> ListRoot:
200
201
  node_dict = _make_list_nodes_from_df(sheet.df, sheet.col_info)
201
- nodes_for_root = _add_nodes_to_parent(node_dict, sheet.df.at[0, "id"]) if node_dict else []
202
+ nodes_for_root = _add_nodes_to_parent(node_dict, str(sheet.df.at[0, "id"])) if node_dict else []
202
203
  return ListRoot(
203
- id_=sheet.df.at[0, "id"],
204
+ id_=str(sheet.df.at[0, "id"]),
204
205
  labels=_get_lang_dict(sheet.df.iloc[0], sheet.col_info.list_cols),
205
206
  nodes=nodes_for_root,
206
207
  comments=_get_lang_dict(sheet.df.iloc[0], sheet.col_info.comment_cols),
@@ -7,10 +7,10 @@ from typing import Protocol
7
7
 
8
8
  from dsp_tools.commands.excel2json.models.input_error import ExcelFileProblem
9
9
  from dsp_tools.commands.excel2json.models.input_error import PositionInExcel
10
- from dsp_tools.commands.excel2json.models.input_error import Problem
11
10
  from dsp_tools.commands.excel2json.models.input_error import grand_separator
12
11
  from dsp_tools.commands.excel2json.models.input_error import list_separator
13
12
  from dsp_tools.commands.excel2json.models.input_error import medium_separator
13
+ from dsp_tools.error.problems import Problem
14
14
 
15
15
 
16
16
  @dataclass(frozen=True)
@@ -23,17 +23,6 @@ class ListCreationProblem:
23
23
  return title + grand_separator.join(msg)
24
24
 
25
25
 
26
- @dataclass(frozen=True)
27
- class ListNodeProblem:
28
- node_id: str
29
- problems: dict[str, str]
30
-
31
- def execute_error_protocol(self) -> str:
32
- msg = [f"The node '{self.node_id}' has the following problem(s):"]
33
- msg.extend([f"Field: '{key}', Problem: {value}" for key, value in self.problems.items()])
34
- return list_separator.join(msg)
35
-
36
-
37
26
  @dataclass
38
27
  class SheetProblem(Protocol):
39
28
  excel_name: str