UncountablePythonSDK 0.0.90__tar.gz → 0.0.91__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.

Potentially problematic release.


This version of UncountablePythonSDK might be problematic. Click here for more details.

Files changed (309) hide show
  1. {uncountablepythonsdk-0.0.90/UncountablePythonSDK.egg-info → uncountablepythonsdk-0.0.91}/PKG-INFO +2 -2
  2. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91/UncountablePythonSDK.egg-info}/PKG-INFO +2 -2
  3. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/UncountablePythonSDK.egg-info/SOURCES.txt +7 -0
  4. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/UncountablePythonSDK.egg-info/requires.txt +1 -1
  5. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/requirements.txt +1 -1
  6. uncountablepythonsdk-0.0.91/examples/download_files.py +26 -0
  7. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/argument_parser/argument_parser.py +57 -25
  8. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization/__init__.py +7 -3
  9. uncountablepythonsdk-0.0.91/pkgs/serialization/annotation.py +64 -0
  10. uncountablepythonsdk-0.0.91/pkgs/serialization/serial_alias.py +47 -0
  11. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization/serial_class.py +26 -32
  12. uncountablepythonsdk-0.0.91/pkgs/serialization/serial_generic.py +16 -0
  13. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization/serial_union.py +9 -9
  14. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization_util/__init__.py +4 -0
  15. uncountablepythonsdk-0.0.91/pkgs/serialization_util/dataclasses.py +14 -0
  16. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization_util/serialization_helpers.py +11 -3
  17. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/builder.py +41 -5
  18. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/emit_python.py +34 -6
  19. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/type_info/emit_type_info.py +7 -2
  20. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pyproject.toml +1 -1
  21. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/core/client.py +58 -1
  22. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/core/environment.py +2 -2
  23. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/scheduler.py +4 -4
  24. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/__init__.py +2 -0
  25. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/chemical/convert_chemical_formats.py +7 -1
  26. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/transition_entity_phase.py +7 -1
  27. uncountablepythonsdk-0.0.91/uncountable/types/api/files/download_file.py +77 -0
  28. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/permissions/set_core_permissions.py +7 -1
  29. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/set_recipe_tags.py +7 -1
  30. uncountablepythonsdk-0.0.91/uncountable/types/api/uploader/__init__.py +1 -0
  31. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/entity_t.py +13 -2
  32. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/id_source_t.py +7 -1
  33. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/identifier_t.py +7 -1
  34. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/overrides_t.py +7 -1
  35. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_identifiers_t.py +13 -2
  36. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/.github/workflows/documentation.yml +0 -0
  37. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/.github/workflows/publish.yml +0 -0
  38. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/.gitignore +0 -0
  39. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/README.md +0 -0
  40. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/UncountablePythonSDK.egg-info/dependency_links.txt +0 -0
  41. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/UncountablePythonSDK.egg-info/top_level.txt +0 -0
  42. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/.gitignore +0 -0
  43. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/conf.py +0 -0
  44. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/index.md +0 -0
  45. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/justfile +0 -0
  46. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/quickstart.md +0 -0
  47. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/android-chrome-192x192.png +0 -0
  48. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/android-chrome-512x512.png +0 -0
  49. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/apple-touch-icon.png +0 -0
  50. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/browserconfig.xml +0 -0
  51. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/favicon-16x16.png +0 -0
  52. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/favicon-32x32.png +0 -0
  53. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/manifest.json +0 -0
  54. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/mstile-150x150.png +0 -0
  55. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/favicons/safari-pinned-tab.svg +0 -0
  56. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/docs/static/logo_blue.png +0 -0
  57. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/async_batch.py +0 -0
  58. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/create_entity.py +0 -0
  59. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/edit_recipe_inputs.py +0 -0
  60. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/integration-server/jobs/materials_auto/example_cron.py +0 -0
  61. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/integration-server/jobs/materials_auto/example_wh.py +0 -0
  62. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/integration-server/jobs/materials_auto/profile.yaml +0 -0
  63. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/integration-server/pyproject.toml +0 -0
  64. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/invoke_uploader.py +0 -0
  65. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/set_recipe_metadata_file.py +0 -0
  66. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/set_recipe_output_file_sdk.py +0 -0
  67. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/examples/upload_files.py +0 -0
  68. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/__init__.py +0 -0
  69. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/argument_parser/__init__.py +0 -0
  70. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/argument_parser/_is_enum.py +0 -0
  71. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/argument_parser/_is_namedtuple.py +0 -0
  72. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/argument_parser/case_convert.py +0 -0
  73. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/__init__.py +0 -0
  74. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/_blob_session.py +0 -0
  75. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/_gdrive_session.py +0 -0
  76. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/_local_session.py +0 -0
  77. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/_s3_session.py +0 -0
  78. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/_sftp_session.py +0 -0
  79. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/file_type_utils.py +0 -0
  80. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/filesystem_utils/filesystem_session.py +0 -0
  81. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/py.typed +0 -0
  82. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization/missing_sentry.py +0 -0
  83. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization/opaque_key.py +0 -0
  84. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization/yaml.py +0 -0
  85. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization_util/_get_type_for_serialization.py +0 -0
  86. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/serialization_util/convert_to_snakecase.py +0 -0
  87. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/strenum_compat/__init__.py +0 -0
  88. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/strenum_compat/strenum_compat.py +0 -0
  89. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/__init__.py +0 -0
  90. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/__main__.py +0 -0
  91. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/actions_registry/__init__.py +0 -0
  92. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/actions_registry/__main__.py +0 -0
  93. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/actions_registry/emit_typescript.py +0 -0
  94. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/config.py +0 -0
  95. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/emit_io_ts.py +0 -0
  96. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/emit_open_api.py +0 -0
  97. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/emit_open_api_util.py +0 -0
  98. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/emit_typescript.py +0 -0
  99. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/emit_typescript_util.py +0 -0
  100. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/load_types.py +0 -0
  101. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/open_api_util.py +0 -0
  102. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/parts/base.py.prepart +0 -0
  103. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/parts/base.ts.prepart +0 -0
  104. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/test.py +0 -0
  105. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/type_info/__main__.py +0 -0
  106. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/util.py +0 -0
  107. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/value_spec/__init__.py +0 -0
  108. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/value_spec/__main__.py +0 -0
  109. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/value_spec/convert_type.py +0 -0
  110. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/value_spec/emit_python.py +0 -0
  111. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/pkgs/type_spec/value_spec/types.py +0 -0
  112. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/setup.cfg +0 -0
  113. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/__init__.py +0 -0
  114. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/core/__init__.py +0 -0
  115. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/core/async_batch.py +0 -0
  116. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/core/file_upload.py +0 -0
  117. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/core/types.py +0 -0
  118. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/__init__.py +0 -0
  119. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/cli.py +0 -0
  120. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/construct_client.py +0 -0
  121. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/cron.py +0 -0
  122. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/db/__init__.py +0 -0
  123. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/db/connect.py +0 -0
  124. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/db/session.py +0 -0
  125. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/entrypoint.py +0 -0
  126. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/executors/__init__.py +0 -0
  127. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/executors/executors.py +0 -0
  128. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/executors/generic_upload_executor.py +0 -0
  129. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/executors/script_executor.py +0 -0
  130. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/job.py +0 -0
  131. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/__init__.py +0 -0
  132. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/__init__.py +0 -0
  133. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/command_client.py +0 -0
  134. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/command_server.py +0 -0
  135. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/protocol/__init__.py +0 -0
  136. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/protocol/command_server.proto +0 -0
  137. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.py +0 -0
  138. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/protocol/command_server_pb2.pyi +0 -0
  139. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/protocol/command_server_pb2_grpc.py +0 -0
  140. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/command_server/types.py +0 -0
  141. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/datastore/__init__.py +0 -0
  142. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/datastore/datastore_sqlite.py +0 -0
  143. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/datastore/interface.py +0 -0
  144. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/datastore/model.py +0 -0
  145. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/job_scheduler.py +0 -0
  146. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/queue_runner.py +0 -0
  147. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/types.py +0 -0
  148. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/queue_runner/worker.py +0 -0
  149. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/scan_profiles.py +0 -0
  150. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/secret_retrieval/__init__.py +0 -0
  151. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/secret_retrieval/retrieve_secret.py +0 -0
  152. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/server.py +0 -0
  153. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/telemetry.py +0 -0
  154. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/integration/webhook_server/entrypoint.py +0 -0
  155. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/py.typed +0 -0
  156. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/__init__.py +0 -0
  157. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/batch/__init__.py +0 -0
  158. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/batch/execute_batch.py +0 -0
  159. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/batch/execute_batch_load_async.py +0 -0
  160. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/chemical/__init__.py +0 -0
  161. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/__init__.py +0 -0
  162. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/create_entities.py +0 -0
  163. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/create_entity.py +0 -0
  164. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/get_entities_data.py +0 -0
  165. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/grant_entity_permissions.py +0 -0
  166. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/list_entities.py +0 -0
  167. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/lock_entity.py +0 -0
  168. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/resolve_entity_ids.py +0 -0
  169. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/set_entity_field_values.py +0 -0
  170. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/set_values.py +0 -0
  171. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/entity/unlock_entity.py +0 -0
  172. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/equipment/__init__.py +0 -0
  173. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/equipment/associate_equipment_input.py +0 -0
  174. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/field_options/__init__.py +0 -0
  175. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/field_options/upsert_field_options.py +0 -0
  176. {uncountablepythonsdk-0.0.90/uncountable/types/api/id_source → uncountablepythonsdk-0.0.91/uncountable/types/api/files}/__init__.py +0 -0
  177. {uncountablepythonsdk-0.0.90/uncountable/types/api/input_groups → uncountablepythonsdk-0.0.91/uncountable/types/api/id_source}/__init__.py +0 -0
  178. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/id_source/list_id_source.py +0 -0
  179. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/id_source/match_id_source.py +0 -0
  180. {uncountablepythonsdk-0.0.90/uncountable/types/api/inputs → uncountablepythonsdk-0.0.91/uncountable/types/api/input_groups}/__init__.py +0 -0
  181. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/input_groups/get_input_group_names.py +0 -0
  182. {uncountablepythonsdk-0.0.90/uncountable/types/api/material_families → uncountablepythonsdk-0.0.91/uncountable/types/api/inputs}/__init__.py +0 -0
  183. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/create_inputs.py +0 -0
  184. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/get_input_data.py +0 -0
  185. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/get_input_names.py +0 -0
  186. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/get_inputs_data.py +0 -0
  187. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/set_input_attribute_values.py +0 -0
  188. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/set_input_category.py +0 -0
  189. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/set_input_subcategories.py +0 -0
  190. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/inputs/set_intermediate_type.py +0 -0
  191. {uncountablepythonsdk-0.0.90/uncountable/types/api/outputs → uncountablepythonsdk-0.0.91/uncountable/types/api/material_families}/__init__.py +0 -0
  192. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/material_families/update_entity_material_families.py +0 -0
  193. {uncountablepythonsdk-0.0.90/uncountable/types/api/permissions → uncountablepythonsdk-0.0.91/uncountable/types/api/outputs}/__init__.py +0 -0
  194. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/outputs/get_output_data.py +0 -0
  195. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/outputs/get_output_names.py +0 -0
  196. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/outputs/resolve_output_conditions.py +0 -0
  197. {uncountablepythonsdk-0.0.90/uncountable/types/api/project → uncountablepythonsdk-0.0.91/uncountable/types/api/permissions}/__init__.py +0 -0
  198. {uncountablepythonsdk-0.0.90/uncountable/types/api/recipe_links → uncountablepythonsdk-0.0.91/uncountable/types/api/project}/__init__.py +0 -0
  199. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/project/get_projects.py +0 -0
  200. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/project/get_projects_data.py +0 -0
  201. {uncountablepythonsdk-0.0.90/uncountable/types/api/recipe_metadata → uncountablepythonsdk-0.0.91/uncountable/types/api/recipe_links}/__init__.py +0 -0
  202. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipe_links/create_recipe_link.py +0 -0
  203. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipe_links/remove_recipe_link.py +0 -0
  204. {uncountablepythonsdk-0.0.90/uncountable/types/api/recipes → uncountablepythonsdk-0.0.91/uncountable/types/api/recipe_metadata}/__init__.py +0 -0
  205. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipe_metadata/get_recipe_metadata_data.py +0 -0
  206. {uncountablepythonsdk-0.0.90/uncountable/types/api/triggers → uncountablepythonsdk-0.0.91/uncountable/types/api/recipes}/__init__.py +0 -0
  207. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/add_recipe_to_project.py +0 -0
  208. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/archive_recipes.py +0 -0
  209. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/associate_recipe_as_input.py +0 -0
  210. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/associate_recipe_as_lot.py +0 -0
  211. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/clear_recipe_outputs.py +0 -0
  212. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/create_recipe.py +0 -0
  213. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/create_recipes.py +0 -0
  214. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/disassociate_recipe_as_input.py +0 -0
  215. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/edit_recipe_inputs.py +0 -0
  216. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_column_calculation_values.py +0 -0
  217. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_curve.py +0 -0
  218. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_recipe_calculations.py +0 -0
  219. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_recipe_links.py +0 -0
  220. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_recipe_names.py +0 -0
  221. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_recipe_output_metadata.py +0 -0
  222. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/get_recipes_data.py +0 -0
  223. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/lock_recipes.py +0 -0
  224. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/remove_recipe_from_project.py +0 -0
  225. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/set_recipe_inputs.py +0 -0
  226. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/set_recipe_metadata.py +0 -0
  227. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/set_recipe_output_annotations.py +0 -0
  228. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/set_recipe_output_file.py +0 -0
  229. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/set_recipe_outputs.py +0 -0
  230. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/unarchive_recipes.py +0 -0
  231. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/recipes/unlock_recipes.py +0 -0
  232. {uncountablepythonsdk-0.0.90/uncountable/types/api/uploader → uncountablepythonsdk-0.0.91/uncountable/types/api/triggers}/__init__.py +0 -0
  233. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/triggers/run_trigger.py +0 -0
  234. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/api/uploader/invoke_uploader.py +0 -0
  235. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/async_batch.py +0 -0
  236. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/async_batch_processor.py +0 -0
  237. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/async_batch_t.py +0 -0
  238. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/async_jobs.py +0 -0
  239. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/async_jobs_t.py +0 -0
  240. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/auth_retrieval.py +0 -0
  241. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/auth_retrieval_t.py +0 -0
  242. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/base.py +0 -0
  243. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/base_t.py +0 -0
  244. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/calculations.py +0 -0
  245. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/calculations_t.py +0 -0
  246. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/chemical_structure.py +0 -0
  247. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/chemical_structure_t.py +0 -0
  248. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/client_base.py +0 -0
  249. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/client_config.py +0 -0
  250. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/client_config_t.py +0 -0
  251. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/curves.py +0 -0
  252. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/curves_t.py +0 -0
  253. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/entity.py +0 -0
  254. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/experiment_groups.py +0 -0
  255. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/experiment_groups_t.py +0 -0
  256. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/field_values.py +0 -0
  257. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/field_values_t.py +0 -0
  258. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/fields.py +0 -0
  259. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/fields_t.py +0 -0
  260. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/generic_upload.py +0 -0
  261. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/generic_upload_t.py +0 -0
  262. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/id_source.py +0 -0
  263. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/identifier.py +0 -0
  264. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/input_attributes.py +0 -0
  265. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/input_attributes_t.py +0 -0
  266. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/inputs.py +0 -0
  267. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/inputs_t.py +0 -0
  268. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/integration_server.py +0 -0
  269. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/integration_server_t.py +0 -0
  270. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/job_definition.py +0 -0
  271. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/job_definition_t.py +0 -0
  272. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/outputs.py +0 -0
  273. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/outputs_t.py +0 -0
  274. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/overrides.py +0 -0
  275. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/permissions.py +0 -0
  276. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/permissions_t.py +0 -0
  277. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/phases.py +0 -0
  278. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/phases_t.py +0 -0
  279. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/post_base.py +0 -0
  280. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/post_base_t.py +0 -0
  281. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/queued_job.py +0 -0
  282. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/queued_job_t.py +0 -0
  283. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_identifiers.py +0 -0
  284. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_inputs.py +0 -0
  285. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_inputs_t.py +0 -0
  286. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_links.py +0 -0
  287. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_links_t.py +0 -0
  288. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_metadata.py +0 -0
  289. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_metadata_t.py +0 -0
  290. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_output_metadata.py +0 -0
  291. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_output_metadata_t.py +0 -0
  292. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_tags.py +0 -0
  293. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_tags_t.py +0 -0
  294. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_workflow_steps.py +0 -0
  295. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipe_workflow_steps_t.py +0 -0
  296. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipes.py +0 -0
  297. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/recipes_t.py +0 -0
  298. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/response.py +0 -0
  299. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/response_t.py +0 -0
  300. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/secret_retrieval.py +0 -0
  301. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/secret_retrieval_t.py +0 -0
  302. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/units.py +0 -0
  303. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/units_t.py +0 -0
  304. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/users.py +0 -0
  305. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/users_t.py +0 -0
  306. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/webhook_job.py +0 -0
  307. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/webhook_job_t.py +0 -0
  308. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/workflows.py +0 -0
  309. {uncountablepythonsdk-0.0.90 → uncountablepythonsdk-0.0.91}/uncountable/types/workflows_t.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.90
3
+ Version: 0.0.91
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
@@ -43,7 +43,7 @@ Requires-Dist: mypy==1.*; extra == "test"
43
43
  Requires-Dist: ruff==0.*; extra == "test"
44
44
  Requires-Dist: pytest==8.*; extra == "test"
45
45
  Requires-Dist: coverage[toml]==7.*; extra == "test"
46
- Requires-Dist: pytest-cov==5.*; extra == "test"
46
+ Requires-Dist: pytest-cov==6.*; extra == "test"
47
47
  Requires-Dist: pytest-xdist==3.*; extra == "test"
48
48
 
49
49
  # Uncountable Python SDK
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: UncountablePythonSDK
3
- Version: 0.0.90
3
+ Version: 0.0.91
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
@@ -43,7 +43,7 @@ Requires-Dist: mypy==1.*; extra == "test"
43
43
  Requires-Dist: ruff==0.*; extra == "test"
44
44
  Requires-Dist: pytest==8.*; extra == "test"
45
45
  Requires-Dist: coverage[toml]==7.*; extra == "test"
46
- Requires-Dist: pytest-cov==5.*; extra == "test"
46
+ Requires-Dist: pytest-cov==6.*; extra == "test"
47
47
  Requires-Dist: pytest-xdist==3.*; extra == "test"
48
48
 
49
49
  # Uncountable Python SDK
@@ -26,6 +26,7 @@ docs/static/favicons/mstile-150x150.png
26
26
  docs/static/favicons/safari-pinned-tab.svg
27
27
  examples/async_batch.py
28
28
  examples/create_entity.py
29
+ examples/download_files.py
29
30
  examples/edit_recipe_inputs.py
30
31
  examples/invoke_uploader.py
31
32
  examples/set_recipe_metadata_file.py
@@ -51,14 +52,18 @@ pkgs/filesystem_utils/_sftp_session.py
51
52
  pkgs/filesystem_utils/file_type_utils.py
52
53
  pkgs/filesystem_utils/filesystem_session.py
53
54
  pkgs/serialization/__init__.py
55
+ pkgs/serialization/annotation.py
54
56
  pkgs/serialization/missing_sentry.py
55
57
  pkgs/serialization/opaque_key.py
58
+ pkgs/serialization/serial_alias.py
56
59
  pkgs/serialization/serial_class.py
60
+ pkgs/serialization/serial_generic.py
57
61
  pkgs/serialization/serial_union.py
58
62
  pkgs/serialization/yaml.py
59
63
  pkgs/serialization_util/__init__.py
60
64
  pkgs/serialization_util/_get_type_for_serialization.py
61
65
  pkgs/serialization_util/convert_to_snakecase.py
66
+ pkgs/serialization_util/dataclasses.py
62
67
  pkgs/serialization_util/serialization_helpers.py
63
68
  pkgs/strenum_compat/__init__.py
64
69
  pkgs/strenum_compat/strenum_compat.py
@@ -237,6 +242,8 @@ uncountable/types/api/equipment/__init__.py
237
242
  uncountable/types/api/equipment/associate_equipment_input.py
238
243
  uncountable/types/api/field_options/__init__.py
239
244
  uncountable/types/api/field_options/upsert_field_options.py
245
+ uncountable/types/api/files/__init__.py
246
+ uncountable/types/api/files/download_file.py
240
247
  uncountable/types/api/id_source/__init__.py
241
248
  uncountable/types/api/id_source/list_id_source.py
242
249
  uncountable/types/api/id_source/match_id_source.py
@@ -26,5 +26,5 @@ mypy==1.*
26
26
  ruff==0.*
27
27
  pytest==8.*
28
28
  coverage[toml]==7.*
29
- pytest-cov==5.*
29
+ pytest-cov==6.*
30
30
  pytest-xdist==3.*
@@ -1,6 +1,6 @@
1
1
  furo==2024.8.6
2
2
  myst-parser==4.0.0
3
- sphinx-autoapi==3.3.0
3
+ sphinx-autoapi==3.4.0
4
4
  sphinx-copybutton==0.5.2
5
5
  Sphinx==8.1.3
6
6
  sphinx_design==0.6.1
@@ -0,0 +1,26 @@
1
+ import os
2
+ from pprint import pprint
3
+
4
+ from uncountable.core import AuthDetailsApiKey, Client
5
+ from uncountable.types import download_file_t, entity_t, identifier_t
6
+
7
+ client = Client(
8
+ base_url="http://localhost:5000",
9
+ auth_details=AuthDetailsApiKey(
10
+ api_id=os.environ["UNC_API_ID"],
11
+ api_secret_key=os.environ["UNC_API_SECRET_KEY"],
12
+ ),
13
+ )
14
+
15
+ file_query = download_file_t.FileDownloadQueryEntityField(
16
+ entity=entity_t.EntityIdentifier(
17
+ type=entity_t.EntityType.LAB_REQUEST,
18
+ identifier_key=identifier_t.IdentifierKeyId(id=2375),
19
+ ),
20
+ field_key=identifier_t.IdentifierKeyRefName(ref_name="attachments"),
21
+ )
22
+
23
+ downloaded = client.download_files(
24
+ file_query=file_query,
25
+ )
26
+ pprint(downloaded)
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import dataclasses
2
4
  import math
3
5
  import types
@@ -6,6 +8,7 @@ from collections import defaultdict
6
8
  from dataclasses import MISSING, dataclass
7
9
  from datetime import date, datetime
8
10
  from decimal import Decimal
11
+ from enum import Enum, auto
9
12
  from importlib import resources
10
13
 
11
14
  import dateutil.parser
@@ -27,11 +30,33 @@ ParserFunction = typing.Callable[[typing.Any], T]
27
30
  ParserCache = dict[type[typing.Any], ParserFunction[typing.Any]]
28
31
 
29
32
 
33
+ class SourceEncoding(Enum):
34
+ API = auto()
35
+ STORAGE = auto()
36
+
37
+
30
38
  @dataclass(frozen=True, eq=True)
31
39
  class ParserOptions:
32
- convert_to_snake_case: bool
40
+ encoding: SourceEncoding
33
41
  strict_property_parsing: bool = False
34
42
 
43
+ @staticmethod
44
+ def Api(*, strict_property_parsing: bool = False) -> ParserOptions:
45
+ return ParserOptions(
46
+ encoding=SourceEncoding.API, strict_property_parsing=strict_property_parsing
47
+ )
48
+
49
+ @staticmethod
50
+ def Storage(*, strict_property_parsing: bool = False) -> ParserOptions:
51
+ return ParserOptions(
52
+ encoding=SourceEncoding.STORAGE,
53
+ strict_property_parsing=strict_property_parsing,
54
+ )
55
+
56
+ @property
57
+ def from_camel_case(self) -> bool:
58
+ return self.encoding == SourceEncoding.API
59
+
35
60
 
36
61
  @dataclass(frozen=True)
37
62
  class ParserContext:
@@ -138,20 +163,10 @@ def _build_parser_discriminated_union(
138
163
  def _build_parser_inner(
139
164
  parsed_type: type[T],
140
165
  context: ParserContext,
141
- *,
142
- convert_string_to_snake_case: bool = False,
143
166
  ) -> ParserFunction[T]:
144
167
  """
145
- convert_to_snake_case - internal flag
146
- if convert_to_snake_case is True, and parsed_type is str,
147
- then the generated parser will convert camel to snake case case
148
- should only be True for cases like dictionary keys
149
- should only be True if options.convert_to_snake_case is True
150
-
151
- NOTE: This argument makes caching at this level difficult, as the cache-map
152
- would need to vary based on this argument. For this reason only dataclasses
153
- are cached now, as they don't use the argument, and they're known to be safe.
154
- This is also enough to support some recursion.
168
+ IMPROVE: We can now cache at this level, to avoid producing redundant
169
+ internal parsers.
155
170
  """
156
171
 
157
172
  serial_union = get_serial_union_data(parsed_type)
@@ -184,7 +199,7 @@ def _build_parser_inner(
184
199
  field_name: field_parser(
185
200
  value.get(
186
201
  snake_to_camel_case(field_name)
187
- if context.options.convert_to_snake_case
202
+ if context.options.from_camel_case
188
203
  else field_name
189
204
  )
190
205
  )
@@ -245,23 +260,32 @@ def _build_parser_inner(
245
260
  args = typing.get_args(parsed_type)
246
261
  if len(args) != 2:
247
262
  raise ValueError("Dict types only support two arguments for now")
248
- k_parser = _build_parser_inner(
263
+ k_inner_parser = _build_parser_inner(
249
264
  args[0],
250
265
  context,
251
- convert_string_to_snake_case=context.options.convert_to_snake_case,
252
266
  )
267
+
268
+ def key_parser(value: typing.Any) -> object:
269
+ inner = k_inner_parser(value)
270
+ if (
271
+ isinstance(inner, str)
272
+ # enum keys and OpaqueData's would also have string value types,
273
+ # but their explicit type is not a string, thus shouldn't be converted
274
+ and args[0] is str
275
+ and context.options.from_camel_case
276
+ ):
277
+ return camel_to_snake_case(value)
278
+ return inner
279
+
253
280
  v_parser = _build_parser_inner(args[1], context)
254
281
  return lambda value: origin(
255
- (k_parser(k), v_parser(v)) for k, v in value.items()
282
+ (key_parser(k), v_parser(v)) for k, v in value.items()
256
283
  )
257
284
 
258
285
  if origin == typing.Literal:
259
286
  valid_values: set[T] = set(typing.get_args(parsed_type))
260
287
  return lambda value: _invoke_membership_parser(valid_values, value)
261
288
 
262
- if parsed_type is str and convert_string_to_snake_case:
263
- return lambda value: camel_to_snake_case(value) # type: ignore
264
-
265
289
  if parsed_type is int:
266
290
  # first parse ints to decimal to allow scientific notation and decimals
267
291
  # e.g. (1) 1e4 => 1000, (2) 3.0 => 3
@@ -320,6 +344,16 @@ def _build_parser_inner(
320
344
  raise ValueError("Missing type cannot be parsed directly")
321
345
 
322
346
  return error
347
+
348
+ # Check last for generic annotated types and process them unwrapped
349
+ # this must be last, since some of the expected types, like Unions,
350
+ # will also be annotated, but have a special form
351
+ if typing.get_origin(parsed_type) is typing.Annotated:
352
+ return _build_parser_inner(
353
+ parsed_type.__origin__, # type: ignore[attr-defined]
354
+ context,
355
+ )
356
+
323
357
  raise ValueError(f"Unhandled type {parsed_type}")
324
358
 
325
359
 
@@ -351,7 +385,7 @@ def _build_parser_dataclass(
351
385
  return (
352
386
  snake_to_camel_case(field_name)
353
387
  if (
354
- context.options.convert_to_snake_case
388
+ context.options.from_camel_case
355
389
  and not serial_class_data.has_unconverted_key(field_name)
356
390
  )
357
391
  else field_name
@@ -474,8 +508,7 @@ class CachedParser(typing.Generic[T]):
474
508
  if self.parser_api is None:
475
509
  self.parser_api = build_parser(
476
510
  self.arguments,
477
- ParserOptions(
478
- convert_to_snake_case=True,
511
+ ParserOptions.Api(
479
512
  strict_property_parsing=self.strict_property_parsing,
480
513
  ),
481
514
  )
@@ -489,8 +522,7 @@ class CachedParser(typing.Generic[T]):
489
522
  if self.parser_storage is None:
490
523
  self.parser_storage = build_parser(
491
524
  self.arguments,
492
- ParserOptions(
493
- convert_to_snake_case=False,
525
+ ParserOptions.Storage(
494
526
  strict_property_parsing=self.strict_property_parsing,
495
527
  ),
496
528
  )
@@ -1,13 +1,17 @@
1
- # flake8:noqa
1
+ from .annotation import unwrap_annotated as unwrap_annotated
2
2
  from .missing_sentry import MISSING_SENTRY as MISSING_SENTRY
3
3
  from .missing_sentry import MissingSentryType as MissingSentryType
4
4
  from .missing_sentry import MissingType as MissingType
5
5
  from .missing_sentry import coalesce_missing_sentry as coalesce_missing_sentry
6
6
  from .opaque_key import OpaqueKey as OpaqueKey
7
+ from .serial_alias import SerialAliasInspector as SerialAliasInspector
8
+ from .serial_alias import get_serial_alias_data as get_serial_alias_data
9
+ from .serial_alias import serial_alias_annotation as serial_alias_annotation
10
+ from .serial_class import SerialClassDataInspector as SerialClassDataInspector
7
11
  from .serial_class import get_serial_class_data as get_serial_class_data
8
12
  from .serial_class import get_serial_string_enum_data as get_serial_string_enum_data
9
13
  from .serial_class import serial_class as serial_class
10
14
  from .serial_class import serial_string_enum as serial_string_enum
11
- from .serial_class import SerialClassDataInspector as SerialClassDataInspector
12
- from .serial_union import serial_union_annotation as serial_union_annotation
15
+ from .serial_generic import get_serial_data as get_serial_data
13
16
  from .serial_union import get_serial_union_data as get_serial_union_data
17
+ from .serial_union import serial_union_annotation as serial_union_annotation
@@ -0,0 +1,64 @@
1
+ import dataclasses
2
+ import typing
3
+
4
+ T = typing.TypeVar("T")
5
+
6
+
7
+ @dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
8
+ class SerialBase:
9
+ named_type_path: typing.Optional[str] = None
10
+ # Indicates this type is allowed in dynamic lookups, such as via a named_type_path
11
+ # This isn't meant to be limting, but to catalog all the types where we need it
12
+ is_dynamic_allowed: bool = False
13
+ # Tracks if this data was provided as a decorator to the type.
14
+ # This is used to track "proper types" which are appropriate
15
+ # for serialization and/or dynamic discovery
16
+ from_decorator: bool = False
17
+
18
+
19
+ def get_serial_annotation(parsed_type: type[T]) -> SerialBase | None:
20
+ if not hasattr(parsed_type, "__metadata__"):
21
+ return None
22
+ metadata = parsed_type.__metadata__ # type:ignore[attr-defined]
23
+ if not isinstance(metadata, tuple) or len(metadata) != 1:
24
+ return None
25
+ serial = metadata[0]
26
+ if not isinstance(serial, SerialBase):
27
+ return None
28
+ return serial
29
+
30
+
31
+ class SerialInspector(typing.Generic[T]):
32
+ def __init__(self, parsed_type: type[T], serial_base: SerialBase) -> None:
33
+ self._parsed_type = parsed_type
34
+ self._serial_base = serial_base
35
+
36
+ @property
37
+ def named_type_path(self) -> typing.Optional[str]:
38
+ return self._serial_base.named_type_path
39
+
40
+ @property
41
+ def from_decorator(self) -> bool:
42
+ return self._serial_base.from_decorator
43
+
44
+ @property
45
+ def is_field_proper(self) -> bool:
46
+ return (
47
+ self._serial_base.from_decorator
48
+ and self._serial_base.named_type_path is not None
49
+ )
50
+
51
+ @property
52
+ def is_dynamic_allowed(self) -> bool:
53
+ return self._serial_base.is_dynamic_allowed
54
+
55
+
56
+ def unwrap_annotated(parsed_type: type[T]) -> type[T]:
57
+ """
58
+ If the type is an annotated type then return the origin of it.
59
+ Otherwise return the original type.
60
+ """
61
+ if typing.get_origin(parsed_type) is typing.Annotated:
62
+ # It's unclear if there's anyway to type this correctly
63
+ return parsed_type.__origin__ # type:ignore[attr-defined, no-any-return]
64
+ return parsed_type
@@ -0,0 +1,47 @@
1
+ import dataclasses
2
+ import typing
3
+
4
+ from .annotation import SerialBase, SerialInspector, get_serial_annotation
5
+
6
+ T = typing.TypeVar("T")
7
+
8
+
9
+ @dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
10
+ class _SerialAlias(SerialBase):
11
+ """
12
+ This class is to be kept private, to provide flexibility in registration/lookup.
13
+ Places that need the data should access it via help classes/methods.
14
+ """
15
+
16
+
17
+ def serial_alias_annotation(
18
+ *,
19
+ named_type_path: typing.Optional[str] = None,
20
+ is_dynamic_allowed: bool = False,
21
+ ) -> _SerialAlias:
22
+ return _SerialAlias(
23
+ named_type_path=named_type_path,
24
+ from_decorator=True,
25
+ is_dynamic_allowed=is_dynamic_allowed,
26
+ )
27
+
28
+
29
+ def _get_serial_alias(parsed_type: type[T]) -> _SerialAlias | None:
30
+ serial = get_serial_annotation(parsed_type)
31
+ if not isinstance(serial, _SerialAlias):
32
+ return None
33
+ return serial
34
+
35
+
36
+ class SerialAliasInspector(SerialInspector[T]):
37
+ def __init__(self, parsed_type: type[T], serial_alias: _SerialAlias) -> None:
38
+ super().__init__(parsed_type, serial_alias)
39
+ self._serial_alias = serial_alias
40
+
41
+
42
+ def get_serial_alias_data(parsed_type: type[T]) -> SerialAliasInspector[T] | None:
43
+ serial = _get_serial_alias(parsed_type)
44
+ if serial is None:
45
+ return None
46
+
47
+ return SerialAliasInspector(parsed_type, serial)
@@ -5,20 +5,18 @@ from collections.abc import Callable
5
5
  from enum import StrEnum
6
6
  from typing import Any, Optional, TypeVar, cast
7
7
 
8
+ from .annotation import SerialBase, SerialInspector
9
+
8
10
  _ClassT = TypeVar("_ClassT")
9
11
 
10
12
 
11
- @dataclasses.dataclass
12
- class _SerialClassData:
13
+ @dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
14
+ class _SerialClassData(SerialBase):
13
15
  unconverted_keys: set[str] = dataclasses.field(default_factory=set)
14
16
  unconverted_values: set[str] = dataclasses.field(default_factory=set)
15
17
  to_string_values: set[str] = dataclasses.field(default_factory=set)
16
18
  parse_require: set[str] = dataclasses.field(default_factory=set)
17
19
  named_type_path: Optional[str] = None
18
- # Tracks if this data was provided as a decorator to the type.
19
- # This is used to track "proper types" which are appropriate
20
- # for serialization and/or dynamic discovery
21
- from_decorator: bool = False
22
20
 
23
21
 
24
22
  EMPTY_SERIAL_CLASS_DATA = _SerialClassData()
@@ -31,6 +29,7 @@ def serial_class(
31
29
  to_string_values: Optional[set[str]] = None,
32
30
  parse_require: Optional[set[str]] = None,
33
31
  named_type_path: Optional[str] = None,
32
+ is_dynamic_allowed: bool = False,
34
33
  ) -> Callable[[_ClassT], _ClassT]:
35
34
  """
36
35
  An additional decorator to a dataclass that specifies serialization options.
@@ -63,17 +62,20 @@ def serial_class(
63
62
  parse_require=parse_require or set(),
64
63
  named_type_path=named_type_path,
65
64
  from_decorator=True,
65
+ is_dynamic_allowed=is_dynamic_allowed,
66
66
  )
67
67
  return orig_class
68
68
 
69
69
  return decorate
70
70
 
71
71
 
72
- class SerialClassDataInspector:
72
+ class SerialClassDataInspector(SerialInspector[_ClassT]):
73
73
  def __init__(
74
74
  self,
75
+ parsed_type: type[_ClassT],
75
76
  current: _SerialClassData,
76
77
  ) -> None:
78
+ super().__init__(parsed_type, current)
77
79
  self.current = current
78
80
 
79
81
  def has_unconverted_key(self, key: str) -> bool:
@@ -88,20 +90,8 @@ class SerialClassDataInspector:
88
90
  def has_parse_require(self, key: str) -> bool:
89
91
  return key in self.current.parse_require
90
92
 
91
- @property
92
- def from_decorator(self) -> bool:
93
- return self.current.from_decorator
94
-
95
- @property
96
- def named_type_path(self) -> Optional[str]:
97
- return self.current.named_type_path
98
-
99
- @property
100
- def is_field_proper(self) -> bool:
101
- return self.current.from_decorator and self.current.named_type_path is not None
102
93
 
103
-
104
- def _get_merged_serial_class_data(type_class: type[Any]) -> _SerialClassData | None:
94
+ def get_merged_serial_class_data(type_class: type[Any]) -> _SerialClassData | None:
105
95
  base_class_data = (
106
96
  cast(_SerialClassData, type_class.__unc_serial_data)
107
97
  if hasattr(type_class, "__unc_serial_data")
@@ -110,26 +100,30 @@ def _get_merged_serial_class_data(type_class: type[Any]) -> _SerialClassData | N
110
100
  if base_class_data is None:
111
101
  return None
112
102
 
103
+ # IMPROVE: We should cache this result on the type
113
104
  if type_class.__bases__ is not None:
114
105
  for base in type_class.__bases__:
115
- curr_base_class_data = _get_merged_serial_class_data(base)
106
+ curr_base_class_data = get_merged_serial_class_data(base)
116
107
  if curr_base_class_data is not None:
117
- base_class_data.unconverted_keys |= (
118
- curr_base_class_data.unconverted_keys
119
- )
120
- base_class_data.unconverted_values |= (
121
- curr_base_class_data.unconverted_values
122
- )
123
- base_class_data.to_string_values |= (
124
- curr_base_class_data.to_string_values
108
+ base_class_data = dataclasses.replace(
109
+ base_class_data,
110
+ unconverted_keys=base_class_data.unconverted_keys
111
+ | curr_base_class_data.unconverted_keys,
112
+ unconverted_values=base_class_data.unconverted_values
113
+ | curr_base_class_data.unconverted_values,
114
+ to_string_values=base_class_data.to_string_values
115
+ | curr_base_class_data.to_string_values,
116
+ parse_require=base_class_data.parse_require
117
+ | curr_base_class_data.parse_require,
125
118
  )
126
- base_class_data.parse_require |= curr_base_class_data.parse_require
127
119
  return base_class_data
128
120
 
129
121
 
130
- def get_serial_class_data(type_class: type[Any]) -> SerialClassDataInspector:
122
+ def get_serial_class_data(
123
+ type_class: type[_ClassT],
124
+ ) -> SerialClassDataInspector[_ClassT]:
131
125
  return SerialClassDataInspector(
132
- _get_merged_serial_class_data(type_class) or EMPTY_SERIAL_CLASS_DATA
126
+ type_class, get_merged_serial_class_data(type_class) or EMPTY_SERIAL_CLASS_DATA
133
127
  )
134
128
 
135
129
 
@@ -0,0 +1,16 @@
1
+ import typing
2
+
3
+ from .annotation import SerialInspector, get_serial_annotation
4
+ from .serial_class import get_merged_serial_class_data
5
+
6
+ T = typing.TypeVar("T")
7
+
8
+
9
+ def get_serial_data(parsed_type: type[T]) -> SerialInspector[T] | None:
10
+ serial = get_serial_annotation(parsed_type)
11
+ if serial is None:
12
+ serial = get_merged_serial_class_data(parsed_type)
13
+
14
+ if serial is not None:
15
+ return SerialInspector(parsed_type, serial)
16
+ return None
@@ -1,6 +1,8 @@
1
1
  import dataclasses
2
2
  import typing
3
3
 
4
+ from .annotation import SerialBase, SerialInspector, get_serial_annotation
5
+
4
6
  T = typing.TypeVar("T")
5
7
 
6
8
 
@@ -17,7 +19,7 @@ class IdentityHashWrapper(typing.Generic[T]):
17
19
 
18
20
 
19
21
  @dataclasses.dataclass(kw_only=True, frozen=True, eq=True)
20
- class _SerialUnion:
22
+ class _SerialUnion(SerialBase):
21
23
  """
22
24
  This class is to be kept private, to provide flexibility in registration/lookup.
23
25
  Places that need the data should access it via help classes/methods.
@@ -27,7 +29,6 @@ class _SerialUnion:
27
29
  # determine which type to parse.
28
30
  discriminator: typing.Optional[str] = None
29
31
  discriminator_map: typing.Optional[IdentityHashWrapper[dict[str, type]]] = None
30
- named_type_path: typing.Optional[str] = None
31
32
 
32
33
 
33
34
  def serial_union_annotation(
@@ -35,6 +36,7 @@ def serial_union_annotation(
35
36
  discriminator: typing.Optional[str] = None,
36
37
  discriminator_map: typing.Optional[dict[str, type]] = None,
37
38
  named_type_path: typing.Optional[str] = None,
39
+ is_dynamic_allowed: bool = False,
38
40
  ) -> _SerialUnion:
39
41
  return _SerialUnion(
40
42
  discriminator=discriminator,
@@ -42,23 +44,21 @@ def serial_union_annotation(
42
44
  if discriminator_map is not None
43
45
  else None,
44
46
  named_type_path=named_type_path,
47
+ from_decorator=True,
48
+ is_dynamic_allowed=is_dynamic_allowed,
45
49
  )
46
50
 
47
51
 
48
52
  def _get_serial_union(parsed_type: type[T]) -> _SerialUnion | None:
49
- if not hasattr(parsed_type, "__metadata__"):
50
- return None
51
- metadata = parsed_type.__metadata__ # type:ignore[attr-defined]
52
- if not isinstance(metadata, tuple) or len(metadata) != 1:
53
- return None
54
- serial = metadata[0]
53
+ serial = get_serial_annotation(parsed_type)
55
54
  if not isinstance(serial, _SerialUnion):
56
55
  return None
57
56
  return serial
58
57
 
59
58
 
60
- class SerialClassInspector(typing.Generic[T]):
59
+ class SerialClassInspector(SerialInspector[T]):
61
60
  def __init__(self, parsed_type: type[T], serial_union: _SerialUnion) -> None:
61
+ super().__init__(parsed_type, serial_union)
62
62
  self._parsed_type = parsed_type
63
63
  self._serial_union = serial_union
64
64
 
@@ -1,4 +1,6 @@
1
1
  from .convert_to_snakecase import convert_dict_to_snake_case
2
+ from .dataclasses import dict_fields as dict_fields
3
+ from .dataclasses import iterate_fields as iterate_fields
2
4
  from .serialization_helpers import (
3
5
  serialize_for_api,
4
6
  serialize_for_storage,
@@ -10,4 +12,6 @@ __all__: list[str] = [
10
12
  "serialize_for_api",
11
13
  "serialize_for_storage",
12
14
  "serialize_for_storage_dict",
15
+ "iterate_fields",
16
+ "dict_fields",
13
17
  ]
@@ -0,0 +1,14 @@
1
+ from dataclasses import fields
2
+ from typing import TYPE_CHECKING, Any, Iterator
3
+
4
+ if TYPE_CHECKING:
5
+ from _typeshed import DataclassInstance
6
+
7
+
8
+ def iterate_fields(d: "DataclassInstance") -> Iterator[tuple[str, Any]]:
9
+ for field in fields(d):
10
+ yield field.name, getattr(d, field.name)
11
+
12
+
13
+ def dict_fields(d: "DataclassInstance") -> dict[str, Any]:
14
+ return dict(iterate_fields(d))