tol-sdk 1.6.37__tar.gz → 1.7.0__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 (345) hide show
  1. {tol_sdk-1.6.37/src/tol_sdk.egg-info → tol_sdk-1.7.0}/PKG-INFO +1 -1
  2. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/pyproject.toml +1 -1
  3. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/blueprint.py +29 -6
  4. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/controller.py +14 -5
  5. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/api_datasource.py +15 -7
  6. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/client.py +12 -6
  7. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/converter.py +22 -8
  8. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/factory.py +5 -3
  9. tol_sdk-1.7.0/src/tol/api_client/view.py +192 -0
  10. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/cli/cli.py +1 -1
  11. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/__init__.py +1 -0
  12. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/http_client.py +4 -2
  13. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/cursor.py +5 -3
  14. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/detail_getter.py +7 -15
  15. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/list_getter.py +3 -1
  16. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/page_getter.py +3 -1
  17. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/relational.py +9 -4
  18. tol_sdk-1.7.0/src/tol/core/requested_fields.py +189 -0
  19. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/elastic/elastic_datasource.py +2 -1
  20. tol_sdk-1.7.0/src/tol/flows/converters/benchling_extraction_to_elastic_extraction_converter.py +49 -0
  21. tol_sdk-1.7.0/src/tol/flows/converters/benchling_extraction_to_elastic_sequencing_request_converter.py +50 -0
  22. tol_sdk-1.7.0/src/tol/flows/converters/benchling_sequencing_request_to_elastic_sequencing_request_converter.py +59 -0
  23. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/benchling_tissue_prep_to_elastic_tissue_prep_converter.py +14 -3
  24. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sample_to_benchling_tissue_update_converter.py +1 -1
  25. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sample_to_elastic_sequencing_request_update_converter.py +4 -1
  26. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_tolid_to_elastic_genome_note_update_converter.py +4 -1
  27. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_tolid_to_elastic_sample_update_converter.py +4 -1
  28. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/sts.py +6 -2
  29. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/database.py +80 -44
  30. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/factory.py +2 -2
  31. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/filter.py +22 -20
  32. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/model.py +43 -38
  33. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/relationship.py +1 -1
  34. tol_sdk-1.7.0/src/tol/sql/sql_converter.py +128 -0
  35. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/sql_datasource.py +85 -180
  36. {tol_sdk-1.6.37/src/tol/sql/board → tol_sdk-1.7.0/src/tol/sql/standard}/__init__.py +1 -1
  37. tol_sdk-1.7.0/src/tol/sql/standard/factory.py +549 -0
  38. {tol_sdk-1.6.37 → tol_sdk-1.7.0/src/tol_sdk.egg-info}/PKG-INFO +1 -1
  39. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol_sdk.egg-info/SOURCES.txt +3 -4
  40. tol_sdk-1.6.37/src/tol/api_client/view.py +0 -322
  41. tol_sdk-1.6.37/src/tol/flows/converters/benchling_extraction_to_elastic_extraction_converter.py +0 -30
  42. tol_sdk-1.6.37/src/tol/flows/converters/benchling_extraction_to_elastic_sequencing_request_converter.py +0 -29
  43. tol_sdk-1.6.37/src/tol/flows/converters/benchling_sequencing_request_to_elastic_sequencing_request_converter.py +0 -38
  44. tol_sdk-1.6.37/src/tol/sql/board/factory.py +0 -341
  45. tol_sdk-1.6.37/src/tol/sql/loader/__init__.py +0 -6
  46. tol_sdk-1.6.37/src/tol/sql/loader/factory.py +0 -246
  47. tol_sdk-1.6.37/src/tol/sql/sql_converter.py +0 -221
  48. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/LICENSE +0 -0
  49. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/MANIFEST.in +0 -0
  50. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/README.md +0 -0
  51. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/setup.cfg +0 -0
  52. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/certs/cacert.pem +0 -0
  53. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/__init__.py +0 -0
  54. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/actions/__init__.py +0 -0
  55. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/actions/action.py +0 -0
  56. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/actions/upsert_action.py +0 -0
  57. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/__init__.py +0 -0
  58. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/action.py +0 -0
  59. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/__init__.py +0 -0
  60. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/abc/__init__.py +0 -0
  61. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/abc/auth.py +0 -0
  62. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/abc/authorisation.py +0 -0
  63. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/asserts.py +0 -0
  64. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/blueprint.py +0 -0
  65. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/composite.py +0 -0
  66. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/config.py +0 -0
  67. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/auth/error.py +0 -0
  68. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/__init__.py +0 -0
  69. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/aggregation_body.py +0 -0
  70. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/aggregation_parameters.py +0 -0
  71. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/auth_context.py +0 -0
  72. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/authenticate.py +0 -0
  73. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/data_body.py +0 -0
  74. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/filter_utils.py +0 -0
  75. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/list_get_parameters.py +0 -0
  76. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/relation_url.py +0 -0
  77. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/misc/stats_parameters.py +0 -0
  78. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/pipeline_steps.py +0 -0
  79. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_base/system.py +0 -0
  80. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/__init__.py +0 -0
  81. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/exception.py +0 -0
  82. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/filter.py +0 -0
  83. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/parser.py +0 -0
  84. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/api_client/validate.py +0 -0
  85. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/barcodes/__init__.py +0 -0
  86. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/barcodes/main.py +0 -0
  87. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/__init__.py +0 -0
  88. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/benchling_converter.py +0 -0
  89. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/benchling_datasource.py +0 -0
  90. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/benchling_warehouse_datasource.py +0 -0
  91. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/__init__.py +0 -0
  92. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/extraction_extraction_type_dna.sql +0 -0
  93. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/extraction_extraction_type_lres.sql +0 -0
  94. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/extraction_extraction_type_pooled_dna.sql +0 -0
  95. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/extraction_extraction_type_rna.sql +0 -0
  96. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/pacbio_prep.sql +0 -0
  97. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/pooled_pacbio_prep.sql +0 -0
  98. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/results_extraction_dna.sql +0 -0
  99. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/results_extraction_pooled.sql +0 -0
  100. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/results_extraction_rna.sql +0 -0
  101. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/results_pacbio_prep.sql +0 -0
  102. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/results_pacbio_prep_pooled.sql +0 -0
  103. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/sample.sql +0 -0
  104. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/sequencing_request_sequencing_platform_hic.sql +0 -0
  105. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/sequencing_request_sequencing_platform_pacbio.sql +0 -0
  106. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/sequencing_request_sequencing_platform_rnaseq.sql +0 -0
  107. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/sequencing_request_sequencing_platform_wgs.sql +0 -0
  108. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/benchling/sql/tissue_prep.sql +0 -0
  109. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/board/__init__.py +0 -0
  110. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/board/blueprint.py +0 -0
  111. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/bold/__init__.py +0 -0
  112. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/bold/bold_datasource.py +0 -0
  113. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/bold/client.py +0 -0
  114. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/bold/converter.py +0 -0
  115. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/bold/factory.py +0 -0
  116. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/bold/parser.py +0 -0
  117. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/cli/__init__.py +0 -0
  118. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/converter/__init__.py +0 -0
  119. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/converter/yaml/__init__.py +0 -0
  120. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/converter/yaml/model.py +0 -0
  121. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/converter/yaml/yaml_converter.py +0 -0
  122. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/copo/__init__.py +0 -0
  123. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/copo/client.py +0 -0
  124. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/copo/converter.py +0 -0
  125. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/copo/copo_datasource.py +0 -0
  126. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/copo/factory.py +0 -0
  127. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/copo/parser.py +0 -0
  128. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/attribute_metadata.py +0 -0
  129. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/core_converter.py +0 -0
  130. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/data_loader.py +0 -0
  131. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/data_object.py +0 -0
  132. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/data_object_converter.py +0 -0
  133. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/data_source_attribute_metadata.py +0 -0
  134. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/data_source_dict.py +0 -0
  135. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/datasource.py +0 -0
  136. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/datasource_error.py +0 -0
  137. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/datasource_filter.py +0 -0
  138. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/datasource_utils.py +0 -0
  139. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/factory.py +0 -0
  140. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/__init__.py +0 -0
  141. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/_filterable.py +0 -0
  142. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/_writer.py +0 -0
  143. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/aggregator.py +0 -0
  144. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/counter.py +0 -0
  145. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/declare.py +0 -0
  146. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/deleter.py +0 -0
  147. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/enricher.py +0 -0
  148. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/enum.py +0 -0
  149. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/group_statter.py +0 -0
  150. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/inserter.py +0 -0
  151. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/operator_config.py +0 -0
  152. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/statter.py +0 -0
  153. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/summariser.py +0 -0
  154. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/updater.py +0 -0
  155. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/operator/upserter.py +0 -0
  156. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/relationship.py +0 -0
  157. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/session.py +0 -0
  158. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/core/validate.py +0 -0
  159. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/elastic/__init__.py +0 -0
  160. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/elastic/runtime_fields.py +0 -0
  161. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/eln/__init__.py +0 -0
  162. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/eln/auth.py +0 -0
  163. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/eln/eln_datasource.py +0 -0
  164. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/eln/entities.py +0 -0
  165. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/eln/generators.py +0 -0
  166. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/eln/sanitise.py +0 -0
  167. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/__init__.py +0 -0
  168. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/client.py +0 -0
  169. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/converter.py +0 -0
  170. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/ena_datasource.py +0 -0
  171. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/ena_methods.py +0 -0
  172. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/factory.py +0 -0
  173. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/filter.py +0 -0
  174. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/ena/parser.py +0 -0
  175. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/excel/__init__.py +0 -0
  176. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/excel/excel.py +0 -0
  177. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/excel/excel_datasource.py +0 -0
  178. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/excel/s3_factory.py +0 -0
  179. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/__init__.py +0 -0
  180. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/__init__.py +0 -0
  181. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/benchling_entity_to_benchling_worklist_item_converter_factory.py +0 -0
  182. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/benchling_sample_casm_to_sts_sample_converter.py +0 -0
  183. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/benchling_sample_to_elastic_sample_converter.py +0 -0
  184. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/benchling_tissue_to_sts_sample_converter.py +0 -0
  185. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/bioscan_extra_pantheon_species_to_elastic_sample_update_converter.py +0 -0
  186. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/bioscan_image_to_elastic_sample_update_converter.py +0 -0
  187. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/bioscan_qc_specimen_to_elastic_sample_update_converter.py +0 -0
  188. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/bioscan_qc_uksi_entry_to_elastic_sample_update_converter.py +0 -0
  189. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/bold_bin_to_elastic_sample_update_converter.py +0 -0
  190. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/bold_sample_to_elastic_sample_update_converter.py +0 -0
  191. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_object_to_portaldb_object_converter.py +0 -0
  192. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sample_to_benchling_tissue_converter.py +0 -0
  193. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sample_to_bold_sample_converter.py +0 -0
  194. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sample_to_sts_sample_converter.py +0 -0
  195. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sequencing_request_to_elastic_run_data_update_converter.py +0 -0
  196. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_sequencing_request_to_sts_sequencing_request_converter.py +0 -0
  197. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_species_to_sts_species_converter.py +0 -0
  198. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/elastic_tolid_to_elastic_curation_update_converter.py +0 -0
  199. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/gap_assembly_to_elastic_assembly_analysis_converter.py +0 -0
  200. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/gap_assembly_to_elastic_assembly_converter.py +0 -0
  201. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/genome_notes_genome_note_to_elastic_genome_note_converter.py +0 -0
  202. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/goat_taxon_to_elastic_species_converter.py +0 -0
  203. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/grit_issue_to_elastic_curation_converter.py +0 -0
  204. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/informatics_tolid_to_elastic_tolid_converter.py +0 -0
  205. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/labwhere_location_to_elastic_sample_update_converter.py +0 -0
  206. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/labwhere_location_to_sts_tray_converter.py +0 -0
  207. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/mlwh_extraction_to_elastic_extraction_converter.py +0 -0
  208. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/mlwh_run_data_to_elastic_run_data_converter.py +0 -0
  209. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/mlwh_sequencing_request_to_elastic_sequencing_request_converter.py +0 -0
  210. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_banked_sample_to_elastic_sample_converter.py +0 -0
  211. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_manifest_to_elastic_manifest_converter.py +0 -0
  212. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_project_to_elastic_sample_update_converter.py +0 -0
  213. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_sample_project_to_elastic_sample_converter.py +0 -0
  214. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_sample_to_casm_benchling_converter.py +0 -0
  215. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_sampleset_to_elastic_sampleset_converter.py +0 -0
  216. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/sts_species_to_elastic_species_converter.py +0 -0
  217. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/tolid_specimen_to_elastic_tolid_converter.py +0 -0
  218. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/tolqc_data_to_elastic_run_data_converter.py +0 -0
  219. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/tolqc_sample_to_elastic_sequencing_request_converter.py +0 -0
  220. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/tolqc_species_to_elastic_species_converter.py +0 -0
  221. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/treeofsex_species_to_treeofsexwh_species_converter.py +0 -0
  222. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/converters/treeofsex_upload_to_treeofsex_attribute_converter.py +0 -0
  223. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/logger.py +0 -0
  224. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/secrets.py +0 -0
  225. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/flows/sequencing_submissions.py +0 -0
  226. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/gap/__init__.py +0 -0
  227. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/gap/gap_datasource.py +0 -0
  228. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/__init__.py +0 -0
  229. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/client.py +0 -0
  230. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/converter.py +0 -0
  231. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/factory.py +0 -0
  232. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/filter.py +0 -0
  233. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/goat_datasource.py +0 -0
  234. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/goat/parser.py +0 -0
  235. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/google_sheets/__init__.py +0 -0
  236. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/google_sheets/google_sheet_datasource.py +0 -0
  237. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/irods/__init__.py +0 -0
  238. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/irods/irods_datasource.py +0 -0
  239. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/__init__.py +0 -0
  240. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/client.py +0 -0
  241. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/converter.py +0 -0
  242. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/factory.py +0 -0
  243. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/filter.py +0 -0
  244. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/jira_datasource.py +0 -0
  245. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/mapper.py +0 -0
  246. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/parser.py +0 -0
  247. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/jira/sort.py +0 -0
  248. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/json/__init__.py +0 -0
  249. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/json/json_datasource.py +0 -0
  250. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/json/s3_json_datasource.py +0 -0
  251. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/labwhere/__init__.py +0 -0
  252. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/labwhere/client.py +0 -0
  253. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/labwhere/converter.py +0 -0
  254. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/labwhere/factory.py +0 -0
  255. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/labwhere/labwhere_datasource.py +0 -0
  256. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/labwhere/parser.py +0 -0
  257. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/markdown.py +0 -0
  258. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/mlwh/__init__.py +0 -0
  259. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/mlwh/mlwh_datasource.py +0 -0
  260. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/prefect/__init__.py +0 -0
  261. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/prefect/converter.py +0 -0
  262. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/prefect/factory.py +0 -0
  263. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/prefect/filter.py +0 -0
  264. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/prefect/prefect_datasource.py +0 -0
  265. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/prefect/prefect_object.py +0 -0
  266. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/s3/__init__.py +0 -0
  267. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/s3/converter.py +0 -0
  268. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/s3/factory.py +0 -0
  269. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/s3/parser.py +0 -0
  270. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/s3/s3_datasource.py +0 -0
  271. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/__init__.py +0 -0
  272. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/configuration.py +0 -0
  273. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/consumer.py +0 -0
  274. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/message_builder.py +0 -0
  275. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/messages.py +0 -0
  276. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/response_processors.py +0 -0
  277. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sciops/sequencing_datasource.py +0 -0
  278. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/services/__init__.py +0 -0
  279. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/services/s3_client.py +0 -0
  280. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/__init__.py +0 -0
  281. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/benchling.py +0 -0
  282. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/benchling_warehouse.py +0 -0
  283. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/bioscan.py +0 -0
  284. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/bioscan_extra.py +0 -0
  285. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/bioscan_image.py +0 -0
  286. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/bioscan_qc.py +0 -0
  287. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/bold.py +0 -0
  288. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/copo.py +0 -0
  289. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/defaults.py +0 -0
  290. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/elastic.py +0 -0
  291. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/ena.py +0 -0
  292. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/gap.py +0 -0
  293. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/genome_notes.py +0 -0
  294. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/goat.py +0 -0
  295. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/grit.py +0 -0
  296. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/informatics.py +0 -0
  297. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/labwhere.py +0 -0
  298. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/mlwh.py +0 -0
  299. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/portal.py +0 -0
  300. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/portal_attributes.py +0 -0
  301. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/portaldb.py +0 -0
  302. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/prefect.py +0 -0
  303. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/sciops.py +0 -0
  304. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/sts_legacy.py +0 -0
  305. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/tolid.py +0 -0
  306. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/tolqc.py +0 -0
  307. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/tolqc_legacy.py +0 -0
  308. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/treeofsex.py +0 -0
  309. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/uksi_qc.py.py +0 -0
  310. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sources/workflows.py +0 -0
  311. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/__init__.py +0 -0
  312. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/action/__init__.py +0 -0
  313. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/action/factory.py +0 -0
  314. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/auth/__init__.py +0 -0
  315. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/auth/blueprint.py +0 -0
  316. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/auth/models.py +0 -0
  317. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/cast.py +0 -0
  318. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/ds_session.py +0 -0
  319. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/exception.py +0 -0
  320. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/ext.py +0 -0
  321. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/pipeline_step/__init__.py +0 -0
  322. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/pipeline_step/factory.py +0 -0
  323. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/session.py +0 -0
  324. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/sort.py +0 -0
  325. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/summary/__init__.py +0 -0
  326. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sql/summary/factory.py +0 -0
  327. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/status/__init__.py +0 -0
  328. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/status/status_datasource.py +0 -0
  329. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sts/__init__.py +0 -0
  330. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sts/sts.py +0 -0
  331. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sts/sts_datasource.py +0 -0
  332. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/sts/sts_requests.py +0 -0
  333. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/treeval/__init__.py +0 -0
  334. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/treeval/treeval_datasource.py +0 -0
  335. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/utils/__init__.py +0 -0
  336. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/utils/csv.py +0 -0
  337. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/utils/s3.py +0 -0
  338. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/validators/__init__.py +0 -0
  339. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/validators/allowed_keys.py +0 -0
  340. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/validators/allowed_values.py +0 -0
  341. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol/validators/unique_values.py +0 -0
  342. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol_sdk.egg-info/dependency_links.txt +0 -0
  343. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol_sdk.egg-info/entry_points.txt +0 -0
  344. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/src/tol_sdk.egg-info/requires.txt +0 -0
  345. {tol_sdk-1.6.37 → tol_sdk-1.7.0}/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.6.37
3
+ Version: 1.7.0
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.6.37"
11
+ version = "1.7.0"
12
12
  description = "SDK for interaction with ToL, Sanger and external services"
13
13
  readme = "README.md"
14
14
  authors = [
@@ -35,6 +35,7 @@ from ..core import DataSource, DataSourceError, OperableDataSource
35
35
  from ..core.data_source_dict import DataSourceDict
36
36
  from ..core.operator import Relational
37
37
  from ..core.operator.operator_config import DefaultOperatorConfig, OperatorConfig
38
+ from ..core.requested_fields import ReqFieldsTree
38
39
 
39
40
 
40
41
  class DataBlueprint(Blueprint):
@@ -179,6 +180,7 @@ def _core_blueprint(
179
180
  data_source_dict: dict[str, DataSource],
180
181
  url_prefix: str,
181
182
  auth_inspector: Optional[AuthInspector] = None,
183
+ include_all_to_ones: bool = True,
182
184
  ) -> DataBlueprint:
183
185
  """
184
186
  Create the core blueprint responsible for managing DataSource endpoints.
@@ -193,6 +195,8 @@ def _core_blueprint(
193
195
  url_prefix (str): URL prefix for all data endpoints.
194
196
  auth_inspector (Optional[AuthInspector], optional): Authentication
195
197
  inspector for request authorisation.
198
+ include_all_to_ones (bool): Whether to fetch or store all to-one related objects
199
+ when fetching or serialising DataObjects.
196
200
 
197
201
  Returns:
198
202
  DataBlueprint: A configured blueprint with all data endpoints and error handlers.
@@ -231,18 +235,30 @@ def _core_blueprint(
231
235
  hop_limit = None if requested_fields else 1
232
236
 
233
237
  data_source = data_source_dict[object_type]
238
+
239
+ # Build a ReqFieldsTree template for the request
240
+ req_fields_tree = ReqFieldsTree(
241
+ object_type,
242
+ data_source,
243
+ requested_fields,
244
+ include_all_to_ones=include_all_to_ones,
245
+ )
246
+
234
247
  view = DefaultView(
248
+ requested_tree=req_fields_tree,
235
249
  prefix=url_prefix,
236
- include_all_to_ones=True,
237
250
  hop_limit=hop_limit,
238
- requested_fields=requested_fields,
239
251
  )
240
- return Controller(data_source, view, auth_inspector=auth_inspector)
252
+ return Controller(data_source, view, req_fields_tree, auth_inspector=auth_inspector)
241
253
 
242
254
  @data_handler.route('/<object_type>/<path:object_id>', methods=['GET']) # Allow slashes
243
255
  def get_detail(*, object_type: str, object_id: str):
244
256
  """Get details of a specific object by ID."""
245
- controller = __new_controller(object_type)
257
+ request_args = ListGetParameters(request.args)
258
+ controller = __new_controller(
259
+ object_type,
260
+ requested_fields=request_args.requested_fields,
261
+ )
246
262
  object_id_unencoded = urllib.parse.unquote(object_id)
247
263
  return controller.get_detail(object_type, object_id_unencoded)
248
264
 
@@ -325,8 +341,11 @@ def _core_blueprint(
325
341
  @data_handler.post('/<object_type>:cursor')
326
342
  def get_cursor_page(*, object_type: str):
327
343
  """Get a page of results using cursor-based pagination."""
328
- controller = __new_controller(object_type)
329
344
  request_args = ListGetParameters(request.args)
345
+ controller = __new_controller(
346
+ object_type,
347
+ requested_fields=request_args.requested_fields,
348
+ )
330
349
  search_after = request.json.get('search_after')
331
350
  return controller.get_cursor_page(object_type, request_args, search_after)
332
351
 
@@ -369,6 +388,7 @@ def data_blueprint(
369
388
  url_prefix: str = '/data',
370
389
  config_prefix: str = '/_config',
371
390
  auth_inspector: Optional[AuthInspector] = None,
391
+ include_all_to_ones: bool = True,
372
392
  ) -> DataBlueprint:
373
393
  """
374
394
  Create a complete data blueprint with both core and configuration endpoints.
@@ -405,7 +425,10 @@ def data_blueprint(
405
425
  config_prefix, data_sources, DefaultOperatorConfig(*data_sources)
406
426
  )
407
427
  core_bp = _core_blueprint(
408
- DataSourceDict(*data_sources), url_prefix, auth_inspector=auth_inspector
428
+ DataSourceDict(*data_sources),
429
+ url_prefix,
430
+ auth_inspector=auth_inspector,
431
+ include_all_to_ones=include_all_to_ones,
409
432
  )
410
433
  core_bp.register_blueprint(config_bp)
411
434
 
@@ -31,7 +31,7 @@ from ..api_client.exception import (
31
31
  UnsupportedOperationError,
32
32
  )
33
33
  from ..api_client.view import ResponseDict, View
34
- from ..core import DataObject, OperableDataSource
34
+ from ..core import DataObject, OperableDataSource, ReqFieldsTree
35
35
  from ..core.datasource_filter import AndFilter, DataSourceFilter
36
36
  from ..core.operator import (
37
37
  Aggregator,
@@ -160,6 +160,7 @@ class Controller:
160
160
  self,
161
161
  data_source: OperableDataSource,
162
162
  view: View,
163
+ requested_tree: ReqFieldsTree | None = None,
163
164
  auth_inspector: Optional[AuthInspector] = None,
164
165
  ) -> None:
165
166
  """
@@ -173,6 +174,7 @@ class Controller:
173
174
  """
174
175
  self.__data_source = data_source
175
176
  self.__view = view
177
+ self.__requested_tree = requested_tree
176
178
  self.__inspector = auth_inspector
177
179
 
178
180
  @property
@@ -263,13 +265,13 @@ class Controller:
263
265
  page_size=query_args.page_size,
264
266
  object_filters=self.__combine_filters(query_args.filter, ext_and),
265
267
  sort_by=query_args.sort_by,
266
- requested_fields=query_args.requested_fields,
268
+ requested_tree=self.__requested_tree,
267
269
  )
268
- document_meta = {
270
+ meta = {
269
271
  'total': total,
270
272
  'types': self.__data_source.get_attribute_types(object_type),
271
273
  }
272
- return self.__view.dump_bulk(data_objects, document_meta=document_meta)
274
+ return self.__view.dump_bulk(data_objects, document_meta=meta)
273
275
 
274
276
  @validate(Counter, 'get_count', OperatorMethod.COUNT)
275
277
  def get_count(
@@ -545,6 +547,7 @@ class Controller:
545
547
  query_args.page_size,
546
548
  self.__combine_filters(query_args.filter, ext_and),
547
549
  search_after,
550
+ requested_tree=self.__requested_tree,
548
551
  )
549
552
  meta = {'search_after': new_search_after}
550
553
 
@@ -657,7 +660,13 @@ class Controller:
657
660
  Raises:
658
661
  ObjectNotFoundByIdException: If no object with the given ID exists.
659
662
  """
660
- data_objects = list(self.__data_source.get_by_id(object_type, [object_id]))
663
+ data_objects = list(
664
+ self.__data_source.get_by_id(
665
+ object_type,
666
+ [object_id],
667
+ requested_tree=self.__requested_tree,
668
+ )
669
+ )
661
670
  if len(data_objects) == 0 or data_objects[0] is None:
662
671
  raise ObjectNotFoundByIdException(object_type, object_id)
663
672
  return data_objects[0]
@@ -144,7 +144,11 @@ class ApiDataSource(
144
144
 
145
145
  client = self.__client_factory()
146
146
  json_responses = (
147
- client.get_detail(object_type, id_)
147
+ client.get_detail(
148
+ object_type,
149
+ id_,
150
+ requested_fields=requested_fields,
151
+ )
148
152
  for id_ in object_ids
149
153
  )
150
154
  json_converter = self.__jc_factory()
@@ -184,16 +188,17 @@ class ApiDataSource(
184
188
  session: Optional[OperableSession] = None,
185
189
  requested_fields: list[str] | None = None,
186
190
  ) -> Iterable[DataObject]:
187
-
188
191
  if self.__can_cursor(object_type, object_filters):
189
192
  return self._get_list_by_cursor(
190
193
  object_type,
191
- object_filters
194
+ object_filters,
195
+ requested_fields=requested_fields,
192
196
  )
193
197
  else:
194
198
  return self.__get_list_regular(
195
199
  object_type,
196
- object_filters
200
+ object_filters,
201
+ requested_fields=requested_fields,
197
202
  )
198
203
 
199
204
  @validate('count')
@@ -266,7 +271,8 @@ class ApiDataSource(
266
271
  object_type,
267
272
  page_size,
268
273
  search_after,
269
- filter_string=filter_string
274
+ filter_string=filter_string,
275
+ requested_fields=requested_fields,
270
276
  )
271
277
  return self.__jc_factory().convert_cursor_page(transfer)
272
278
 
@@ -429,7 +435,8 @@ class ApiDataSource(
429
435
  def __get_list_regular(
430
436
  self,
431
437
  object_type: str,
432
- object_filters: Optional[DataSourceFilter]
438
+ object_filters: Optional[DataSourceFilter],
439
+ requested_fields: list[str] | None = None,
433
440
  ) -> Iterable[DataObject]:
434
441
 
435
442
  page = 1
@@ -443,7 +450,8 @@ class ApiDataSource(
443
450
  object_type,
444
451
  page,
445
452
  page_size,
446
- filter_string=filter_string
453
+ filter_string=filter_string,
454
+ requested_fields=requested_fields,
447
455
  )
448
456
  (results_page, _) = jc_converter.convert_list(transfer)
449
457
 
@@ -28,9 +28,13 @@ class JsonApiClient(HttpClient):
28
28
  config_prefix: str = '/_config',
29
29
  token_header: str = 'token',
30
30
  retries: int = 5,
31
+ status_forcelist: Optional[list[int]] = None,
31
32
  merge_collections: bool | None = None,
32
33
  ) -> None:
33
- super().__init__(token=token, token_header=token_header, retries=retries)
34
+ kwargs = {'token': token, 'token_header': token_header, 'retries': retries}
35
+ if status_forcelist is not None:
36
+ kwargs['status_forcelist'] = status_forcelist
37
+ super().__init__(**kwargs)
34
38
  self.__data_url = f'{api_url}{data_prefix}'
35
39
  self.__config_url = f'{self.__data_url}{config_prefix}'
36
40
  self.__merge_collections = merge_collections
@@ -77,7 +81,7 @@ class JsonApiClient(HttpClient):
77
81
  page_size=page_size,
78
82
  filter=filter_string,
79
83
  sort_by=sort_string,
80
- requested_field=requested_fields
84
+ requested_fields=requested_fields
81
85
  )
82
86
  headers = self._merge_headers()
83
87
  return self.__fetch_list(
@@ -455,7 +459,9 @@ class JsonApiClient(HttpClient):
455
459
  return f'{self.__config_url}/return_mode'
456
460
 
457
461
  def __no_none_value_dict(self, **kwargs) -> dict[str, Any]:
458
- return {
459
- k: v for k, v in kwargs.items()
460
- if v is not None
461
- }
462
+ str_params = {}
463
+ for k, v in kwargs.items():
464
+ if v is None:
465
+ continue
466
+ str_params[k] = ','.join([str(x) for x in v]) if isinstance(v, list) else str(v)
467
+ return str_params
@@ -5,8 +5,8 @@
5
5
  from typing import Any, Dict, Optional, Union
6
6
 
7
7
  from .parser import Parser
8
- from .view import View
9
- from ..core import DataObject
8
+ from .view import DefaultView
9
+ from ..core import DataObject, DataSource, ReqFieldsTree
10
10
  from ..core.relationship import RelationshipConfig
11
11
 
12
12
 
@@ -25,7 +25,7 @@ JsonRelationshipConfig = dict[
25
25
  ]
26
26
 
27
27
 
28
- class JsonApiConverter():
28
+ class JsonApiConverter:
29
29
 
30
30
  """
31
31
  Converts from JSON:API transfers to instances of
@@ -142,26 +142,40 @@ class JsonApiConverter():
142
142
  )
143
143
 
144
144
 
145
- class DataObjectConverter():
145
+ class DataObjectConverter:
146
146
 
147
147
  """
148
148
  Converts from instances of `DataObject` to
149
149
  JSON:API transfers.
150
150
  """
151
151
 
152
- def __init__(self, view: View) -> None:
153
- self.__view = view
152
+ def __init__(
153
+ self,
154
+ data_source: DataSource,
155
+ prefix: str | None = None,
156
+ ) -> None:
157
+ self.__data_source = data_source
158
+ self.__prefix = prefix
159
+
160
+ def __build_view(self, object_type):
161
+ req_fields_tree = ReqFieldsTree(object_type, self.__data_source)
162
+ return DefaultView(req_fields_tree, self.__prefix)
154
163
 
155
164
  def convert(self, input_: DataObject) -> JsonApiTransfer:
156
165
  """
157
166
  Converts a single `DataObject` instance to a JsonApiTransfer
158
167
  """
159
168
 
160
- return self.__view.dump(input_)
169
+ view = self.__build_view(input_.type)
170
+ return view.dump(input_)
161
171
 
162
172
  def convert_list(self, input_: list[DataObject]) -> JsonApiTransfer:
163
173
  """
164
174
  Converts a `list` of `DataObject` instances to a JsonApiTransfer
165
175
  """
166
176
 
167
- return self.__view.dump_bulk(input_)
177
+ if not input_:
178
+ msg = 'Cannot convert empty list'
179
+ raise ValueError(msg)
180
+ view = self.__build_view(input_[0].type)
181
+ return view.dump_bulk(input_)
@@ -17,7 +17,6 @@ from .converter import (
17
17
  )
18
18
  from .filter import DefaultApiFilter
19
19
  from .parser import DefaultParser
20
- from .view import DefaultView
21
20
  from ..core import DataSource
22
21
 
23
22
 
@@ -66,8 +65,7 @@ class _ConverterFactory:
66
65
  Returns an instantiated `DataObjectConverter`.
67
66
  """
68
67
 
69
- view = DefaultView(prefix=self.__prefix)
70
- return DataObjectConverter(view)
68
+ return DataObjectConverter(self.__data_source, prefix=self.__prefix)
71
69
 
72
70
  def json_converter_factory(self) -> JsonConverterFactory:
73
71
  """
@@ -87,6 +85,7 @@ def _get_client_factory(
87
85
  token: Optional[str],
88
86
  data_prefix: str,
89
87
  retries: int,
88
+ status_forcelist: list[int],
90
89
  merge_collections: bool | None,
91
90
  ) -> Callable[[], JsonApiClient]:
92
91
  """
@@ -99,6 +98,7 @@ def _get_client_factory(
99
98
  token=token,
100
99
  data_prefix=data_prefix,
101
100
  retries=retries,
101
+ status_forcelist=status_forcelist,
102
102
  merge_collections=merge_collections,
103
103
  )
104
104
 
@@ -113,6 +113,7 @@ def create_api_datasource(
113
113
 
114
114
  data_prefix: str = '/data',
115
115
  retries: int = 5,
116
+ status_forcelist: Optional[list[int]] = None,
116
117
  merge_collections: bool | None = None,
117
118
  ) -> ApiDataSource:
118
119
  """
@@ -127,6 +128,7 @@ def create_api_datasource(
127
128
  token=token,
128
129
  data_prefix=data_prefix,
129
130
  retries=retries,
131
+ status_forcelist=status_forcelist,
130
132
  merge_collections=merge_collections,
131
133
  )
132
134
  manager = _ConverterFactory(data_prefix)
@@ -0,0 +1,192 @@
1
+ # SPDX-FileCopyrightText: 2022 Genome Research Ltd.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ import urllib
6
+ from abc import ABC, abstractmethod
7
+ from datetime import date
8
+ from typing import Any, Dict, Iterable, List, Optional, Union
9
+
10
+ from ..core import DataObject
11
+ from ..core.requested_fields import ReqFieldsTree
12
+
13
+ DocumentMeta = Dict[str, Any]
14
+ DumpDict = Dict[str, Any]
15
+ DumpDictMany = List[DumpDict]
16
+ ResponseDict = Dict[str, Union[DumpDict, DumpDictMany]]
17
+
18
+
19
+ class View(ABC):
20
+ """
21
+ Provides an MVC-esque View class. Can serialize both an individual
22
+ DataObject, as well as an Iterable of DataObject instances.
23
+ """
24
+
25
+ @abstractmethod
26
+ def dump(
27
+ self,
28
+ data_object: DataObject,
29
+ document_meta: Optional[DocumentMeta] = None,
30
+ ) -> ResponseDict:
31
+ """
32
+ Create a JSON:API response for an individual DataObject result
33
+ """
34
+
35
+ @abstractmethod
36
+ def dump_bulk(
37
+ self,
38
+ data_objects: Iterable[DataObject],
39
+ document_meta: Optional[DocumentMeta] = None,
40
+ ) -> ResponseDict:
41
+ """
42
+ Create a JSON:API response for an Iterable of DataObject results
43
+ """
44
+
45
+
46
+ RelationshipDump = dict[str, dict[str, str]]
47
+ AllRelationshipsDump = dict[str, RelationshipDump]
48
+
49
+
50
+ class DefaultView(View):
51
+ """
52
+ Provides a default implementation of the View ABC.
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ requested_tree: ReqFieldsTree,
58
+ prefix: str = '',
59
+ hop_limit: Optional[int] = None,
60
+ ) -> None:
61
+ """
62
+ Args:
63
+
64
+ - prefix - the URL prefix on which the
65
+ data blueprint is served
66
+ - hop_limit - the maximum recursion limit
67
+ on including related to-one
68
+ objects. Default no limit
69
+ - requested_tree - a tree data structure of the
70
+ requested fields for the query
71
+ """
72
+
73
+ self.__prefix = prefix
74
+ self.__hop_limit = hop_limit
75
+ self.__requested_tree = requested_tree
76
+
77
+ def dump(
78
+ self,
79
+ data_object: DataObject,
80
+ document_meta: Optional[DocumentMeta] = None,
81
+ ) -> ResponseDict:
82
+ response = {
83
+ 'data': self.__dump_object(
84
+ data_object,
85
+ tree=self.__requested_tree,
86
+ ),
87
+ }
88
+ if document_meta is not None:
89
+ response['meta'] = document_meta
90
+ return response
91
+
92
+ def dump_bulk(
93
+ self,
94
+ data_objects: Iterable[DataObject],
95
+ document_meta: Optional[DocumentMeta] = None,
96
+ ) -> ResponseDict:
97
+ dumped = [
98
+ self.__dump_object(
99
+ data_object,
100
+ tree=self.__requested_tree,
101
+ )
102
+ for data_object in data_objects
103
+ ]
104
+ response = {'data': dumped}
105
+ if document_meta is not None:
106
+ response['meta'] = document_meta
107
+ return response
108
+
109
+ def __dump_object(
110
+ self,
111
+ data_object: DataObject,
112
+ tree: ReqFieldsTree,
113
+ ) -> DumpDict:
114
+ dump = {'type': data_object.type, 'id': data_object.id}
115
+ # Stub trees are created by requested_fields paths ending in ".id"
116
+ if not tree.is_stub:
117
+ self.__add_attributes(data_object, dump, tree)
118
+ if tree.has_relationships:
119
+ self.__add_relationships(data_object, dump, tree)
120
+ return dump
121
+
122
+ def __add_attributes(
123
+ self,
124
+ data_object: DataObject,
125
+ dump: DumpDict,
126
+ tree: ReqFieldsTree | None,
127
+ ):
128
+ if tree and (attr_names := tree.attribute_names):
129
+ # Only add requested attributes
130
+ dump['attributes'] = self.__convert_attributes(
131
+ {name: getattr(data_object, name) for name in attr_names}
132
+ )
133
+ elif data_object.attributes:
134
+ # Default behaviour is to add all attributes
135
+ dump['attributes'] = self.__convert_attributes(data_object.attributes)
136
+
137
+ def __add_relationships(
138
+ self,
139
+ data_object: DataObject,
140
+ dump: DumpDict,
141
+ tree: ReqFieldsTree | None = None,
142
+ ) -> DumpDict:
143
+ rel_dict = self.__dump_to_one_relationships(
144
+ data_object, tree
145
+ ) | self.__dump_to_many_relationships(data_object, tree)
146
+ if rel_dict:
147
+ dump['relationships'] = rel_dict
148
+
149
+ def __dump_to_one_relationships(
150
+ self,
151
+ data_object: DataObject,
152
+ tree: ReqFieldsTree,
153
+ ) -> RelationshipDump:
154
+ to_ones = {}
155
+ for name in tree.to_one_names():
156
+ if name in data_object._to_one_objects:
157
+ one_dump = None
158
+ if one := data_object._to_one_objects.get(name):
159
+ if sub_tree := tree.get_sub_tree(name):
160
+ one_dump = {'data': self.__dump_object(one, tree=sub_tree)}
161
+ else:
162
+ one_dump = {'data': {'type': one.type, 'id': one.id}}
163
+ to_ones[name] = one_dump
164
+ return to_ones
165
+
166
+ def __dump_to_many_relationships(
167
+ self,
168
+ data_object: DataObject,
169
+ tree: ReqFieldsTree,
170
+ ) -> RelationshipDump:
171
+ quoted_id = urllib.parse.quote(str(data_object.id), safe='')
172
+ to_many = {}
173
+ for name in tree.to_many_names():
174
+ if sub_tree := tree.get_sub_tree(name):
175
+ to_many[name] = {
176
+ 'data': [
177
+ self.__dump_object(x, tree=sub_tree) for x in getattr(data_object, name)
178
+ ]
179
+ }
180
+ else:
181
+ link = f'{self.__prefix}/{data_object.type}/{quoted_id}/{name}'
182
+ to_many[name] = {'links': {'related': link}}
183
+ return to_many
184
+
185
+ def __convert_attributes(self, attributes: dict[str, Any]) -> dict[str, Any]:
186
+ return {k: self.__convert_value(v) for k, v in attributes.items()}
187
+
188
+ def __convert_value(self, __v: Any) -> Any:
189
+ if isinstance(__v, date):
190
+ # `datetime` is a subclass of `date`
191
+ return __v.isoformat()
192
+ return __v
@@ -309,7 +309,7 @@ def test(ctx, type_, pytest_options):
309
309
 
310
310
  click.echo('Running tests...')
311
311
  if type_ in {'unit', 'system', 'integration'}:
312
- verbosity = '-v' if type_ == 'unit' else '-vvvx'
312
+ verbosity = '-v' if type_ == 'unit' else '-vv'
313
313
  # shlex will correctly re-quote any quoted arguments from the command
314
314
  # line:
315
315
  pytest_cmd = shlex.join(['pytest', verbosity, type_, *pytest_options])
@@ -30,6 +30,7 @@ from .data_object_converter import ( # noqa F401
30
30
  )
31
31
  from .factory import core_data_object # noqa F401
32
32
  from .http_client import HttpClient # noqa F401
33
+ from .requested_fields import ReqFieldsTree # noqa: F401
33
34
  from .validate import ( # noqa F401
34
35
  Validator,
35
36
  ValidationSeverity,
@@ -18,10 +18,12 @@ class HttpClient:
18
18
  self,
19
19
  token: Optional[str] = None,
20
20
  token_header: str = 'token',
21
- retries: int = 5
21
+ retries: int = 5,
22
+ status_forcelist: Optional[list[int]] = [429, 502, 503, 504],
22
23
  ) -> None:
23
24
  self.__token = self._token_header(token_header, token)
24
25
  self.__retries = retries
26
+ self.__status_forcelist = status_forcelist
25
27
 
26
28
  def _token_header(
27
29
  self,
@@ -77,7 +79,7 @@ class HttpClient:
77
79
  retry_strategy = Retry(
78
80
  total=self.__retries,
79
81
  backoff_factor=1,
80
- status_forcelist=[429, 502, 503, 504]
82
+ status_forcelist=self.__status_forcelist
81
83
  )
82
84
  session.mount('http://', HTTPAdapter(max_retries=retry_strategy))
83
85
  session.mount('https://', HTTPAdapter(max_retries=retry_strategy))
@@ -14,6 +14,7 @@ from ..datasource_filter import DataSourceFilter
14
14
 
15
15
  if typing.TYPE_CHECKING:
16
16
  from ..data_object import DataObject
17
+ from ..requested_fields import ReqFieldsTree
17
18
  from ..session import OperableSession
18
19
 
19
20
 
@@ -48,7 +49,8 @@ class Cursor(_Filterable, ABC):
48
49
  object_filters: Optional[DataSourceFilter] = None,
49
50
  search_after: list[str] | None = None,
50
51
  session: Optional[OperableSession] = None,
51
- requested_fields: list[str] | None = None
52
+ requested_fields: list[str] | None = None,
53
+ requested_tree: ReqFieldsTree | None = None,
52
54
  ) -> tuple[Iterable[DataObject], list[str] | None]:
53
55
  """
54
56
  Gets an `Iterable` of `DataObject` instances of the given
@@ -118,7 +120,7 @@ class Cursor(_Filterable, ABC):
118
120
  object_type: str,
119
121
  object_filters: Optional[DataSourceFilter] = None,
120
122
  session: Optional[OperableSession] = None,
121
- requested_fields: list[str] | None = None
123
+ **kwargs,
122
124
  ) -> Iterable[DataObject]:
123
125
  """
124
126
  A usable implementation for `ListGetter.get_list()`
@@ -135,7 +137,7 @@ class Cursor(_Filterable, ABC):
135
137
  object_filters=object_filters,
136
138
  search_after=search_after,
137
139
  session=session,
138
- requested_fields=requested_fields,
140
+ **kwargs,
139
141
  )
140
142
  objs = list(fetched)
141
143