tol-sdk 1.7.5b0__tar.gz → 1.7.5b3__tar.gz

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 (354) hide show
  1. {tol_sdk-1.7.5b0/src/tol_sdk.egg-info → tol_sdk-1.7.5b3}/PKG-INFO +1 -1
  2. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/pyproject.toml +1 -1
  3. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/detail_getter.py +1 -1
  4. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/client.py +3 -2
  5. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/__init__.py +2 -0
  6. tol_sdk-1.7.5b3/src/tol/flows/converters/incoming_sample_to_ena_sample_converter.py +130 -0
  7. tol_sdk-1.7.5b3/src/tol/flows/converters/incoming_sample_to_incoming_sample_with_lists_converter.py +46 -0
  8. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/auth/models.py +21 -12
  9. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/__init__.py +2 -1
  10. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/allowed_keys.py +2 -1
  11. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/allowed_values.py +2 -1
  12. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/allowed_values_from_datasource.py +9 -10
  13. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/assert_on_condition.py +6 -6
  14. tol_sdk-1.7.5b3/src/tol/validators/converter_and_validate.py +93 -0
  15. tol_sdk-1.7.5b3/src/tol/validators/ena_checklist.py +73 -0
  16. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/ena_submittable.py +1 -0
  17. tol_sdk-1.7.5b3/src/tol/validators/interfaces/__init__.py +5 -0
  18. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/interfaces/condition_evaluator.py +42 -1
  19. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/min_one_valid_value.py +1 -0
  20. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/mutually_exclusive.py +12 -8
  21. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/regex.py +29 -4
  22. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/regex_by_value.py +24 -4
  23. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/specimens_have_same_taxon.py +1 -1
  24. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/sts_fields.py +1 -0
  25. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/tolid.py +2 -1
  26. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/unique_values.py +2 -1
  27. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/validators/unique_whole_organisms.py +1 -1
  28. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3/src/tol_sdk.egg-info}/PKG-INFO +1 -1
  29. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol_sdk.egg-info/SOURCES.txt +4 -0
  30. tol_sdk-1.7.5b0/src/tol/validators/interfaces/__init__.py +0 -5
  31. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/LICENSE +0 -0
  32. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/MANIFEST.in +0 -0
  33. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/README.md +0 -0
  34. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/setup.cfg +0 -0
  35. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/certs/cacert.pem +0 -0
  36. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/__init__.py +0 -0
  37. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/actions/__init__.py +0 -0
  38. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/actions/action.py +0 -0
  39. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/actions/upsert_action.py +0 -0
  40. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/__init__.py +0 -0
  41. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/action.py +0 -0
  42. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/__init__.py +0 -0
  43. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/abc/__init__.py +0 -0
  44. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/abc/auth.py +0 -0
  45. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/abc/authorisation.py +0 -0
  46. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/asserts.py +0 -0
  47. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/blueprint.py +0 -0
  48. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/composite.py +0 -0
  49. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/config.py +0 -0
  50. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/auth/error.py +0 -0
  51. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/blueprint.py +0 -0
  52. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/controller.py +0 -0
  53. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/data_upload.py +0 -0
  54. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/__init__.py +0 -0
  55. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/aggregation_body.py +0 -0
  56. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/aggregation_parameters.py +0 -0
  57. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/auth_context.py +0 -0
  58. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/authenticate.py +0 -0
  59. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/data_body.py +0 -0
  60. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/filter_utils.py +0 -0
  61. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/list_get_parameters.py +0 -0
  62. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/relation_url.py +0 -0
  63. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/misc/stats_parameters.py +0 -0
  64. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/pipeline_steps.py +0 -0
  65. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_base/system.py +0 -0
  66. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/__init__.py +0 -0
  67. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/api_datasource.py +0 -0
  68. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/client.py +0 -0
  69. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/converter.py +0 -0
  70. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/exception.py +0 -0
  71. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/factory.py +0 -0
  72. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/filter.py +0 -0
  73. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/parser.py +0 -0
  74. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/validate.py +0 -0
  75. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/api_client/view.py +0 -0
  76. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/barcodes/__init__.py +0 -0
  77. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/barcodes/main.py +0 -0
  78. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/__init__.py +0 -0
  79. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/benchling_converter.py +0 -0
  80. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/benchling_datasource.py +0 -0
  81. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/benchling_warehouse_datasource.py +0 -0
  82. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/__init__.py +0 -0
  83. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/extraction_extraction_type_dna.sql +0 -0
  84. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/extraction_extraction_type_lres.sql +0 -0
  85. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/extraction_extraction_type_pooled_dna.sql +0 -0
  86. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/extraction_extraction_type_rna.sql +0 -0
  87. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/pacbio_prep.sql +0 -0
  88. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/pooled_pacbio_prep.sql +0 -0
  89. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/results_extraction_dna.sql +0 -0
  90. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/results_extraction_pooled.sql +0 -0
  91. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/results_extraction_rna.sql +0 -0
  92. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/results_pacbio_prep.sql +0 -0
  93. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/results_pacbio_prep_pooled.sql +0 -0
  94. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/sample.sql +0 -0
  95. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/sequencing_request_sequencing_platform_hic.sql +0 -0
  96. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/sequencing_request_sequencing_platform_pacbio.sql +0 -0
  97. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/sequencing_request_sequencing_platform_rnaseq.sql +0 -0
  98. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/sequencing_request_sequencing_platform_wgs.sql +0 -0
  99. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/benchling/sql/tissue_prep.sql +0 -0
  100. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/board/__init__.py +0 -0
  101. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/board/blueprint.py +0 -0
  102. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/bold/__init__.py +0 -0
  103. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/bold/bold_datasource.py +0 -0
  104. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/bold/client.py +0 -0
  105. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/bold/converter.py +0 -0
  106. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/bold/factory.py +0 -0
  107. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/bold/parser.py +0 -0
  108. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/cli/__init__.py +0 -0
  109. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/cli/cli.py +0 -0
  110. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/converter/__init__.py +0 -0
  111. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/converter/yaml/__init__.py +0 -0
  112. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/converter/yaml/model.py +0 -0
  113. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/converter/yaml/yaml_converter.py +0 -0
  114. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/copo/__init__.py +0 -0
  115. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/copo/client.py +0 -0
  116. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/copo/converter.py +0 -0
  117. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/copo/copo_datasource.py +0 -0
  118. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/copo/factory.py +0 -0
  119. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/copo/parser.py +0 -0
  120. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/__init__.py +0 -0
  121. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/attribute_metadata.py +0 -0
  122. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/core_converter.py +0 -0
  123. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/data_loader.py +0 -0
  124. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/data_object.py +0 -0
  125. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/data_object_converter.py +0 -0
  126. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/data_source_attribute_metadata.py +0 -0
  127. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/data_source_dict.py +0 -0
  128. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/datasource.py +0 -0
  129. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/datasource_error.py +0 -0
  130. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/datasource_filter.py +0 -0
  131. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/datasource_utils.py +0 -0
  132. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/factory.py +0 -0
  133. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/http_client.py +0 -0
  134. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/__init__.py +0 -0
  135. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/_filterable.py +0 -0
  136. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/_writer.py +0 -0
  137. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/aggregator.py +0 -0
  138. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/counter.py +0 -0
  139. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/cursor.py +0 -0
  140. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/declare.py +0 -0
  141. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/deleter.py +0 -0
  142. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/enricher.py +0 -0
  143. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/enum.py +0 -0
  144. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/group_statter.py +0 -0
  145. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/inserter.py +0 -0
  146. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/list_getter.py +0 -0
  147. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/operator_config.py +0 -0
  148. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/page_getter.py +0 -0
  149. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/relational.py +0 -0
  150. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/statter.py +0 -0
  151. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/summariser.py +0 -0
  152. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/updater.py +0 -0
  153. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/operator/upserter.py +0 -0
  154. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/relationship.py +0 -0
  155. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/requested_fields.py +0 -0
  156. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/session.py +0 -0
  157. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/core/validate.py +0 -0
  158. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/elastic/__init__.py +0 -0
  159. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/elastic/elastic_datasource.py +0 -0
  160. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/elastic/runtime_fields.py +0 -0
  161. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/eln/__init__.py +0 -0
  162. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/eln/auth.py +0 -0
  163. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/eln/eln_datasource.py +0 -0
  164. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/eln/entities.py +0 -0
  165. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/eln/generators.py +0 -0
  166. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/eln/sanitise.py +0 -0
  167. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/__init__.py +0 -0
  168. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/converter.py +0 -0
  169. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/ena_datasource.py +0 -0
  170. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/ena_methods.py +0 -0
  171. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/factory.py +0 -0
  172. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/filter.py +0 -0
  173. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/ena/parser.py +0 -0
  174. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/excel/__init__.py +0 -0
  175. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/excel/excel.py +0 -0
  176. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/excel/excel_datasource.py +0 -0
  177. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/excel/s3_factory.py +0 -0
  178. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/__init__.py +0 -0
  179. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_entity_to_benchling_worklist_item_converter_factory.py +0 -0
  180. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_extraction_to_elastic_extraction_converter.py +0 -0
  181. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_extraction_to_elastic_sequencing_request_converter.py +0 -0
  182. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_sample_casm_to_sts_sample_converter.py +0 -0
  183. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_sample_to_elastic_sample_converter.py +0 -0
  184. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_sequencing_request_to_elastic_sequencing_request_converter.py +0 -0
  185. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_tissue_prep_to_elastic_tissue_prep_converter.py +0 -0
  186. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/benchling_tissue_to_sts_sample_converter.py +0 -0
  187. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/bioscan_extra_pantheon_species_to_elastic_sample_update_converter.py +0 -0
  188. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/bioscan_image_to_elastic_sample_update_converter.py +0 -0
  189. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/bioscan_qc_specimen_to_elastic_sample_update_converter.py +0 -0
  190. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/bioscan_qc_uksi_entry_to_elastic_sample_update_converter.py +0 -0
  191. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/bold_bin_to_elastic_sample_update_converter.py +0 -0
  192. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/bold_sample_to_elastic_sample_update_converter.py +0 -0
  193. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_object_to_portaldb_object_converter.py +0 -0
  194. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sample_to_benchling_tissue_converter.py +0 -0
  195. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sample_to_benchling_tissue_update_converter.py +0 -0
  196. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sample_to_bold_sample_converter.py +0 -0
  197. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sample_to_elastic_sequencing_request_update_converter.py +0 -0
  198. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sample_to_sts_sample_converter.py +0 -0
  199. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sequencing_request_to_elastic_run_data_update_converter.py +0 -0
  200. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_sequencing_request_to_sts_sequencing_request_converter.py +0 -0
  201. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_species_to_sts_species_converter.py +0 -0
  202. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_tolid_to_elastic_curation_update_converter.py +0 -0
  203. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_tolid_to_elastic_genome_note_update_converter.py +0 -0
  204. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/elastic_tolid_to_elastic_sample_update_converter.py +0 -0
  205. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/gap_assembly_to_elastic_assembly_analysis_converter.py +0 -0
  206. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/gap_assembly_to_elastic_assembly_converter.py +0 -0
  207. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/genome_notes_genome_note_to_elastic_genome_note_converter.py +0 -0
  208. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/goat_taxon_to_elastic_species_converter.py +0 -0
  209. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/grit_issue_to_elastic_curation_converter.py +0 -0
  210. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/informatics_tolid_to_elastic_tolid_converter.py +0 -0
  211. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/labwhere_location_to_elastic_sample_update_converter.py +0 -0
  212. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/labwhere_location_to_sts_tray_converter.py +0 -0
  213. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/mlwh_extraction_to_elastic_extraction_converter.py +0 -0
  214. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/mlwh_run_data_to_elastic_run_data_converter.py +0 -0
  215. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/mlwh_sequencing_request_to_elastic_sequencing_request_converter.py +0 -0
  216. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_banked_sample_to_elastic_sample_converter.py +0 -0
  217. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_manifest_to_elastic_manifest_converter.py +0 -0
  218. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_project_to_elastic_sample_update_converter.py +0 -0
  219. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_sample_project_to_elastic_sample_converter.py +0 -0
  220. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_sample_to_casm_benchling_converter.py +0 -0
  221. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_sampleset_to_elastic_sampleset_converter.py +0 -0
  222. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/sts_species_to_elastic_species_converter.py +0 -0
  223. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/tolid_specimen_to_elastic_tolid_converter.py +0 -0
  224. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/tolqc_data_to_elastic_run_data_converter.py +0 -0
  225. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/tolqc_sample_to_elastic_sequencing_request_converter.py +0 -0
  226. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/tolqc_species_to_elastic_species_converter.py +0 -0
  227. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/treeofsex_species_to_treeofsexwh_species_converter.py +0 -0
  228. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/converters/treeofsex_upload_to_treeofsex_attribute_converter.py +0 -0
  229. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/logger.py +0 -0
  230. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/secrets.py +0 -0
  231. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/flows/sequencing_submissions.py +0 -0
  232. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/gap/__init__.py +0 -0
  233. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/gap/gap_datasource.py +0 -0
  234. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/__init__.py +0 -0
  235. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/client.py +0 -0
  236. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/converter.py +0 -0
  237. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/factory.py +0 -0
  238. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/filter.py +0 -0
  239. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/goat_datasource.py +0 -0
  240. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/goat/parser.py +0 -0
  241. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/google_sheets/__init__.py +0 -0
  242. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/google_sheets/google_sheet_datasource.py +0 -0
  243. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/irods/__init__.py +0 -0
  244. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/irods/irods_datasource.py +0 -0
  245. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/__init__.py +0 -0
  246. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/client.py +0 -0
  247. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/converter.py +0 -0
  248. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/factory.py +0 -0
  249. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/filter.py +0 -0
  250. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/jira_datasource.py +0 -0
  251. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/mapper.py +0 -0
  252. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/parser.py +0 -0
  253. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/jira/sort.py +0 -0
  254. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/json/__init__.py +0 -0
  255. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/json/json_datasource.py +0 -0
  256. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/json/s3_json_datasource.py +0 -0
  257. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/labwhere/__init__.py +0 -0
  258. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/labwhere/client.py +0 -0
  259. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/labwhere/converter.py +0 -0
  260. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/labwhere/factory.py +0 -0
  261. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/labwhere/labwhere_datasource.py +0 -0
  262. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/labwhere/parser.py +0 -0
  263. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/markdown.py +0 -0
  264. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/mlwh/__init__.py +0 -0
  265. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/mlwh/mlwh_datasource.py +0 -0
  266. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/prefect/__init__.py +0 -0
  267. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/prefect/converter.py +0 -0
  268. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/prefect/factory.py +0 -0
  269. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/prefect/filter.py +0 -0
  270. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/prefect/prefect_datasource.py +0 -0
  271. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/prefect/prefect_object.py +0 -0
  272. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/s3/__init__.py +0 -0
  273. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/s3/converter.py +0 -0
  274. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/s3/factory.py +0 -0
  275. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/s3/parser.py +0 -0
  276. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/s3/s3_datasource.py +0 -0
  277. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/__init__.py +0 -0
  278. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/configuration.py +0 -0
  279. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/consumer.py +0 -0
  280. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/message_builder.py +0 -0
  281. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/messages.py +0 -0
  282. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/response_processors.py +0 -0
  283. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sciops/sequencing_datasource.py +0 -0
  284. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/services/__init__.py +0 -0
  285. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/services/s3_client.py +0 -0
  286. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/__init__.py +0 -0
  287. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/benchling.py +0 -0
  288. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/benchling_warehouse.py +0 -0
  289. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/bioscan.py +0 -0
  290. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/bioscan_extra.py +0 -0
  291. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/bioscan_image.py +0 -0
  292. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/bioscan_qc.py +0 -0
  293. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/bold.py +0 -0
  294. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/copo.py +0 -0
  295. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/defaults.py +0 -0
  296. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/elastic.py +0 -0
  297. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/ena.py +0 -0
  298. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/gap.py +0 -0
  299. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/genome_notes.py +0 -0
  300. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/goat.py +0 -0
  301. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/grit.py +0 -0
  302. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/informatics.py +0 -0
  303. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/labwhere.py +0 -0
  304. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/mlwh.py +0 -0
  305. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/portal.py +0 -0
  306. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/portal_attributes.py +0 -0
  307. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/portaldb.py +0 -0
  308. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/prefect.py +0 -0
  309. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/sciops.py +0 -0
  310. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/sts.py +0 -0
  311. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/sts_legacy.py +0 -0
  312. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/tolid.py +0 -0
  313. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/tolqc.py +0 -0
  314. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/tolqc_legacy.py +0 -0
  315. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/treeofsex.py +0 -0
  316. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/uksi_qc.py.py +0 -0
  317. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sources/workflows.py +0 -0
  318. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/__init__.py +0 -0
  319. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/action/__init__.py +0 -0
  320. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/action/factory.py +0 -0
  321. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/auth/__init__.py +0 -0
  322. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/auth/blueprint.py +0 -0
  323. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/cast.py +0 -0
  324. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/database.py +0 -0
  325. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/ds_session.py +0 -0
  326. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/exception.py +0 -0
  327. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/ext.py +0 -0
  328. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/factory.py +0 -0
  329. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/filter.py +0 -0
  330. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/model.py +0 -0
  331. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/pipeline_step/__init__.py +0 -0
  332. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/pipeline_step/factory.py +0 -0
  333. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/relationship.py +0 -0
  334. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/session.py +0 -0
  335. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/sort.py +0 -0
  336. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/sql_converter.py +0 -0
  337. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/sql_datasource.py +0 -0
  338. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/standard/__init__.py +0 -0
  339. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sql/standard/factory.py +0 -0
  340. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/status/__init__.py +0 -0
  341. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/status/status_datasource.py +0 -0
  342. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sts/__init__.py +0 -0
  343. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sts/sts.py +0 -0
  344. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sts/sts_datasource.py +0 -0
  345. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/sts/sts_requests.py +0 -0
  346. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/treeval/__init__.py +0 -0
  347. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/treeval/treeval_datasource.py +0 -0
  348. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/utils/__init__.py +0 -0
  349. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/utils/csv.py +0 -0
  350. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol/utils/s3.py +0 -0
  351. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol_sdk.egg-info/dependency_links.txt +0 -0
  352. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol_sdk.egg-info/entry_points.txt +0 -0
  353. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol_sdk.egg-info/requires.txt +0 -0
  354. {tol_sdk-1.7.5b0 → tol_sdk-1.7.5b3}/src/tol_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tol-sdk
3
- Version: 1.7.5b0
3
+ Version: 1.7.5b3
4
4
  Summary: SDK for interaction with ToL, Sanger and external services
5
5
  Author-email: ToL Platforms Team <tol-platforms@sanger.ac.uk>
6
6
  License: MIT
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "tol-sdk"
11
- version = "1.7.5-beta"
11
+ version = "1.7.5-beta3"
12
12
  description = "SDK for interaction with ToL, Sanger and external services"
13
13
  readme = "README.md"
14
14
  authors = [
@@ -82,7 +82,7 @@ class DetailGetter(ABC):
82
82
  for id_ in object_ids:
83
83
  seekable_objects.seek(0)
84
84
  for obj in seekable_objects:
85
- if obj.id == id_:
85
+ if str(obj.id) == str(id_):
86
86
  yield obj
87
87
  break
88
88
  else:
@@ -116,12 +116,13 @@ class EnaApiClient(HttpClient):
116
116
  Returns the URL and parameters for a detail query.
117
117
  """
118
118
  if object_type == 'checklist':
119
- ids = ','.join(object_ids)
119
+ ids = ','.join(str(id_) for id_ in object_ids)
120
120
  url = f'{self.__ena_url}/ena/browser/api/xml/{ids}'
121
121
  params = {}
122
122
  return url, params
123
123
  if object_type == 'submittable_taxon':
124
- ids = ','.join(object_ids)
124
+ # This is actually called separately for each taxon id
125
+ ids = ','.join(str(id_) for id_ in object_ids)
125
126
  url = f'{self.__ena_url}/ena/taxonomy/rest/tax-id/{ids}'
126
127
  params = {}
127
128
  return url, params
@@ -34,6 +34,8 @@ from .gap_assembly_to_elastic_assembly_analysis_converter import GapAssemblyToEl
34
34
  from .genome_notes_genome_note_to_elastic_genome_note_converter import GenomeNotesGenomeNoteToElasticGenomeNoteConverter # noqa F401
35
35
  from .goat_taxon_to_elastic_species_converter import GoatTaxonToElasticSpeciesConverter # noqa F401
36
36
  from .grit_issue_to_elastic_curation_converter import GritIssueToElasticCurationConverter # noqa F401
37
+ from .incoming_sample_to_ena_sample_converter import IncomingSampleToEnaSampleConverter # noqa
38
+ from .incoming_sample_to_incoming_sample_with_lists_converter import IncomingSampleToIncomingSampleWithListsConverter # noqa F401
37
39
  from .informatics_tolid_to_elastic_tolid_converter import InformaticsTolidToElasticTolidConverter # noqa F401
38
40
  from .labwhere_location_to_elastic_sample_update_converter import LabwhereLocationToElasticSampleUpdateConverter # noqa F401
39
41
  from .labwhere_location_to_sts_tray_converter import LabwhereLocationToStsTrayConverter # noqa F401
@@ -0,0 +1,130 @@
1
+ # SPDX-FileCopyrightText: 2025 Genome Research Ltd.
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ import re
5
+ from dataclasses import dataclass
6
+ from typing import Iterable
7
+
8
+ from tol.core import DataObject, DataObjectToDataObjectOrUpdateConverter
9
+
10
+
11
+ class IncomingSampleToEnaSampleConverter(DataObjectToDataObjectOrUpdateConverter):
12
+
13
+ @dataclass(slots=True, frozen=True, kw_only=True)
14
+ class Config:
15
+ ena_checklist_id: str
16
+ project_name: str
17
+
18
+ __slots__ = ['__config']
19
+ __config: Config
20
+
21
+ def __init__(self, data_object_factory, config: Config) -> None:
22
+ super().__init__(data_object_factory)
23
+ self.__config = config
24
+ self._data_object_factory = data_object_factory
25
+
26
+ def convert(self, data_object: DataObject) -> Iterable[DataObject]:
27
+ """
28
+ converting the samples DataObject into ENA format
29
+ """
30
+ s = data_object
31
+ attributes = {
32
+ 'ENA-CHECKLIST': self.__config.ena_checklist_id,
33
+ 'organism part': self.__replace_underscores(
34
+ s.attributes.get('ORGANISM_PART')),
35
+ 'lifestage': (
36
+ 'spore-bearing structure'
37
+ if s.attributes.get('LIFESTAGE') == 'SPORE_BEARING_STRUCTURE'
38
+ else self.__replace_underscores(
39
+ s.attributes.get('LIFESTAGE'))
40
+ ),
41
+ 'project name':
42
+ self.__config.project_name,
43
+ 'collected by':
44
+ self.__replace_underscores(
45
+ s.attributes.get('COLLECTED_BY')),
46
+ 'collection date':
47
+ self.__replace_underscores(
48
+ s.attributes.get('DATE_OF_COLLECTION')).lower(),
49
+ 'geographic location (country and/or sea)':
50
+ self.__collection_country(s).replace('_', ' '),
51
+ 'geographic location (latitude)':
52
+ self.__replace_underscores(
53
+ s.attributes.get('DECIMAL_LATITUDE')).lower(),
54
+ 'geographic location (latitude) units':
55
+ 'DD',
56
+ 'geographic location (longitude)':
57
+ self.__replace_underscores(
58
+ s.attributes.get('DECIMAL_LONGITUDE')).lower(),
59
+ 'geographic location (longitude) units':
60
+ 'DD',
61
+ 'geographic location (region and locality)':
62
+ self.__collection_region(s).replace('_', ' '),
63
+ 'identified_by':
64
+ self.__replace_underscores(
65
+ s.attributes.get('IDENTIFIED_BY')),
66
+ 'habitat':
67
+ self.__replace_underscores(
68
+ s.attributes.get('HABITAT')),
69
+ 'identifier_affiliation':
70
+ self.__replace_underscores(
71
+ s.attributes.get('IDENTIFIER_AFFILIATION')),
72
+ 'sex':
73
+ self.__replace_underscores(
74
+ s.attributes.get('SEX')),
75
+ 'relationship':
76
+ self.__replace_underscores(
77
+ s.attributes.get('RELATIONSHIP')),
78
+ 'SYMBIONT':
79
+ 'Y' if s.attributes.get('SYMBIONT') == 'SYMBIONT' else 'N',
80
+ 'collecting institution':
81
+ self.__replace_underscores(
82
+ s.attributes.get('COLLECTOR_AFFILIATION'))
83
+ }
84
+ if self.__sanitise(s.attributes.get('DEPTH')) != '':
85
+ attributes['geographic location (depth)'] = s.attributes.get('DEPTH')
86
+ attributes['geographic location (depth) units'] = 'm'
87
+ if self.__sanitise(s.attributes.get('ELEVATION')) != '':
88
+ attributes['geographic location (elevation)'] = s.attributes.get('ELEVATION')
89
+ attributes['geographic location (elevation) units'] = 'm'
90
+ if self.__sanitise(s.attributes.get('ORIGINAL_COLLECTION_DATE')) != '':
91
+ attributes['original collection date'] = s.attributes.get('ORIGINAL_COLLECTION_DATE')
92
+ if self.__sanitise(s.attributes.get('ORIGINAL_GEOGRAPHIC_LOCATION')) != '':
93
+ attributes['original geographic location'] = self.__replace_underscores(s.attributes.get('ORIGINAL_GEOGRAPHIC_LOCATION')) # noqa
94
+ if s.attributes.get('GAL') is not None:
95
+ attributes['GAL'] = s.attributes.get('GAL')
96
+ if s.attributes.get('VOUCHER_ID') is not None:
97
+ attributes['specimen_voucher'] = s.attributes.get('VOUCHER_ID')
98
+ if s.attributes.get('SPECIMEN_ID') is not None:
99
+ attributes['specimen_id'] = s.attributes.get('SPECIMEN_ID')
100
+ if s.attributes.get('GAL_SAMPLE_ID') is not None:
101
+ attributes['GAL_sample_id'] = s.attributes.get('GAL_SAMPLE_ID')
102
+ if s.attributes.get('CULTURE_OR_STRAIN_ID') is not None:
103
+ attributes['culture_or_strain_id'] = s.attributes.get('CULTURE_OR_STRAIN_ID')
104
+
105
+ ret = self._data_object_factory(
106
+ 'sample',
107
+ s.id,
108
+ attributes=attributes,
109
+ )
110
+ yield ret
111
+
112
+ def __collection_country(self, data_object: DataObject):
113
+ return re.split(
114
+ r'\s*\|\s*',
115
+ data_object.attributes.get('COLLECTION_LOCATION'))[0]
116
+
117
+ def __collection_region(self, data_object: DataObject):
118
+ return ' | '.join(re.split(
119
+ r'\s*\|\s*',
120
+ data_object.attributes.get('COLLECTION_LOCATION'))[1:])
121
+
122
+ def __replace_underscores(self, value):
123
+ if type(value) != str:
124
+ return value
125
+ return self.__sanitise(value, '').replace('_', ' ')
126
+
127
+ def __sanitise(self, value, default_value=''):
128
+ if value is None:
129
+ return default_value
130
+ return value
@@ -0,0 +1,46 @@
1
+ # SPDX-FileCopyrightText: 2025 Genome Research Ltd.
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from dataclasses import dataclass
5
+ from typing import Iterable
6
+
7
+ from tol.core import DataObject, DataObjectToDataObjectOrUpdateConverter
8
+
9
+
10
+ class IncomingSampleToIncomingSampleWithListsConverter(DataObjectToDataObjectOrUpdateConverter):
11
+
12
+ @dataclass(slots=True, frozen=True, kw_only=True)
13
+ class Config:
14
+ fields_to_convert: str
15
+ separator: str = '|'
16
+
17
+ __slots__ = ['__config']
18
+ __config: Config
19
+
20
+ def __init__(self, data_object_factory, config: Config) -> None:
21
+ super().__init__(data_object_factory)
22
+ self.__config = config
23
+ self._data_object_factory = data_object_factory
24
+
25
+ def convert(self, data_object: DataObject) -> Iterable[DataObject]:
26
+ """
27
+ converting the samples DataObject into ENA format
28
+ """
29
+
30
+ ret = self._data_object_factory(
31
+ data_object.type,
32
+ data_object.id,
33
+ attributes={
34
+ k: v for k, v in data_object.attributes.items()
35
+ if k not in self.__config.fields_to_convert
36
+ } | {
37
+ field: self.__convert_to_list(data_object.get_field_by_name(field))
38
+ for field in self.__config.fields_to_convert
39
+ }
40
+ )
41
+ yield ret
42
+
43
+ def __convert_to_list(self, value: str | None) -> list[str]:
44
+ if not value:
45
+ return []
46
+ return [item.strip() for item in value.split(self.__config.separator)]
@@ -19,6 +19,7 @@ from sqlalchemy.ext.declarative import declared_attr
19
19
  from sqlalchemy.orm import (
20
20
  Mapped,
21
21
  Session,
22
+ joinedload,
22
23
  mapped_column,
23
24
  relationship
24
25
  )
@@ -184,7 +185,7 @@ def create_models(
184
185
 
185
186
  id: Mapped[str] = mapped_column( # noqa A003
186
187
  primary_key=True,
187
- name=None if not prefix_with_name else 'state_id'
188
+ name='state_id' if prefix_with_name else None
188
189
  )
189
190
 
190
191
  created_at: Mapped[datetime] = mapped_column(
@@ -257,13 +258,13 @@ def create_models(
257
258
  id: Mapped[int] = mapped_column( # noqa A003
258
259
  primary_key=True,
259
260
  autoincrement=True,
260
- name=None if not prefix_with_name else 'user_id'
261
+ name='user_id' if prefix_with_name else None
261
262
  )
262
263
 
263
- _tokens: Mapped[list['Token']] = relationship(
264
+ _tokens: Mapped[list[Token]] = relationship(
264
265
  back_populates='user'
265
266
  )
266
- _role_bindings: Mapped[list['RoleBinding']] = relationship(
267
+ _role_bindings: Mapped[list[RoleBinding]] = relationship(
267
268
  back_populates='user'
268
269
  )
269
270
 
@@ -340,7 +341,7 @@ def create_models(
340
341
 
341
342
  class _TokenPKMixin:
342
343
  """
343
- Has an integer has a primary key.
344
+ Has an integer as a primary key.
344
345
 
345
346
  This is all that is needed in most apps,
346
347
  and is the default.
@@ -403,11 +404,19 @@ def create_models(
403
404
  token: str
404
405
  ) -> Optional[Token]:
405
406
 
406
- return sess.query(
407
- cls
408
- ).filter_by(
409
- token=token
410
- ).one_or_none()
407
+ return (
408
+ sess.query(cls)
409
+ .filter_by(token=token)
410
+ .options(
411
+ # Join through to the Role table when fetching a Token so
412
+ # that SQLAlchemy only fires one SELECT query instead of
413
+ # four to get `token.user._role_bindings.role.name`
414
+ joinedload(cls.user)
415
+ .joinedload(User._role_bindings)
416
+ .joinedload(RoleBinding.role)
417
+ )
418
+ .one_or_none()
419
+ )
411
420
 
412
421
  @classmethod
413
422
  def get_or_create(
@@ -475,14 +484,14 @@ def create_models(
475
484
  id: Mapped[int] = mapped_column( # noqa A003
476
485
  primary_key=True,
477
486
  autoincrement=True,
478
- name=None if not prefix_with_name else 'role_id'
487
+ name='role_id' if prefix_with_name else None
479
488
  )
480
489
 
481
490
  name: Mapped[str] = mapped_column(
482
491
  unique=True
483
492
  )
484
493
 
485
- _role_bindings: Mapped[list['RoleBinding']] = relationship(
494
+ _role_bindings: Mapped[list[RoleBinding]] = relationship(
486
495
  back_populates='role'
487
496
  )
488
497
 
@@ -6,6 +6,8 @@ from .allowed_keys import AllowedKeysValidator # noqa
6
6
  from .allowed_values import AllowedValuesValidator # noqa
7
7
  from .allowed_values_from_datasource import AllowedValuesFromDataSourceValidator # noqa
8
8
  from .assert_on_condition import AssertOnConditionValidator # noqa
9
+ from .converter_and_validate import ConverterAndValidateValidator # noqa
10
+ from .ena_checklist import EnaChecklistValidator # noqa
9
11
  from .mutually_exclusive import MutuallyExclusiveValidator # noqa
10
12
  from .ena_submittable import EnaSubmittableValidator # noqa
11
13
  from .regex import Regex, RegexValidator # noqa
@@ -15,6 +17,5 @@ from .sts_fields import StsFieldsValidator # noqa
15
17
  from .tolid import TolidValidator # noqa
16
18
  from .unique_values import UniqueValuesValidator # noqa
17
19
  from .unique_whole_organisms import UniqueWholeOrganismsValidator # noqa
18
- # Conditions are used where validators are defined, not just within validators
19
20
  from .interfaces import Condition # noqa
20
21
  from .min_one_valid_value import MinOneValidValueValidator # noqa
@@ -26,7 +26,8 @@ class AllowedKeysValidator(Validator):
26
26
 
27
27
  def __init__(
28
28
  self,
29
- config: Config
29
+ config: Config,
30
+ **kwargs
30
31
  ) -> None:
31
32
 
32
33
  super().__init__()
@@ -27,7 +27,8 @@ class AllowedValuesValidator(Validator):
27
27
 
28
28
  def __init__(
29
29
  self,
30
- config: Config
30
+ config: Config,
31
+ **kwargs
31
32
  ) -> None:
32
33
 
33
34
  super().__init__()
@@ -17,7 +17,6 @@ class AllowedValuesFromDataSourceValidator(Validator):
17
17
  """
18
18
  @dataclass(slots=True, frozen=True, kw_only=True)
19
19
  class Config:
20
- allowed_values: List[str | int | float] | None = None
21
20
  datasource_instance_id: int
22
21
  datasource_object_type: str
23
22
  datasource_field_name: str
@@ -30,22 +29,19 @@ class AllowedValuesFromDataSourceValidator(Validator):
30
29
  def __init__(
31
30
  self,
32
31
  config: Config,
32
+ allowed_values: List[str | int | float] | None = None, # For testing
33
+ **kwargs
33
34
  ) -> None:
34
35
 
35
36
  super().__init__()
36
37
 
37
38
  self.__config = config
38
- self.__cached_list = self.__config.allowed_values \
39
+ self.__cached_list = allowed_values \
39
40
  or self.__initialize_list_from_datasource()
40
41
 
41
- if self.__config.allowed_values is None:
42
- self.__cached_list = self.__initialize_list_from_datasource()
43
- else:
44
- self.__cached_list = self.__config.allowed_values
45
-
46
42
  def __initialize_list_from_datasource(self) -> List[str | int | float]:
47
43
  dsi = portaldb().get_one('data_source_instance', self.__config.datasource_instance_id)
48
- ds = DataSourceUtils.get_data_source_by_data_source_instance(dsi)
44
+ ds = DataSourceUtils.get_datasource_by_datasource_instance(dsi)
49
45
  return [
50
46
  obj.get_field_by_name(
51
47
  self.__config.datasource_field_name
@@ -59,8 +55,11 @@ class AllowedValuesFromDataSourceValidator(Validator):
59
55
  obj: DataObject
60
56
  ) -> None:
61
57
  field_value = obj.get_field_by_name(self.__config.field_name)
62
- if field_value not in self.__cached_list:
63
- print(self.__cached_list)
58
+ if not field_value:
59
+ return
60
+ if not isinstance(field_value, list):
61
+ field_value = [field_value]
62
+ if any(value not in self.__cached_list for value in field_value):
64
63
  multiple_cached_values = len(self.__cached_list) > 1
65
64
 
66
65
  cached_list_str = ''
@@ -7,7 +7,7 @@ from typing import List
7
7
 
8
8
  from tol.core import DataObject, Validator
9
9
 
10
- from .interfaces import Condition, ConditionEvaluator
10
+ from .interfaces import Condition, ConditionDict, ConditionEvaluator
11
11
 
12
12
 
13
13
  class AssertOnConditionValidator(Validator, ConditionEvaluator):
@@ -19,13 +19,13 @@ class AssertOnConditionValidator(Validator, ConditionEvaluator):
19
19
  """
20
20
  @dataclass(slots=True, frozen=True, kw_only=True)
21
21
  class Config:
22
- condition: Condition
23
- assertions: List[Condition]
22
+ condition: ConditionDict
23
+ assertions: List[ConditionDict]
24
24
 
25
25
  __slots__ = ['__config']
26
26
  __config: Config
27
27
 
28
- def __init__(self, config: Config) -> None:
28
+ def __init__(self, config: Config, **kwargs) -> None:
29
29
  super().__init__()
30
30
 
31
31
  self.__config = config
@@ -33,10 +33,10 @@ class AssertOnConditionValidator(Validator, ConditionEvaluator):
33
33
  def _validate_data_object(self, obj: DataObject) -> None:
34
34
  # Check condition atribute
35
35
  # (only perform the assertions if the condition passes)
36
- if self._does_condition_pass(self.__config.condition, obj):
36
+ if self._does_condition_pass(Condition.from_dict(self.__config.condition), obj):
37
37
  # Perform each assertion
38
38
  for assertion in self.__config.assertions:
39
- self.__perform_assertion(obj, assertion)
39
+ self.__perform_assertion(obj, Condition.from_dict(assertion))
40
40
 
41
41
  def __perform_assertion(self, obj: DataObject, assertion: Condition) -> None:
42
42
  # There's only an error or warning if the assertion condition fails
@@ -0,0 +1,93 @@
1
+ # SPDX-FileCopyrightText: 2025 Genome Research Ltd.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ import importlib
6
+ from dataclasses import dataclass
7
+
8
+ from tol.core import DataObject
9
+ from tol.core.factory import DataObjectFactory
10
+ from tol.core.validate import ValidationResult, Validator
11
+
12
+
13
+ class ConverterAndValidateValidator(Validator):
14
+ """
15
+ Convert DataObjects, validate the converted ones, and return the original
16
+ input unchanged. Inner validator results are not merged here.
17
+
18
+ {
19
+ "converters": [{
20
+ "module": "<path.to.module>",
21
+ "class_name": "<path.to.ConverterClass>",
22
+ "config": { ... }
23
+ }],
24
+ "validators": [{
25
+ "module": "<path.to.module>",
26
+ "class_name": "<path.to.ValidatorClass>",
27
+ "config": { ... }
28
+ }]
29
+ }
30
+
31
+ """
32
+ @dataclass(slots=True, frozen=True, kw_only=True)
33
+ class Config:
34
+ converters: list[dict]
35
+ validators: list[dict]
36
+
37
+ __slots__ = [
38
+ '__converters',
39
+ '__validators'
40
+ ]
41
+
42
+ def __init__(
43
+ self,
44
+ config: Config,
45
+ data_object_factory: DataObjectFactory,
46
+ **kwargs
47
+ ) -> None:
48
+ super().__init__()
49
+ self.__converters = []
50
+ self.__validators = []
51
+
52
+ for conv in config.converters:
53
+ __module = importlib.import_module(conv.get('module'))
54
+ converter_class = getattr(__module, conv.get('class_name'))
55
+
56
+ converter_conf = converter_class.Config(
57
+ **conv.get('config')
58
+ )
59
+ self.__converters.append(converter_class(
60
+ data_object_factory=data_object_factory,
61
+ config=converter_conf,
62
+ ))
63
+ for val in config.validators:
64
+ __module = importlib.import_module(val.get('module'))
65
+ validator_class = getattr(__module, val.get('class_name'))
66
+
67
+ validator_conf = validator_class.Config(
68
+ **val.get('config')
69
+ )
70
+ self.__validators.append(validator_class(
71
+ data_object_factory=data_object_factory,
72
+ config=validator_conf,
73
+ ))
74
+
75
+ def _validate_data_object(self, obj: DataObject) -> None:
76
+ converted_objs = [obj]
77
+ for converter in self.__converters:
78
+ converted_objs = converter.convert_iterable(converted_objs)
79
+ for obj in converted_objs:
80
+ for validator in self.__validators:
81
+ validator._validate_data_object(obj)
82
+
83
+ @property
84
+ def results(self) -> list[ValidationResult]:
85
+ return [result for validator in self.__validators for result in validator.results]
86
+
87
+ @property
88
+ def warnings(self) -> list[ValidationResult]:
89
+ return [warning for validator in self.__validators for warning in validator.warnings]
90
+
91
+ @property
92
+ def errors(self) -> list[ValidationResult]:
93
+ return [error for validator in self.__validators for error in validator.errors]
@@ -0,0 +1,73 @@
1
+ # SPDX-FileCopyrightText: 2025 Genome Research Ltd.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ import re
6
+ from dataclasses import dataclass
7
+
8
+ from tol.core import DataSource
9
+ from tol.core.data_object import DataObject
10
+ from tol.core.validate import Validator
11
+ from tol.sources.ena import ena
12
+
13
+
14
+ class EnaChecklistValidator(Validator):
15
+ """
16
+ validates the ENA_CHECKLIST for each samples
17
+ """
18
+
19
+ @dataclass(slots=True, frozen=True, kw_only=True)
20
+ class Config:
21
+ ena_checklist_id: str
22
+
23
+ __slots__ = ['__config']
24
+ __config: Config
25
+
26
+ def __init__(self, config: Config, datasource: DataSource = ena(), **kwargs) -> None:
27
+ super().__init__()
28
+ self.__config = config
29
+ self._datasource = datasource
30
+
31
+ def _validate_data_object(self, obj: DataObject) -> None:
32
+ ena_datasource = self._datasource
33
+ ena_checklist = ena_datasource.get_one('checklist', self.__config.ena_checklist_id)
34
+
35
+ validations = ena_checklist.attributes['checklist']
36
+ for key in validations:
37
+ field_name = key
38
+ if 'field' in validations[key]:
39
+ field_name = validations[key]['field']
40
+ if 'mandatory' in validations[key] and key not in obj.attributes:
41
+ self.add_error(object_id=obj.id, detail='Must be given', field=[field_name])
42
+ continue
43
+ if 'mandatory' in validations[key] and obj.attributes[key] is None:
44
+ self.add_error(object_id=obj.id, detail='Must be given', field=[field_name])
45
+ continue
46
+ if 'mandatory' in validations[key] and obj.attributes.get(key) == '':
47
+ self.add_error(
48
+ object_id=obj.id,
49
+ detail='Must not be empty', field=[field_name]
50
+ )
51
+
52
+ if 'restricted text' in validations[key] and key in obj.attributes:
53
+ for condition in validations[key]:
54
+ if type(condition) == str and '(' in condition:
55
+ regex = condition
56
+ compiled_re = re.compile(regex)
57
+ if not compiled_re.search(obj.attributes.get(key)):
58
+ self.add_error(
59
+ object_id=obj.id,
60
+ detail='Must match specific pattern', field=[field_name]
61
+ )
62
+
63
+ # Check against allowed values
64
+ if 'text choice' in validations[key] and key in obj.attributes:
65
+ for condition in validations[key]:
66
+ if type(condition) == list:
67
+ allowed_values = condition
68
+ if obj.attributes.get(key).lower() not in \
69
+ [x.lower() for x in allowed_values]:
70
+ self.add_error(
71
+ object_id=obj.id,
72
+ detail='Must be in allowed values', field=[field_name]
73
+ )
@@ -28,6 +28,7 @@ class EnaSubmittableValidator(Validator):
28
28
  self,
29
29
  config: Config,
30
30
  ena_datasource: DataSource | None = ena(), # For testing
31
+ **kwargs
31
32
  ) -> None:
32
33
 
33
34
  super().__init__()
@@ -0,0 +1,5 @@
1
+ # SPDX-FileCopyrightText: 2025 Genome Research Ltd.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ from .condition_evaluator import Condition, ConditionDict, ConditionEvaluator # noqa