UncountablePythonSDK 0.0.186__tar.gz → 0.0.187__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 (452) hide show
  1. {uncountablepythonsdk-0.0.186/UncountablePythonSDK.egg-info → uncountablepythonsdk-0.0.187}/PKG-INFO +1 -1
  2. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187/UncountablePythonSDK.egg-info}/PKG-INFO +1 -1
  3. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/UncountablePythonSDK.egg-info/SOURCES.txt +3 -0
  4. uncountablepythonsdk-0.0.187/examples/integration-server/jobs/materials_auto/example_scale_connection.py +150 -0
  5. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/profile.yaml +5 -0
  6. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_inner.py +18 -3
  7. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/non_discriminated_union_exceptions.py +0 -2
  8. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/scan_profiles.py +11 -4
  9. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/scheduler.py +123 -65
  10. uncountablepythonsdk-0.0.187/uncountable/integration/service.py +74 -0
  11. uncountablepythonsdk-0.0.187/uncountable/integration/service_runner.py +44 -0
  12. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/entity_t.py +6 -0
  13. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/job_definition.py +1 -0
  14. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/job_definition_t.py +15 -0
  15. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/.github/workflows/documentation.yml +0 -0
  16. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/.github/workflows/publish.yml +0 -0
  17. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/.gitignore +0 -0
  18. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/README.md +0 -0
  19. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/UncountablePythonSDK.egg-info/dependency_links.txt +0 -0
  20. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/UncountablePythonSDK.egg-info/requires.txt +0 -0
  21. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/UncountablePythonSDK.egg-info/top_level.txt +0 -0
  22. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/.flowmarkignore +0 -0
  23. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/.gitignore +0 -0
  24. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/conf.py +0 -0
  25. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/index.md +0 -0
  26. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/integration_examples/add_file_to_folder.md +0 -0
  27. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/integration_examples/create_ingredient.md +0 -0
  28. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/integration_examples/create_output.md +0 -0
  29. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/integration_examples/index.md +0 -0
  30. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/integration_examples/upload_file.md +0 -0
  31. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/justfile +0 -0
  32. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/requirements.txt +0 -0
  33. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/android-chrome-192x192.png +0 -0
  34. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/android-chrome-512x512.png +0 -0
  35. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/apple-touch-icon.png +0 -0
  36. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/browserconfig.xml +0 -0
  37. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/favicon-16x16.png +0 -0
  38. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/favicon-32x32.png +0 -0
  39. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/manifest.json +0 -0
  40. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/mstile-150x150.png +0 -0
  41. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/favicons/safari-pinned-tab.svg +0 -0
  42. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/docs/static/logo_blue.png +0 -0
  43. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/async_batch.py +0 -0
  44. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/async_batch_large_parse.py +0 -0
  45. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/basic_auth.py +0 -0
  46. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/create_entity.py +0 -0
  47. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/create_ingredient_sdk.py +0 -0
  48. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/download_files.py +0 -0
  49. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/edit_recipe_inputs.py +0 -0
  50. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/concurrent_cron.py +0 -0
  51. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_cron.py +0 -0
  52. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_http.py +0 -0
  53. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_http_get.py +0 -0
  54. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_instrument.py +0 -0
  55. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_parse.py +0 -0
  56. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_predictions.py +0 -0
  57. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_runsheet_wh.py +0 -0
  58. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/jobs/materials_auto/example_wh.py +0 -0
  59. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/integration-server/pyproject.toml +0 -0
  60. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/invoke_uploader.py +0 -0
  61. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/oauth.py +0 -0
  62. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/set_input_pdf_attribute.py +0 -0
  63. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/set_recipe_metadata_file.py +0 -0
  64. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/set_recipe_output_file_sdk.py +0 -0
  65. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/stream_dataset_measurements.py +0 -0
  66. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/examples/upload_files.py +0 -0
  67. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/__init__.py +0 -0
  68. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/__init__.py +0 -0
  69. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/cached_parser.py +0 -0
  70. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/case_convert.py +0 -0
  71. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_base.py +0 -0
  72. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_builder.py +0 -0
  73. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_cache.py +0 -0
  74. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_error.py +0 -0
  75. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_function_type.py +0 -0
  76. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/parser_options.py +0 -0
  77. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/argument_parser/type_predicates.py +0 -0
  78. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/__init__.py +0 -0
  79. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_blob_session.py +0 -0
  80. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_file_share_session.py +0 -0
  81. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_gdrive_session.py +0 -0
  82. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_local_session.py +0 -0
  83. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_s3_session.py +0 -0
  84. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_sftp_connection.py +0 -0
  85. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/_sftp_session.py +0 -0
  86. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/file_type_utils.py +0 -0
  87. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/filesystem_utils/filesystem_session.py +0 -0
  88. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/py.typed +0 -0
  89. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/__init__.py +0 -0
  90. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/annotation.py +0 -0
  91. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/missing_sentry.py +0 -0
  92. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/opaque_key.py +0 -0
  93. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/serial_alias.py +0 -0
  94. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/serial_class.py +0 -0
  95. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/serial_generic.py +0 -0
  96. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/serial_union.py +0 -0
  97. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/unknown.py +0 -0
  98. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/usage.py +0 -0
  99. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization/yaml.py +0 -0
  100. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization_util/__init__.py +0 -0
  101. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization_util/_get_type_for_serialization.py +0 -0
  102. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization_util/convert_to_snakecase.py +0 -0
  103. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization_util/dataclasses.py +0 -0
  104. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/serialization_util/serialization_helpers.py +0 -0
  105. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/strenum_compat/__init__.py +0 -0
  106. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/strenum_compat/strenum_compat.py +0 -0
  107. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/__init__.py +0 -0
  108. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/__main__.py +0 -0
  109. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/actions_registry/__init__.py +0 -0
  110. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/actions_registry/__main__.py +0 -0
  111. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/actions_registry/emit_python.py +0 -0
  112. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/actions_registry/emit_typescript.py +0 -0
  113. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/builder.py +0 -0
  114. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/builder_types.py +0 -0
  115. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/config.py +0 -0
  116. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/cross_output_links.py +0 -0
  117. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_io_ts.py +0 -0
  118. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_open_api.py +0 -0
  119. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_open_api_util.py +0 -0
  120. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_python.py +0 -0
  121. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_scss.py +0 -0
  122. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_typescript.py +0 -0
  123. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/emit_typescript_util.py +0 -0
  124. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/load_types.py +0 -0
  125. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/open_api_util.py +0 -0
  126. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/parts/base.py.prepart +0 -0
  127. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/parts/base.ts.prepart +0 -0
  128. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/test.py +0 -0
  129. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/type_info/__main__.py +0 -0
  130. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/type_info/emit_type_info.py +0 -0
  131. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/ui_entry_actions/__init__.py +0 -0
  132. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/ui_entry_actions/generate_ui_entry_actions.py +0 -0
  133. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/util.py +0 -0
  134. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/value_spec/__init__.py +0 -0
  135. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/value_spec/__main__.py +0 -0
  136. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/value_spec/convert_type.py +0 -0
  137. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/value_spec/emit_python.py +0 -0
  138. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pkgs/type_spec/value_spec/types.py +0 -0
  139. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/pyproject.toml +0 -0
  140. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/setup.cfg +0 -0
  141. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/__init__.py +0 -0
  142. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/__init__.py +0 -0
  143. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/async_batch.py +0 -0
  144. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/client.py +0 -0
  145. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/environment.py +0 -0
  146. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/file_upload.py +0 -0
  147. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/query/__init__.py +0 -0
  148. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/query/builder.py +0 -0
  149. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/query/column.py +0 -0
  150. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/query/row.py +0 -0
  151. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/query/types.py +0 -0
  152. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/core/types.py +0 -0
  153. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/__init__.py +0 -0
  154. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/cli.py +0 -0
  155. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/construct_client.py +0 -0
  156. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/cron.py +0 -0
  157. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/db/__init__.py +0 -0
  158. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/db/connect.py +0 -0
  159. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/db/session.py +0 -0
  160. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/entrypoint.py +0 -0
  161. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/executors/__init__.py +0 -0
  162. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/executors/executors.py +0 -0
  163. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/executors/generic_upload_executor.py +0 -0
  164. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/executors/script_executor.py +0 -0
  165. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/http_server/__init__.py +0 -0
  166. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/http_server/types.py +0 -0
  167. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/job.py +0 -0
  168. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/__init__.py +0 -0
  169. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/__init__.py +0 -0
  170. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/command_client.py +0 -0
  171. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/command_server.py +0 -0
  172. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/constants.py +0 -0
  173. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/protocol/__init__.py +0 -0
  174. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/protocol/command_server.proto +0 -0
  175. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +0 -0
  176. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +0 -0
  177. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +0 -0
  178. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/provision_webhook.py +0 -0
  179. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/command_server/types.py +0 -0
  180. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/__init__.py +0 -0
  181. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/datastore_postgres.py +0 -0
  182. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/datastore_sql_base.py +0 -0
  183. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/datastore_sqlite.py +0 -0
  184. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/factory.py +0 -0
  185. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/interface.py +0 -0
  186. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/datastore/model.py +0 -0
  187. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/job_process.py +0 -0
  188. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/job_runner.py +0 -0
  189. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/job_scheduler.py +0 -0
  190. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/queue_runner.py +0 -0
  191. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/types.py +0 -0
  192. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/queue_runner/worker.py +0 -0
  193. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/request_context.py +0 -0
  194. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/secret_retrieval/__init__.py +0 -0
  195. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/secret_retrieval/basic_secret.py +0 -0
  196. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/secret_retrieval/retrieve_secret.py +0 -0
  197. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/server.py +0 -0
  198. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/telemetry.py +0 -0
  199. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/webhook_bootstrap.py +0 -0
  200. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/webhook_entity.py +0 -0
  201. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/integration/webhook_server/entrypoint.py +0 -0
  202. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/py.typed +0 -0
  203. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/__init__.py +0 -0
  204. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/__init__.py +0 -0
  205. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/batch/__init__.py +0 -0
  206. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/batch/execute_batch.py +0 -0
  207. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/batch/execute_batch_load_async.py +0 -0
  208. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/chemical/__init__.py +0 -0
  209. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/chemical/convert_chemical_formats.py +0 -0
  210. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/condition_parameters/__init__.py +0 -0
  211. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/condition_parameters/upsert_condition_match.py +0 -0
  212. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/condition_parameters/upsert_condition_matches.py +0 -0
  213. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/__init__.py +0 -0
  214. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/add_entity_comment.py +0 -0
  215. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/create_entities.py +0 -0
  216. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/create_entity.py +0 -0
  217. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/create_or_update_entities.py +0 -0
  218. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/create_or_update_entity.py +0 -0
  219. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/export_entities.py +0 -0
  220. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/get_entities_data.py +0 -0
  221. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/grant_entity_permissions.py +0 -0
  222. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/list_aggregate.py +0 -0
  223. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/list_entities.py +0 -0
  224. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/lock_entity.py +0 -0
  225. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/lookup_entity.py +0 -0
  226. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/resolve_entity_ids.py +0 -0
  227. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/set_barcode.py +0 -0
  228. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/set_entities_field_values.py +0 -0
  229. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/set_entity_field_values.py +0 -0
  230. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/set_values.py +0 -0
  231. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/transition_entity_phase.py +0 -0
  232. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/entity/unlock_entity.py +0 -0
  233. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/equipment/__init__.py +0 -0
  234. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/equipment/associate_equipment_input.py +0 -0
  235. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/field_options/__init__.py +0 -0
  236. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/field_options/upsert_field_options.py +0 -0
  237. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/file_folders/__init__.py +0 -0
  238. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/file_folders/add_file_to_folder.py +0 -0
  239. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/file_folders/modify_file_system.py +0 -0
  240. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/files/__init__.py +0 -0
  241. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/files/download_file.py +0 -0
  242. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/id_source/__init__.py +0 -0
  243. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/id_source/list_id_source.py +0 -0
  244. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/id_source/match_id_source.py +0 -0
  245. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/input_groups/__init__.py +0 -0
  246. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/input_groups/get_input_group_names.py +0 -0
  247. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/__init__.py +0 -0
  248. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/create_inputs.py +0 -0
  249. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/get_input_data.py +0 -0
  250. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/get_input_names.py +0 -0
  251. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/get_inputs_data.py +0 -0
  252. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/set_input_attribute_values.py +0 -0
  253. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/set_input_category.py +0 -0
  254. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/set_input_subcategories.py +0 -0
  255. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/inputs/set_intermediate_type.py +0 -0
  256. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/integrations/__init__.py +0 -0
  257. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/integrations/publish_realtime_data.py +0 -0
  258. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/integrations/push_notification.py +0 -0
  259. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/integrations/register_sockets_token.py +0 -0
  260. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/listing/__init__.py +0 -0
  261. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/listing/export_listing.py +0 -0
  262. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/listing/fetch_listing.py +0 -0
  263. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/material_families/__init__.py +0 -0
  264. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/material_families/update_entity_material_families.py +0 -0
  265. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/ml/__init__.py +0 -0
  266. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/ml/get_analyze_results.py +0 -0
  267. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/ml/get_suggest_results.py +0 -0
  268. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/ml/submit_async_job.py +0 -0
  269. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/notebooks/__init__.py +0 -0
  270. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/notebooks/add_notebook_content.py +0 -0
  271. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/notebooks/get_notebook_content.py +0 -0
  272. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/output_parameters/__init__.py +0 -0
  273. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/output_parameters/swap_output_condition_parameters.py +0 -0
  274. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/outputs/__init__.py +0 -0
  275. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/outputs/get_output_data.py +0 -0
  276. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/outputs/get_output_names.py +0 -0
  277. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/outputs/get_output_organization.py +0 -0
  278. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/outputs/resolve_output_conditions.py +0 -0
  279. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/outputs/update_output_condition_parameter.py +0 -0
  280. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/permissions/__init__.py +0 -0
  281. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/permissions/set_core_permissions.py +0 -0
  282. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/permissions/set_entity_permission.py +0 -0
  283. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/project/__init__.py +0 -0
  284. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/project/get_projects.py +0 -0
  285. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/project/get_projects_data.py +0 -0
  286. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipe_links/__init__.py +0 -0
  287. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipe_links/create_recipe_link.py +0 -0
  288. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipe_links/create_recipe_links.py +0 -0
  289. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipe_links/remove_recipe_link.py +0 -0
  290. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipe_metadata/__init__.py +0 -0
  291. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +0 -0
  292. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/__init__.py +0 -0
  293. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/add_recipe_to_project.py +0 -0
  294. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/add_time_series_data.py +0 -0
  295. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/archive_recipes.py +0 -0
  296. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/associate_recipe_as_input.py +0 -0
  297. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/associate_recipe_as_lot.py +0 -0
  298. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/clear_recipe_outputs.py +0 -0
  299. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/create_mix_order.py +0 -0
  300. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/create_recipe.py +0 -0
  301. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/create_recipes.py +0 -0
  302. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/disassociate_recipe_as_input.py +0 -0
  303. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/edit_recipe_inputs.py +0 -0
  304. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_column_calculation_values.py +0 -0
  305. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_curve.py +0 -0
  306. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_recipe_calculations.py +0 -0
  307. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_recipe_links.py +0 -0
  308. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_recipe_names.py +0 -0
  309. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_recipe_output_metadata.py +0 -0
  310. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/get_recipes_data.py +0 -0
  311. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/lock_recipes.py +0 -0
  312. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/remove_recipe_from_project.py +0 -0
  313. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_inputs.py +0 -0
  314. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_metadata.py +0 -0
  315. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_output_annotations.py +0 -0
  316. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_output_file.py +0 -0
  317. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_outputs.py +0 -0
  318. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_tags.py +0 -0
  319. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/set_recipe_total.py +0 -0
  320. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/unarchive_recipes.py +0 -0
  321. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/unlock_recipes.py +0 -0
  322. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/upsert_recipe_workflow_step.py +0 -0
  323. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/recipes/upsert_step_relationships.py +0 -0
  324. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/runsheet/__init__.py +0 -0
  325. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/runsheet/complete_async_upload.py +0 -0
  326. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/runsheet/export_default_runsheet.py +0 -0
  327. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/time_series/__init__.py +0 -0
  328. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/time_series/ingest_dataset_measurements.py +0 -0
  329. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/triggers/__init__.py +0 -0
  330. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/triggers/run_trigger.py +0 -0
  331. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/uploader/__init__.py +0 -0
  332. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/uploader/complete_async_parse.py +0 -0
  333. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/uploader/invoke_uploader.py +0 -0
  334. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/user/__init__.py +0 -0
  335. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/api/user/get_current_user_info.py +0 -0
  336. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/async_batch.py +0 -0
  337. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/async_batch_processor.py +0 -0
  338. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/async_batch_t.py +0 -0
  339. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/async_jobs.py +0 -0
  340. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/async_jobs_t.py +0 -0
  341. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/auth_retrieval.py +0 -0
  342. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/auth_retrieval_t.py +0 -0
  343. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/base.py +0 -0
  344. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/base_t.py +0 -0
  345. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/calculations.py +0 -0
  346. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/calculations_t.py +0 -0
  347. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/chemical_structure.py +0 -0
  348. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/chemical_structure_t.py +0 -0
  349. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/client_base.py +0 -0
  350. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/client_config.py +0 -0
  351. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/client_config_t.py +0 -0
  352. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/condition_match.py +0 -0
  353. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/condition_match_t.py +0 -0
  354. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/curves.py +0 -0
  355. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/curves_t.py +0 -0
  356. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/data.py +0 -0
  357. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/data_t.py +0 -0
  358. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/dataset_measurements.py +0 -0
  359. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/dataset_measurements_t.py +0 -0
  360. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/entity.py +0 -0
  361. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/experiment_groups.py +0 -0
  362. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/experiment_groups_t.py +0 -0
  363. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/exports.py +0 -0
  364. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/exports_t.py +0 -0
  365. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/field_values.py +0 -0
  366. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/field_values_t.py +0 -0
  367. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/fields.py +0 -0
  368. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/fields_t.py +0 -0
  369. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/generic_upload.py +0 -0
  370. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/generic_upload_t.py +0 -0
  371. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/id_source.py +0 -0
  372. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/id_source_t.py +0 -0
  373. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/identifier.py +0 -0
  374. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/identifier_t.py +0 -0
  375. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/input_attributes.py +0 -0
  376. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/input_attributes_t.py +0 -0
  377. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/inputs.py +0 -0
  378. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/inputs_t.py +0 -0
  379. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/integration_server.py +0 -0
  380. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/integration_server_t.py +0 -0
  381. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/integration_session.py +0 -0
  382. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/integration_session_t.py +0 -0
  383. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/integrations.py +0 -0
  384. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/integrations_t.py +0 -0
  385. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/listing.py +0 -0
  386. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/listing_t.py +0 -0
  387. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/ml_reports.py +0 -0
  388. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/ml_reports_t.py +0 -0
  389. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/notices.py +0 -0
  390. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/notices_t.py +0 -0
  391. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/notifications.py +0 -0
  392. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/notifications_t.py +0 -0
  393. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/outputs.py +0 -0
  394. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/outputs_t.py +0 -0
  395. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/overrides.py +0 -0
  396. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/overrides_t.py +0 -0
  397. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/permissions.py +0 -0
  398. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/permissions_t.py +0 -0
  399. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/phases.py +0 -0
  400. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/phases_t.py +0 -0
  401. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/post_base.py +0 -0
  402. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/post_base_t.py +0 -0
  403. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/queued_job.py +0 -0
  404. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/queued_job_t.py +0 -0
  405. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_identifiers.py +0 -0
  406. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_identifiers_t.py +0 -0
  407. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_inputs.py +0 -0
  408. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_inputs_t.py +0 -0
  409. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_links.py +0 -0
  410. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_links_t.py +0 -0
  411. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_metadata.py +0 -0
  412. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_metadata_t.py +0 -0
  413. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_output_metadata.py +0 -0
  414. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_output_metadata_t.py +0 -0
  415. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_step_relationships.py +0 -0
  416. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_step_relationships_t.py +0 -0
  417. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_tags.py +0 -0
  418. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_tags_t.py +0 -0
  419. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_workflow_step_types.py +0 -0
  420. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_workflow_step_types_t.py +0 -0
  421. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_workflow_steps.py +0 -0
  422. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipe_workflow_steps_t.py +0 -0
  423. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipes.py +0 -0
  424. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/recipes_t.py +0 -0
  425. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/request_headers.py +0 -0
  426. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/request_headers_t.py +0 -0
  427. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/response.py +0 -0
  428. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/response_t.py +0 -0
  429. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/runsheet.py +0 -0
  430. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/runsheet_format.py +0 -0
  431. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/runsheet_format_t.py +0 -0
  432. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/runsheet_t.py +0 -0
  433. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/secret_retrieval.py +0 -0
  434. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/secret_retrieval_t.py +0 -0
  435. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/sockets.py +0 -0
  436. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/sockets_t.py +0 -0
  437. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/specs.py +0 -0
  438. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/specs_t.py +0 -0
  439. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/step_relationships.py +0 -0
  440. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/step_relationships_t.py +0 -0
  441. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/units.py +0 -0
  442. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/units_t.py +0 -0
  443. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/uploader.py +0 -0
  444. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/uploader_t.py +0 -0
  445. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/users.py +0 -0
  446. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/users_t.py +0 -0
  447. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/webhook.py +0 -0
  448. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/webhook_job.py +0 -0
  449. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/webhook_job_t.py +0 -0
  450. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/webhook_t.py +0 -0
  451. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/workflows.py +0 -0
  452. {uncountablepythonsdk-0.0.186 → uncountablepythonsdk-0.0.187}/uncountable/types/workflows_t.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.186
3
+ Version: 0.0.187
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.186
3
+ Version: 0.0.187
4
4
  Summary: Uncountable SDK
5
5
  Project-URL: Homepage, https://github.com/uncountableinc/uncountable-python-sdk
6
6
  Project-URL: Repository, https://github.com/uncountableinc/uncountable-python-sdk.git
@@ -52,6 +52,7 @@ examples/integration-server/jobs/materials_auto/example_instrument.py
52
52
  examples/integration-server/jobs/materials_auto/example_parse.py
53
53
  examples/integration-server/jobs/materials_auto/example_predictions.py
54
54
  examples/integration-server/jobs/materials_auto/example_runsheet_wh.py
55
+ examples/integration-server/jobs/materials_auto/example_scale_connection.py
55
56
  examples/integration-server/jobs/materials_auto/example_wh.py
56
57
  examples/integration-server/jobs/materials_auto/profile.yaml
57
58
  pkgs/__init__.py
@@ -151,6 +152,8 @@ uncountable/integration/request_context.py
151
152
  uncountable/integration/scan_profiles.py
152
153
  uncountable/integration/scheduler.py
153
154
  uncountable/integration/server.py
155
+ uncountable/integration/service.py
156
+ uncountable/integration/service_runner.py
154
157
  uncountable/integration/telemetry.py
155
158
  uncountable/integration/webhook_bootstrap.py
156
159
  uncountable/integration/webhook_entity.py
@@ -0,0 +1,150 @@
1
+ import asyncio
2
+ import json
3
+ import random
4
+ from dataclasses import dataclass
5
+ from decimal import Decimal
6
+
7
+ from uncountable.core.client import Client
8
+ from uncountable.integration.service import Service, ServiceArguments, register_service
9
+ from uncountable.types import entity_t, identifier_t, listing_t, sockets_t
10
+ from uncountable.types.base_t import ObjectId
11
+ from uncountable.types.integration_session_t import IntegrationSessionInstrument
12
+ from websockets.asyncio.client import connect
13
+
14
+ from pkgs.serialization_util import serialize_for_api
15
+
16
+ SCALE_EQUIPMENT_NAMES = [
17
+ "Instrument Scale One",
18
+ "Instrument Scale Two",
19
+ "Instrument Scale Three",
20
+ ]
21
+ EQUIPMENT_ID_COLUMN_REF_NAME = "id"
22
+ EQUIPMENT_NAME_COLUMN_REF_NAME = "name"
23
+ SOCKET_URL = "ws://host.docker.internal:8765"
24
+ READING_INTERVAL_SECONDS = 1.0
25
+
26
+
27
+ @dataclass(kw_only=True)
28
+ class InstrumentRoom:
29
+ equipment_name: str
30
+ token: str
31
+ room_key: str
32
+
33
+
34
+ @dataclass(kw_only=True)
35
+ class InstrumentReading:
36
+ equipment_name: str
37
+ value: Decimal
38
+
39
+
40
+ def _build_equipment_column(ref_name: str) -> listing_t.ColumnIdentifierEntityRefName:
41
+ return listing_t.ColumnIdentifierEntityRefName(
42
+ entity_type=entity_t.EntityType.EQUIPMENT, ref_name=ref_name
43
+ )
44
+
45
+
46
+ def _resolve_equipment_id(*, client: Client, equipment_name: str) -> ObjectId:
47
+ id_column = _build_equipment_column(EQUIPMENT_ID_COLUMN_REF_NAME)
48
+ name_column = _build_equipment_column(EQUIPMENT_NAME_COLUMN_REF_NAME)
49
+ results = client.fetch_listing(
50
+ entity_type=entity_t.EntityType.EQUIPMENT,
51
+ columns=[id_column],
52
+ filters=listing_t.FilterNodeColumnAnd(
53
+ filters=(
54
+ listing_t.FilterSpecEquals(
55
+ relation=listing_t.FilterRelation.EQUALS,
56
+ column=name_column,
57
+ value=equipment_name,
58
+ ),
59
+ )
60
+ ),
61
+ ).results
62
+ if len(results) != 1:
63
+ raise Exception(
64
+ f"expected exactly one equipment named {equipment_name}, found {len(results)}"
65
+ )
66
+ equipment_id = results[0].column_values[0]
67
+ if not isinstance(equipment_id, int):
68
+ raise Exception(
69
+ f"expected an integer id for equipment named {equipment_name}, found {equipment_id!r}"
70
+ )
71
+ return ObjectId(equipment_id)
72
+
73
+
74
+ @register_service
75
+ class ScaleConnectionService(Service):
76
+ def run(self, args: ServiceArguments) -> None:
77
+ rooms = [
78
+ self._register_room(args=args, equipment_name=equipment_name)
79
+ for equipment_name in SCALE_EQUIPMENT_NAMES
80
+ ]
81
+ asyncio.run(self._stream_readings(args=args, rooms=rooms))
82
+
83
+ def _register_room(
84
+ self, *, args: ServiceArguments, equipment_name: str
85
+ ) -> InstrumentRoom:
86
+ equipment_id = _resolve_equipment_id(
87
+ client=args.client, equipment_name=equipment_name
88
+ )
89
+ registration = args.client.register_sockets_token(
90
+ socket_request=sockets_t.SocketRequestIntegrationSession(
91
+ integration_session=IntegrationSessionInstrument(
92
+ equipment_key=identifier_t.IdentifierKeyId(id=equipment_id)
93
+ )
94
+ )
95
+ ).response
96
+ return InstrumentRoom(
97
+ equipment_name=equipment_name,
98
+ token=registration.token,
99
+ room_key=registration.room_key,
100
+ )
101
+
102
+ async def _stream_readings(
103
+ self, *, args: ServiceArguments, rooms: list[InstrumentRoom]
104
+ ) -> None:
105
+ rooms_by_name = {room.equipment_name: room for room in rooms}
106
+ async with connect(
107
+ SOCKET_URL, additional_headers={"X-UNC-EXTERNAL": "true"}
108
+ ) as ws:
109
+ for room in rooms:
110
+ await ws.send(
111
+ json.dumps(
112
+ serialize_for_api(
113
+ sockets_t.JoinRoomWithTokenSocketClientMessage(
114
+ token=room.token
115
+ )
116
+ )
117
+ )
118
+ )
119
+ args.logger.log_info(f"Joined room for instrument {room.equipment_name}")
120
+
121
+ readings: asyncio.Queue[InstrumentReading] = asyncio.Queue()
122
+ emit_task = asyncio.create_task(
123
+ self._emit_readings(rooms=rooms, readings=readings)
124
+ )
125
+ try:
126
+ while True:
127
+ reading = await readings.get()
128
+ room = rooms_by_name[reading.equipment_name]
129
+ await ws.send(
130
+ json.dumps(
131
+ serialize_for_api(
132
+ sockets_t.SendInstrumentReadingClientMessage(
133
+ value=reading.value, room_key=room.room_key
134
+ )
135
+ )
136
+ )
137
+ )
138
+ finally:
139
+ emit_task.cancel()
140
+
141
+ async def _emit_readings(
142
+ self, *, rooms: list[InstrumentRoom], readings: asyncio.Queue[InstrumentReading]
143
+ ) -> None:
144
+ while True:
145
+ room = random.choice(rooms)
146
+ value = Decimal(str(round(random.uniform(0, 500), 2)))
147
+ await readings.put(
148
+ InstrumentReading(equipment_name=room.equipment_name, value=value)
149
+ )
150
+ await asyncio.sleep(READING_INTERVAL_SECONDS)
@@ -117,3 +117,8 @@ jobs:
117
117
  executor:
118
118
  type: script
119
119
  import_path: example_parse
120
+ services:
121
+ - id: example_scale_connection
122
+ name: Example Scale Connection
123
+ import_path: example_scale_connection
124
+ enabled: true
@@ -5,6 +5,7 @@ import datetime
5
5
  import math
6
6
  import types
7
7
  import typing
8
+ from collections.abc import Mapping
8
9
  from datetime import date
9
10
  from decimal import Decimal
10
11
  from enum import Enum
@@ -140,18 +141,32 @@ def _build_parser_discriminated_union(
140
141
  else discriminator_raw
141
142
  )
142
143
 
144
+ accepted = ", ".join(sorted(discriminator_map))
145
+
143
146
  def parse(value: typing.Any) -> typing.Any:
144
147
  if context.options.allow_direct_type and dataclasses.is_dataclass(value):
145
148
  discriminant = getattr(value, discriminator)
146
- else:
149
+ elif isinstance(value, Mapping):
147
150
  discriminant = value.get(discriminator)
151
+ else:
152
+ raise ParserError(
153
+ f"expected-object-for-union; found {type(value).__name__} where an "
154
+ f"object with {discriminator} set to one of: {accepted} was expected",
155
+ value=value,
156
+ )
148
157
  if discriminant is None:
149
- raise ParserError("missing-union-discriminant")
158
+ raise ParserError(
159
+ f"missing-union-discriminant; set {discriminator} to one of: {accepted}"
160
+ )
150
161
  if not isinstance(discriminant, str):
151
162
  raise ParserError("union-discriminant-is-not-string", value=discriminant)
152
163
  parser = discriminator_map.get(discriminant)
153
164
  if parser is None:
154
- raise ParserError("missing-type-for-union-discriminant", value=discriminant)
165
+ raise ParserError(
166
+ f"missing-type-for-union-discriminant; {discriminator} must be one of: "
167
+ f"{accepted}",
168
+ value=discriminant,
169
+ )
155
170
  return parser(value)
156
171
 
157
172
  return parse
@@ -2,8 +2,6 @@ NON_DISCRIMINATED_UNION_EXCEPTIONS = [
2
2
  "audit_log.AuditLogDataValues",
3
3
  "generate_tool_parameters.UnionWithoutDiscrim",
4
4
  "output_calculation_entities.ConditionParameterFilterCondition",
5
- "output_parameters.AnalyticalMethodParameterOptions",
6
- "output_parameters.AnalyticalMethodLinkedOptionValue",
7
5
  "recipes_redirect.RecipesRedirectResult",
8
6
  "value_spec.ResolvedPathAll",
9
7
  "deprecated_calculation_types.DeprecatedWeightedSumEntitiesV0",
@@ -21,7 +21,7 @@ def load_profiles() -> list[job_definition_t.ProfileMetadata]:
21
21
  if entry.is_dir() and entry.name not in _IGNORED_PROFILE_FOLDERS
22
22
  ]
23
23
  profile_details: list[job_definition_t.ProfileMetadata] = []
24
- seen_job_ids: set[str] = set()
24
+ seen_ids: set[str] = set()
25
25
  for profile_file in profiles:
26
26
  profile_name = profile_file.name
27
27
  try:
@@ -30,9 +30,14 @@ def load_profiles() -> list[job_definition_t.ProfileMetadata]:
30
30
  resource="profile.yaml",
31
31
  )
32
32
  for job in definition.jobs:
33
- if job.id in seen_job_ids:
34
- raise Exception(f"multiple jobs with id {job.id}")
35
- seen_job_ids.add(job.id)
33
+ if job.id in seen_ids:
34
+ raise Exception(f"multiple jobs or services with id {job.id}")
35
+ seen_ids.add(job.id)
36
+ services = definition.services if definition.services is not None else []
37
+ for service in services:
38
+ if service.id in seen_ids:
39
+ raise Exception(f"multiple jobs or services with id {service.id}")
40
+ seen_ids.add(service.id)
36
41
 
37
42
  if definition.environments is not None:
38
43
  for integration_env in integration_envs:
@@ -42,6 +47,7 @@ def load_profiles() -> list[job_definition_t.ProfileMetadata]:
42
47
  job_definition_t.ProfileMetadata(
43
48
  name=profile_name,
44
49
  jobs=definition.jobs,
50
+ services=services,
45
51
  base_url=environment_config.base_url,
46
52
  integration_server_base_url=environment_config.integration_server_base_url,
47
53
  app_base_url=environment_config.app_base_url,
@@ -58,6 +64,7 @@ def load_profiles() -> list[job_definition_t.ProfileMetadata]:
58
64
  job_definition_t.ProfileMetadata(
59
65
  name=profile_name,
60
66
  jobs=definition.jobs,
67
+ services=services,
61
68
  base_url=definition.base_url,
62
69
  integration_server_base_url=definition.integration_server_base_url,
63
70
  app_base_url=definition.app_base_url,
@@ -19,6 +19,12 @@ from uncountable.integration.queue_runner.command_server import (
19
19
  )
20
20
  from uncountable.integration.queue_runner.queue_runner import start_queue_runner
21
21
  from uncountable.integration.queue_runner.types import RESTART_EXIT_CODE
22
+ from uncountable.integration.scan_profiles import load_profiles
23
+ from uncountable.integration.service_runner import (
24
+ ServiceToStart,
25
+ run_service,
26
+ select_enabled_services,
27
+ )
22
28
  from uncountable.integration.telemetry import Logger
23
29
 
24
30
  SHUTDOWN_TIMEOUT_SECS = 30
@@ -32,9 +38,30 @@ class ProcessName(StrEnum):
32
38
  UWSGI = "uwsgi"
33
39
 
34
40
 
41
+ @dataclass(frozen=True, kw_only=True)
42
+ class CoreProcessKey:
43
+ name: ProcessName
44
+
45
+ @property
46
+ def label(self) -> str:
47
+ return self.name
48
+
49
+
50
+ @dataclass(frozen=True, kw_only=True)
51
+ class ServiceProcessKey:
52
+ service_id: str
53
+
54
+ @property
55
+ def label(self) -> str:
56
+ return f"service:{self.service_id}"
57
+
58
+
59
+ ProcessKey = CoreProcessKey | ServiceProcessKey
60
+
61
+
35
62
  @dataclass(kw_only=True)
36
63
  class ProcessInfo:
37
- name: ProcessName
64
+ key: ProcessKey
38
65
  process: AnyProcess
39
66
 
40
67
  @property
@@ -77,16 +104,17 @@ def _wait_for_process(
77
104
  start = time.time()
78
105
  while time.time() - start < timeout_secs:
79
106
  if not proc_info.is_alive:
80
- logger.log_debug(f"{proc_info.name} shut down successfully")
107
+ logger.log_debug(f"{proc_info.key.label} shut down successfully")
81
108
  return True
82
109
  time.sleep(1)
83
110
  return False
84
111
 
85
112
 
86
- def handle_shutdown(logger: Logger, processes: dict[ProcessName, ProcessInfo]) -> None:
113
+ def handle_shutdown(logger: Logger, processes: dict[ProcessKey, ProcessInfo]) -> None:
87
114
  logger.log_debug("received shutdown command, shutting down sub-processes")
88
115
 
89
- cron = processes.get(ProcessName.CRON_SERVER)
116
+ cron_key = CoreProcessKey(name=ProcessName.CRON_SERVER)
117
+ cron = processes.get(cron_key)
90
118
  if cron is not None and cron.is_alive:
91
119
  logger.log_debug("stopping cron_server first to prevent new job submissions")
92
120
  cron.process.terminate()
@@ -94,7 +122,7 @@ def handle_shutdown(logger: Logger, processes: dict[ProcessName, ProcessInfo]) -
94
122
  logger.log_warning("cron_server did not stop in time, killing")
95
123
  cron.process.kill()
96
124
 
97
- remaining = [p for name, p in processes.items() if name != ProcessName.CRON_SERVER]
125
+ remaining = [p for key, p in processes.items() if key != cron_key]
98
126
  for proc_info in remaining:
99
127
  if proc_info.is_alive:
100
128
  proc_info.process.terminate()
@@ -106,70 +134,62 @@ def handle_shutdown(logger: Logger, processes: dict[ProcessName, ProcessInfo]) -
106
134
  ):
107
135
  logger.log_debug(
108
136
  "waiting for sub-processes to shut down",
109
- attributes={"still_living_processes": [p.name for p in still_living]},
137
+ attributes={"still_living_processes": [p.key.label for p in still_living]},
110
138
  )
111
139
  still_living = [p for p in still_living if p.is_alive]
112
140
  time.sleep(1)
113
141
 
114
142
  for proc_info in still_living:
115
143
  logger.log_warning(
116
- f"{proc_info.name} failed to shut down after {SHUTDOWN_TIMEOUT_SECS} seconds, forcefully terminating"
144
+ f"{proc_info.key.label} failed to shut down after {SHUTDOWN_TIMEOUT_SECS} seconds, forcefully terminating"
117
145
  )
118
146
  proc_info.process.kill()
119
147
 
120
148
 
121
- def restart_process(
122
- logger: Logger, proc_info: ProcessInfo, processes: dict[ProcessName, ProcessInfo]
123
- ) -> None:
124
- logger.log_error(
125
- f"process {proc_info.name} shut down unexpectedly - exit code {proc_info.exitcode}. Restarting..."
126
- )
127
-
128
- match proc_info.name:
129
- case ProcessName.QUEUE_RUNNER:
130
- queue_proc = multiprocessing.Process(target=start_queue_runner)
131
- queue_proc.start()
132
- new_info = ProcessInfo(name=ProcessName.QUEUE_RUNNER, process=queue_proc)
133
- processes[ProcessName.QUEUE_RUNNER] = new_info
134
- try:
135
- _wait_queue_runner_online()
136
- logger.log_debug("queue runner restarted successfully")
137
- except Exception as e:
138
- logger.log_exception(e)
139
- logger.log_error(
140
- "queue runner failed to restart, shutting down scheduler"
141
- )
142
- handle_shutdown(logger, processes)
143
- sys.exit(1)
149
+ class DeadProcessOutcome(StrEnum):
150
+ RESTART_REQUESTED = "restart_requested"
151
+ RESTART_AFTER_CRASH = "restart_after_crash"
152
+ SHUTDOWN_ALL = "shutdown_all"
144
153
 
145
- case ProcessName.CRON_SERVER:
146
- cron_proc = multiprocessing.Process(target=cron_target)
147
- cron_proc.start()
148
- new_info = ProcessInfo(name=ProcessName.CRON_SERVER, process=cron_proc)
149
- processes[ProcessName.CRON_SERVER] = new_info
150
- logger.log_debug("cron server restarted successfully")
151
154
 
152
- case ProcessName.UWSGI:
153
- uwsgi_proc: AnyProcess = subprocess.Popen(["uwsgi", "--die-on-term"])
154
- new_info = ProcessInfo(name=ProcessName.UWSGI, process=uwsgi_proc)
155
- processes[ProcessName.UWSGI] = new_info
156
- logger.log_debug("uwsgi restarted successfully")
155
+ def classify_dead_process(key: ProcessKey, exitcode: int | None) -> DeadProcessOutcome:
156
+ if exitcode == RESTART_EXIT_CODE:
157
+ return DeadProcessOutcome.RESTART_REQUESTED
158
+ match key:
159
+ case ServiceProcessKey():
160
+ return DeadProcessOutcome.RESTART_AFTER_CRASH
161
+ case CoreProcessKey():
162
+ return DeadProcessOutcome.SHUTDOWN_ALL
163
+ case _:
164
+ assert_never(key)
157
165
 
158
166
 
159
167
  def check_process_alarms(
160
- logger: Logger, processes: dict[ProcessName, ProcessInfo]
168
+ logger: Logger, processes: dict[ProcessKey, ProcessInfo]
161
169
  ) -> ProcessAlarm | None:
162
170
  for proc_info in processes.values():
163
- if not proc_info.is_alive:
164
- if proc_info.exitcode == RESTART_EXIT_CODE:
171
+ if proc_info.is_alive:
172
+ continue
173
+ outcome = classify_dead_process(proc_info.key, proc_info.exitcode)
174
+ match outcome:
175
+ case DeadProcessOutcome.RESTART_REQUESTED:
165
176
  logger.log_warning(
166
- f"process {proc_info.name} requested restart! restarting"
177
+ f"process {proc_info.key.label} requested restart! restarting"
167
178
  )
168
- return ProcessAlarmRestart(process=proc_info)
169
- logger.log_error(
170
- f"process {proc_info.name} shut down unexpectedly! shutting down scheduler; exit code is {proc_info.exitcode}"
171
- )
172
- return ProcessAlarmShutdownAll()
179
+ case DeadProcessOutcome.RESTART_AFTER_CRASH:
180
+ logger.log_error(
181
+ f"process {proc_info.key.label} exited unexpectedly with exit "
182
+ f"code {proc_info.exitcode}; cleaning up and restarting"
183
+ )
184
+ case DeadProcessOutcome.SHUTDOWN_ALL:
185
+ logger.log_error(
186
+ f"process {proc_info.key.label} shut down unexpectedly! shutting "
187
+ f"down scheduler; exit code is {proc_info.exitcode}"
188
+ )
189
+ return ProcessAlarmShutdownAll()
190
+ case _:
191
+ assert_never(outcome)
192
+ return ProcessAlarmRestart(process=proc_info)
173
193
  return None
174
194
 
175
195
 
@@ -194,20 +214,20 @@ def _wait_queue_runner_online() -> None:
194
214
 
195
215
  def main() -> None:
196
216
  logger = Logger(get_current_span())
197
- processes: dict[ProcessName, ProcessInfo] = {}
217
+ processes: dict[ProcessKey, ProcessInfo] = {}
198
218
 
199
219
  multiprocessing.set_start_method("forkserver")
200
220
 
201
221
  def add_process(process: ProcessInfo) -> None:
202
- processes[process.name] = process
203
- logger.log_debug(f"started process {process.name}")
222
+ processes[process.key] = process
223
+ logger.log_debug(f"started process {process.key.label}")
204
224
 
205
225
  def _start_queue_runner() -> None:
206
226
  runner_process = multiprocessing.Process(target=start_queue_runner)
207
227
  runner_process.start()
208
228
  add_process(
209
229
  ProcessInfo(
210
- name=ProcessName.QUEUE_RUNNER,
230
+ key=CoreProcessKey(name=ProcessName.QUEUE_RUNNER),
211
231
  process=runner_process,
212
232
  )
213
233
  )
@@ -219,17 +239,46 @@ def main() -> None:
219
239
  handle_shutdown(logger, processes=processes)
220
240
  return
221
241
 
242
+ def _start_service(service_to_start: ServiceToStart) -> None:
243
+ service_process = multiprocessing.Process(
244
+ target=run_service,
245
+ kwargs={
246
+ "service": service_to_start.service,
247
+ "profile_metadata": service_to_start.profile_metadata,
248
+ },
249
+ )
250
+ service_process.start()
251
+ add_process(
252
+ ProcessInfo(
253
+ key=ServiceProcessKey(service_id=service_to_start.service.id),
254
+ process=service_process,
255
+ )
256
+ )
257
+
222
258
  _start_queue_runner()
223
259
 
224
260
  cron_process = multiprocessing.Process(target=cron_target)
225
261
  cron_process.start()
226
- add_process(ProcessInfo(name=ProcessName.CRON_SERVER, process=cron_process))
262
+ add_process(
263
+ ProcessInfo(
264
+ key=CoreProcessKey(name=ProcessName.CRON_SERVER), process=cron_process
265
+ )
266
+ )
227
267
 
228
268
  uwsgi_process = subprocess.Popen([
229
269
  "uwsgi",
230
270
  "--die-on-term",
231
271
  ])
232
- add_process(ProcessInfo(name=ProcessName.UWSGI, process=uwsgi_process))
272
+ add_process(
273
+ ProcessInfo(key=CoreProcessKey(name=ProcessName.UWSGI), process=uwsgi_process)
274
+ )
275
+
276
+ services_by_id: dict[str, ServiceToStart] = {
277
+ service_to_start.service.id: service_to_start
278
+ for service_to_start in select_enabled_services(load_profiles())
279
+ }
280
+ for service_to_start in services_by_id.values():
281
+ _start_service(service_to_start)
233
282
 
234
283
  shutdown_requested = False
235
284
 
@@ -244,16 +293,25 @@ def main() -> None:
244
293
  process_alarm = check_process_alarms(logger, processes=processes)
245
294
  match process_alarm:
246
295
  case ProcessAlarmRestart():
247
- match process_alarm.process.name:
248
- case ProcessName.QUEUE_RUNNER:
249
- del processes[ProcessName.QUEUE_RUNNER]
250
- _start_queue_runner()
251
- case ProcessName.CRON_SERVER | ProcessName.UWSGI:
252
- raise NotImplementedError(
253
- f"restarting {process_alarm.process.name} not yet implemented"
254
- )
296
+ match process_alarm.process.key:
297
+ case CoreProcessKey() as core_key:
298
+ match core_key.name:
299
+ case ProcessName.QUEUE_RUNNER:
300
+ del processes[
301
+ CoreProcessKey(name=ProcessName.QUEUE_RUNNER)
302
+ ]
303
+ _start_queue_runner()
304
+ case ProcessName.CRON_SERVER | ProcessName.UWSGI:
305
+ raise NotImplementedError(
306
+ f"restarting {core_key.label} not yet implemented"
307
+ )
308
+ case _:
309
+ assert_never(core_key.name)
310
+ case ServiceProcessKey() as service_key:
311
+ del processes[service_key]
312
+ _start_service(services_by_id[service_key.service_id])
255
313
  case _:
256
- assert_never(process_alarm.process.name)
314
+ assert_never(process_alarm.process.key)
257
315
  case ProcessAlarmShutdownAll():
258
316
  handle_shutdown(logger, processes)
259
317
  sys.exit(1)
@@ -0,0 +1,74 @@
1
+ import importlib
2
+ import inspect
3
+ import os
4
+ from abc import ABC, abstractmethod
5
+ from dataclasses import dataclass
6
+
7
+ from uncountable.core.client import Client
8
+ from uncountable.integration.telemetry import Logger
9
+ from uncountable.types.job_definition_t import (
10
+ IntegrationService,
11
+ ProfileMetadata,
12
+ )
13
+
14
+ __all__ = [
15
+ "Service",
16
+ "ServiceArguments",
17
+ "register_service",
18
+ "resolve_service",
19
+ "resolve_service_class",
20
+ ]
21
+
22
+
23
+ @dataclass(kw_only=True)
24
+ class ServiceArguments:
25
+ service_definition: IntegrationService
26
+ profile_metadata: ProfileMetadata
27
+ client: Client
28
+ logger: Logger
29
+
30
+
31
+ class Service(ABC):
32
+ _unc_service_registered: bool = False
33
+
34
+ @abstractmethod
35
+ def run(self, args: ServiceArguments) -> None: ...
36
+
37
+
38
+ def register_service[ST: type[Service]](cls: ST) -> ST:
39
+ if not (isinstance(cls, type) and issubclass(cls, Service)):
40
+ raise TypeError(
41
+ f"@register_service can only be applied to Service subclasses, got {cls}"
42
+ )
43
+ cls._unc_service_registered = True
44
+ return cls
45
+
46
+
47
+ def resolve_service_class(
48
+ service: IntegrationService, profile_metadata: ProfileMetadata
49
+ ) -> type[Service]:
50
+ service_module_path = ".".join([
51
+ os.environ["UNC_PROFILES_MODULE"],
52
+ profile_metadata.name,
53
+ service.import_path,
54
+ ])
55
+ service_module = importlib.import_module(service_module_path)
56
+ found_services: list[type[Service]] = []
57
+ for _, service_class in inspect.getmembers(service_module, inspect.isclass):
58
+ if (
59
+ service_class.__module__ == service_module.__name__
60
+ and getattr(service_class, "_unc_service_registered", False)
61
+ and issubclass(service_class, Service)
62
+ ):
63
+ found_services.append(service_class)
64
+ assert len(found_services) == 1, (
65
+ f"expected exactly one registered service class in {service.import_path}, found {len(found_services)}"
66
+ )
67
+ return found_services[0]
68
+
69
+
70
+ def resolve_service(
71
+ service: IntegrationService, profile_metadata: ProfileMetadata
72
+ ) -> Service:
73
+ service_class = resolve_service_class(service, profile_metadata)
74
+ return service_class()