classifyre-cli 0.6.5__tar.gz → 0.6.7__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 (377) hide show
  1. classifyre_cli-0.6.7/.turbo/turbo-build.log +3 -0
  2. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/PKG-INFO +1 -1
  3. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/package.json +1 -1
  4. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/pyproject.toml +1 -1
  5. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/sdk.py +7 -0
  6. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/base.py +4 -7
  7. classifyre_cli-0.6.7/src/utils/sampling_cursor.py +45 -0
  8. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_source.py +5 -12
  9. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_dropbox_source.py +2 -4
  10. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_elasticsearch_source.py +3 -4
  11. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_google_workspace_source.py +3 -6
  12. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_hugging_face_source.py +2 -3
  13. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_kafka_source.py +2 -2
  14. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_meilisearch_source.py +2 -3
  15. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_opensearch_source.py +2 -3
  16. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_sampling_automatic.py +2 -3
  17. classifyre_cli-0.6.7/tests/test_sampling_cursor.py +60 -0
  18. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_sandbox_source.py +2 -3
  19. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_tabular_automatic_sampling.py +2 -3
  20. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/uv.lock +396 -378
  21. classifyre_cli-0.6.5/.turbo/turbo-build.log +0 -3
  22. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/.gitignore +0 -0
  23. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/.python-version +0 -0
  24. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/README.md +0 -0
  25. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/main.py +0 -0
  26. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/scripts/generate_models.py +0 -0
  27. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/scripts/generate_runtime_packages.py +0 -0
  28. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/scripts/generate_sdk_completions.py +0 -0
  29. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/__init__.py +0 -0
  30. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/augmentation/__init__.py +0 -0
  31. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/augmentation/contract.py +0 -0
  32. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/augmentation/preview.py +0 -0
  33. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/augmentation/runner.py +0 -0
  34. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/augmentation/sdk.py +0 -0
  35. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/augmentation/session.py +0 -0
  36. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/config.py +0 -0
  37. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/__init__.py +0 -0
  38. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/base.py +0 -0
  39. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/broken_links/__init__.py +0 -0
  40. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/broken_links/detector.py +0 -0
  41. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/config.py +0 -0
  42. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/content/__init__.py +0 -0
  43. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/__init__.py +0 -0
  44. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/detector.py +0 -0
  45. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/extractor.py +0 -0
  46. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/__init__.py +0 -0
  47. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_base.py +0 -0
  48. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_custom_detector.py +0 -0
  49. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_factory.py +0 -0
  50. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_gliner2.py +0 -0
  51. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_image_classification.py +0 -0
  52. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_llm.py +0 -0
  53. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_object_detection.py +0 -0
  54. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_regex.py +0 -0
  55. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_tag.py +0 -0
  56. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/runners/_text_classification.py +0 -0
  57. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom/trainer.py +0 -0
  58. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/__init__.py +0 -0
  59. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/contract.py +0 -0
  60. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/files.py +0 -0
  61. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/preview.py +0 -0
  62. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/results.py +0 -0
  63. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/runner.py +0 -0
  64. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/sdk.py +0 -0
  65. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/custom_detector/session.py +0 -0
  66. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/dependencies.py +0 -0
  67. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/engine_version.py +0 -0
  68. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/errors.py +0 -0
  69. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/pii/__init__.py +0 -0
  70. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/pii/detector.py +0 -0
  71. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/secrets/__init__.py +0 -0
  72. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/secrets/detector.py +0 -0
  73. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/threat/__init__.py +0 -0
  74. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/threat/code_security_detector.py +0 -0
  75. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/detectors/threat/yara_detector.py +0 -0
  76. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/file_evaluation/__init__.py +0 -0
  77. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/file_evaluation/asset_fixture.py +0 -0
  78. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/file_evaluation/runner.py +0 -0
  79. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/graph/__init__.py +0 -0
  80. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/graph/edges.py +0 -0
  81. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/main.py +0 -0
  82. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/models/generated_detectors.py +0 -0
  83. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/models/generated_input.py +0 -0
  84. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/models/generated_single_asset_scan_results.py +0 -0
  85. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/__init__.py +0 -0
  86. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/child.py +0 -0
  87. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/cli.py +0 -0
  88. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/cohort.py +0 -0
  89. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/contract.py +0 -0
  90. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/execute.py +0 -0
  91. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/files.py +0 -0
  92. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/groups.py +0 -0
  93. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/outputs.py +0 -0
  94. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/packages.py +0 -0
  95. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/protocol.py +0 -0
  96. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/redact.py +0 -0
  97. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/scaffold.py +0 -0
  98. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/notebook/serialize.py +0 -0
  99. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/outputs/__init__.py +0 -0
  100. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/outputs/base.py +0 -0
  101. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/outputs/console.py +0 -0
  102. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/outputs/factory.py +0 -0
  103. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/outputs/file.py +0 -0
  104. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/outputs/rest.py +0 -0
  105. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/__init__.py +0 -0
  106. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/asset_payload_server.py +0 -0
  107. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/content_provider.py +0 -0
  108. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/detector_breaker.py +0 -0
  109. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/detector_pipeline.py +0 -0
  110. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/parsed_content_provider.py +0 -0
  111. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/payload_window.py +0 -0
  112. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/scan_cache.py +0 -0
  113. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/text_artifact.py +0 -0
  114. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/pipeline/worker_pool.py +0 -0
  115. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/__init__.py +0 -0
  116. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/asset_metadata.py +0 -0
  117. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/atlassian_common.py +0 -0
  118. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/azure_blob_storage/__init__.py +0 -0
  119. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/azure_blob_storage/source.py +0 -0
  120. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/confluence/__init__.py +0 -0
  121. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/confluence/source.py +0 -0
  122. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/custom/__init__.py +0 -0
  123. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/custom/env.py +0 -0
  124. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/custom/runner.py +0 -0
  125. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/custom/source.py +0 -0
  126. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/databricks/__init__.py +0 -0
  127. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/databricks/source.py +0 -0
  128. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/delta_lake/__init__.py +0 -0
  129. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/delta_lake/source.py +0 -0
  130. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/dependencies.py +0 -0
  131. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/dropbox/__init__.py +0 -0
  132. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/dropbox/auth.py +0 -0
  133. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/dropbox/source.py +0 -0
  134. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/elasticsearch/__init__.py +0 -0
  135. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/elasticsearch/source.py +0 -0
  136. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/email/__init__.py +0 -0
  137. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/email/source.py +0 -0
  138. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/git/__init__.py +0 -0
  139. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/git/source.py +0 -0
  140. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/google_cloud_storage/__init__.py +0 -0
  141. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/google_cloud_storage/source.py +0 -0
  142. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/google_workspace/__init__.py +0 -0
  143. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/google_workspace/source.py +0 -0
  144. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/hive/__init__.py +0 -0
  145. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/hive/source.py +0 -0
  146. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/hugging_face/__init__.py +0 -0
  147. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/hugging_face/source.py +0 -0
  148. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/iceberg/__init__.py +0 -0
  149. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/iceberg/source.py +0 -0
  150. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/jira/__init__.py +0 -0
  151. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/jira/source.py +0 -0
  152. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/kafka/__init__.py +0 -0
  153. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/kafka/rest.py +0 -0
  154. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/kafka/source.py +0 -0
  155. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/lakehouse_base.py +0 -0
  156. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/local_folder/__init__.py +0 -0
  157. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/local_folder/source.py +0 -0
  158. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/meilisearch/__init__.py +0 -0
  159. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/meilisearch/source.py +0 -0
  160. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/microsoft_365/__init__.py +0 -0
  161. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/microsoft_365/source.py +0 -0
  162. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/mongodb/__init__.py +0 -0
  163. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/mongodb/source.py +0 -0
  164. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/mssql/__init__.py +0 -0
  165. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/mssql/source.py +0 -0
  166. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/mysql/__init__.py +0 -0
  167. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/mysql/source.py +0 -0
  168. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/neo4j/__init__.py +0 -0
  169. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/neo4j/source.py +0 -0
  170. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/notion/__init__.py +0 -0
  171. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/notion/client.py +0 -0
  172. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/notion/source.py +0 -0
  173. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/object_storage/base.py +0 -0
  174. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/opensearch/__init__.py +0 -0
  175. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/opensearch/source.py +0 -0
  176. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/oracle/__init__.py +0 -0
  177. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/oracle/source.py +0 -0
  178. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/postgresql/__init__.py +0 -0
  179. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/postgresql/source.py +0 -0
  180. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/powerbi/__init__.py +0 -0
  181. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/powerbi/source.py +0 -0
  182. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/recipe_normalizer.py +0 -0
  183. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/reddit/__init__.py +0 -0
  184. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/reddit/source.py +0 -0
  185. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/s3_client.py +0 -0
  186. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/s3_compatible_storage/README.md +0 -0
  187. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/s3_compatible_storage/__init__.py +0 -0
  188. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/s3_compatible_storage/source.py +0 -0
  189. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/sandbox/__init__.py +0 -0
  190. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/sandbox/source.py +0 -0
  191. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/search_engine_base.py +0 -0
  192. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/servicedesk/__init__.py +0 -0
  193. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/servicedesk/source.py +0 -0
  194. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/slack/__init__.py +0 -0
  195. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/slack/source.py +0 -0
  196. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/snowflake/__init__.py +0 -0
  197. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/snowflake/source.py +0 -0
  198. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/sqlite/__init__.py +0 -0
  199. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/sqlite/source.py +0 -0
  200. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/tableau/__init__.py +0 -0
  201. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/tableau/source.py +0 -0
  202. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/tabular_base.py +0 -0
  203. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/tabular_utils.py +0 -0
  204. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/wordpress/__init__.py +0 -0
  205. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/wordpress/source.py +0 -0
  206. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/youtube/__init__.py +0 -0
  207. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/sources/youtube/source.py +0 -0
  208. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/telemetry.py +0 -0
  209. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/__init__.py +0 -0
  210. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/archive_extraction.py +0 -0
  211. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/content_extraction.py +0 -0
  212. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/dependency_groups.py +0 -0
  213. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/embedded_files.py +0 -0
  214. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/external_video.py +0 -0
  215. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/file_metadata.py +0 -0
  216. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/file_parser.py +0 -0
  217. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/file_to_images.py +0 -0
  218. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/hashing.py +0 -0
  219. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/legacy_office.py +0 -0
  220. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/payload.py +0 -0
  221. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/range_reader.py +0 -0
  222. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/redaction.py +0 -0
  223. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/resources.py +0 -0
  224. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/source_files.py +0 -0
  225. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/sql_lineage.py +0 -0
  226. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/torch_runtime.py +0 -0
  227. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/transcription.py +0 -0
  228. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/urn.py +0 -0
  229. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/uv_sync.py +0 -0
  230. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/validation.py +0 -0
  231. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/src/utils/video_processing.py +0 -0
  232. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/__init__.py +0 -0
  233. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/_lakehouse_fakes.py +0 -0
  234. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/conftest.py +0 -0
  235. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/__init__.py +0 -0
  236. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/broken_links/test_broken_links_detector.py +0 -0
  237. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/conftest.py +0 -0
  238. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/content/__init__.py +0 -0
  239. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/__init__.py +0 -0
  240. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/conftest.py +0 -0
  241. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_gliner2_classification.py +0 -0
  242. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_invoice_extraction.py +0 -0
  243. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_llm_runner.py +0 -0
  244. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_pipeline_integration.py +0 -0
  245. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_regex_runner.py +0 -0
  246. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_runner_hardening.py +0 -0
  247. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/custom/test_transformer_runners.py +0 -0
  248. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/__init__.py +0 -0
  249. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/conftest.py +0 -0
  250. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/sample_invoice.pdf +0 -0
  251. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/test_pii_chunking.py +0 -0
  252. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/test_pii_detector.py +0 -0
  253. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/test_pii_detector_extended.py +0 -0
  254. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/test_pii_regional_entities.py +0 -0
  255. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/pii/test_pii_severity.py +0 -0
  256. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/secrets/__init__.py +0 -0
  257. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/secrets/test_secrets_detector.py +0 -0
  258. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/secrets/test_secrets_detector_extended.py +0 -0
  259. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_base_detector.py +0 -0
  260. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_custom_detector_examples_runtime.py +0 -0
  261. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_custom_detector_session.py +0 -0
  262. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_detector_catalog_commercial.py +0 -0
  263. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_detector_pipeline_types.py +0 -0
  264. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_detector_schema_examples.py +0 -0
  265. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_detector_types.py +0 -0
  266. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_phase2_detectors.py +0 -0
  267. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_registry.py +0 -0
  268. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/test_tag_runner.py +0 -0
  269. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/threat/__init__.py +0 -0
  270. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/threat/test_code_security_detector.py +0 -0
  271. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/detectors/threat/test_yara_detector.py +0 -0
  272. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/integration/test_wordpress_broken_links_detector.py +0 -0
  273. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/integration/test_wordpress_links_assets.py +0 -0
  274. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/pipeline/test_detector_breaker.py +0 -0
  275. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/pipeline/test_detector_outcomes.py +0 -0
  276. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/pipeline/test_detector_pipeline.py +0 -0
  277. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/pipeline/test_worker_pool.py +0 -0
  278. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_arrow_ipc_payloads.py +0 -0
  279. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_assets_metadata_catalog.py +0 -0
  280. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_contract.py +0 -0
  281. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_edges.py +0 -0
  282. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_patch.py +0 -0
  283. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_scan_cache.py +0 -0
  284. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_sdk.py +0 -0
  285. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_session.py +0 -0
  286. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_augmentation_tags_end_to_end.py +0 -0
  287. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_azure_blob_storage_source.py +0 -0
  288. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_base_source_attachment.py +0 -0
  289. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_base_source_sampling.py +0 -0
  290. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_byte_valued_fields.py +0 -0
  291. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_config.py +0 -0
  292. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_confluence_source.py +0 -0
  293. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_detector_end_to_end.py +0 -0
  294. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_detector_evaluation.py +0 -0
  295. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_detector_notebook.py +0 -0
  296. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_detector_templates.py +0 -0
  297. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_extractor.py +0 -0
  298. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_source_relationships.py +0 -0
  299. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_custom_source_tags_end_to_end.py +0 -0
  300. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_databricks_source.py +0 -0
  301. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_delta_lake_source.py +0 -0
  302. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_dependency_groups.py +0 -0
  303. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_detector_scope.py +0 -0
  304. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_dropbox_auth_command.py +0 -0
  305. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_email_source.py +0 -0
  306. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_file_evaluation_runner.py +0 -0
  307. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_git_source.py +0 -0
  308. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_google_cloud_storage_source.py +0 -0
  309. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_graph_edges.py +0 -0
  310. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_hashing.py +0 -0
  311. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_hive_source.py +0 -0
  312. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_iceberg_source.py +0 -0
  313. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_jira_source.py +0 -0
  314. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_lineage_loss_reporting.py +0 -0
  315. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_local_folder_source.py +0 -0
  316. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_main.py +0 -0
  317. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_microsoft_365_source.py +0 -0
  318. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_mongodb_source.py +0 -0
  319. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_mssql_source.py +0 -0
  320. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_mysql_source.py +0 -0
  321. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_neo4j_source.py +0 -0
  322. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_asset_entity.py +0 -0
  323. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_asset_extract.py +0 -0
  324. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_asset_tags.py +0 -0
  325. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_cohort.py +0 -0
  326. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_execute.py +0 -0
  327. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_files.py +0 -0
  328. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_groups.py +0 -0
  329. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_log_levels.py +0 -0
  330. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_packages.py +0 -0
  331. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_query_assets.py +0 -0
  332. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_sdk_exports.py +0 -0
  333. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_serialize.py +0 -0
  334. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notebook_templates.py +0 -0
  335. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_notion_source.py +0 -0
  336. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_object_storage_download_efficiency.py +0 -0
  337. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_oracle_source.py +0 -0
  338. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_outputs.py +0 -0
  339. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_payload_window.py +0 -0
  340. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_payload_window_parquet.py +0 -0
  341. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_postgresql_source.py +0 -0
  342. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_powerbi_source.py +0 -0
  343. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_range_reading.py +0 -0
  344. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_recipe_normalizer.py +0 -0
  345. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_reddit_source.py +0 -0
  346. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_rest_backpressure.py +0 -0
  347. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_runtime_packages.py +0 -0
  348. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_s3_compatible_storage_source.py +0 -0
  349. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_scan_cache.py +0 -0
  350. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_sdk_completions.py +0 -0
  351. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_secret_redaction.py +0 -0
  352. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_semantic_declarations.py +0 -0
  353. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_servicedesk_source.py +0 -0
  354. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_slack_source.py +0 -0
  355. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_snowflake_source.py +0 -0
  356. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_source_dependency_groups.py +0 -0
  357. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_source_strategy_conformance.py +0 -0
  358. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_sqlite_source.py +0 -0
  359. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_tableau_source.py +0 -0
  360. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_tabular_lineage.py +0 -0
  361. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_tabular_utils.py +0 -0
  362. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_torch_runtime.py +0 -0
  363. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_urn.py +0 -0
  364. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_uv_sync.py +0 -0
  365. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_wordpress_source.py +0 -0
  366. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_youtube_source.py +0 -0
  367. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/test_youtube_source_integration.py +0 -0
  368. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_archive_extraction.py +0 -0
  369. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_content_extraction.py +0 -0
  370. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_embedded_files.py +0 -0
  371. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_file_metadata.py +0 -0
  372. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_file_parser.py +0 -0
  373. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_file_to_images.py +0 -0
  374. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_legacy_office.py +0 -0
  375. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_payload.py +0 -0
  376. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_transcription.py +0 -0
  377. {classifyre_cli-0.6.5 → classifyre_cli-0.6.7}/tests/utils/test_video_processing.py +0 -0
@@ -0,0 +1,3 @@
1
+ $ uv sync
2
+ Resolved 325 packages in 264ms
3
+ Checked 51 packages in 6ms
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: classifyre-cli
3
- Version: 0.6.5
3
+ Version: 0.6.7
4
4
  Summary: Classifyre CLI — scan and classify unstructured data sources
5
5
  License: MIT
6
6
  Keywords: data,ingestion,metadata,pii,secrets,unstructured
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classifyre/cli",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "build": "uv sync",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "classifyre-cli"
3
- version = "0.6.5"
3
+ version = "0.6.7"
4
4
  description = "Classifyre CLI — scan and classify unstructured data sources"
5
5
  readme = "README.md"
6
6
  # Upper bound is load-bearing: onnxruntime publishes no cp315 wheels (notably
@@ -47,6 +47,7 @@ from ..graph.edges import (
47
47
  same_as,
48
48
  uses,
49
49
  )
50
+ from ..utils.sampling_cursor import check_cursor_fits
50
51
  from ..utils.urn import Urn
51
52
  from .cohort import CohortItem, normalize_bands, select_cohort
52
53
  from .files import DEFAULT_PAGE_SIZE, ParsedContent, pages, parse
@@ -700,7 +701,13 @@ class Context:
700
701
  no longer implies a deleted one. Worse, the discard was silent: the call
701
702
  succeeded, the notebook believed it had saved state, and the next run
702
703
  started from nothing.
704
+
705
+ Raises ``ValueError`` for a cursor too large to start the next run with
706
+ (128 KiB compressed). Keep a cursor to positions and counters; state
707
+ that grows with the corpus belongs in assets, read back with
708
+ ``ctx.query_assets()``.
703
709
  """
710
+ check_cursor_fits(cursor)
704
711
  self._next_cursor = dict(cursor)
705
712
 
706
713
  @property
@@ -1,5 +1,3 @@
1
- import base64
2
- import json
3
1
  import logging
4
2
  import os
5
3
  import threading
@@ -13,6 +11,7 @@ from ..outputs.rest import IngestEdge
13
11
  if TYPE_CHECKING:
14
12
  from ..utils.file_parser import ParsedBytes
15
13
  from ..utils.hashing import calculate_checksum, normalize_http_url
14
+ from ..utils.sampling_cursor import decode_sampling_cursor
16
15
  from ..utils.validation import validate_output
17
16
  from .recipe_normalizer import normalize_source_recipe
18
17
 
@@ -34,8 +33,8 @@ class BaseSource(ABC):
34
33
  # Default batch size for streaming asset results
35
34
  BATCH_SIZE: int = 50
36
35
  HAS_SUCCESSFUL_RUN_ENV = "CLASSIFYRE_SOURCE_HAS_SUCCESSFUL_RUN"
37
- # The API injects the saved AUTOMATIC sampling cursor here (base64-encoded
38
- # JSON) before launching the CLI job. The recipe itself cannot carry it
36
+ # The API injects the saved cursor here (gzip + base64 JSON, see
37
+ # utils/sampling_cursor.py) before launching the CLI job. The recipe itself cannot carry it
39
38
  # because every source schema sets ``additionalProperties: false``.
40
39
  SAMPLING_CURSOR_ENV = "CLASSIFYRE_SAMPLING_CURSOR"
41
40
 
@@ -128,12 +127,10 @@ class BaseSource(ABC):
128
127
  if not raw:
129
128
  return {}
130
129
  try:
131
- decoded = base64.b64decode(raw).decode("utf-8")
132
- data = json.loads(decoded)
130
+ return decode_sampling_cursor(raw)
133
131
  except Exception as exc:
134
132
  logger.warning("Ignoring malformed %s: %s", self.SAMPLING_CURSOR_ENV, exc)
135
133
  return {}
136
- return data if isinstance(data, dict) else {}
137
134
 
138
135
  def sampling_cursor(self) -> dict[str, Any]:
139
136
  """Return the cursor saved by the previous run (empty on first run)."""
@@ -0,0 +1,45 @@
1
+ """How a source's saved cursor travels from the API to a scan.
2
+
3
+ The API hands the cursor to the CLI in one environment variable, gzip then
4
+ base64. Linux caps a single environment variable at 128 KiB (MAX_ARG_STRLEN);
5
+ over it the process never starts and the kernel's "argument list too long"
6
+ names neither the variable nor its size. So the size is checked on both ends:
7
+ the API refuses to launch with a cursor that does not fit, and a notebook is
8
+ told in the run that tries to *save* one, while it can still do something
9
+ about it.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import base64
15
+ import gzip
16
+ import json
17
+ from collections.abc import Mapping
18
+ from typing import Any
19
+
20
+ #: The limit for one environment variable, and so for an encoded cursor.
21
+ MAX_ENCODED_CURSOR_BYTES = 128 * 1024
22
+
23
+
24
+ def encode_sampling_cursor(cursor: Mapping[str, Any]) -> str:
25
+ """The cursor as it is put into the environment variable."""
26
+ raw = json.dumps(cursor, separators=(",", ":")).encode("utf-8")
27
+ return base64.b64encode(gzip.compress(raw)).decode("ascii")
28
+
29
+
30
+ def decode_sampling_cursor(encoded: str) -> dict[str, Any]:
31
+ """The cursor an environment variable carries. Raises on malformed input."""
32
+ data = json.loads(gzip.decompress(base64.b64decode(encoded)).decode("utf-8"))
33
+ return data if isinstance(data, dict) else {}
34
+
35
+
36
+ def check_cursor_fits(cursor: Mapping[str, Any]) -> None:
37
+ """Refuse a cursor the next run could not be started with."""
38
+ size = len(encode_sampling_cursor(cursor))
39
+ if size > MAX_ENCODED_CURSOR_BYTES:
40
+ raise ValueError(
41
+ f"This cursor is {size} bytes compressed, over the "
42
+ f"{MAX_ENCODED_CURSOR_BYTES}-byte limit: the next run could not be "
43
+ "started with it. A cursor records where a run stopped; keep bulk "
44
+ "state in assets and read it back with ctx.query_assets()."
45
+ )
@@ -20,6 +20,7 @@ from src.sources.asset_metadata import is_open_kind, validate_metadata
20
20
  from src.sources.custom.env import ALLOWED_ENV_KEYS, scrubbed_environment
21
21
  from src.sources.custom.source import CustomSource, CustomSourceError
22
22
  from src.utils.hashing import hash_id
23
+ from src.utils.sampling_cursor import encode_sampling_cursor
23
24
 
24
25
  SIMPLE_NOTEBOOK = """from classifyre import Asset, ctx
25
26
 
@@ -344,12 +345,10 @@ def test_automatic_strategy_pages_across_runs(monkeypatch: pytest.MonkeyPatch) -
344
345
 
345
346
  # The API carries the cursor to the next run through the environment,
346
347
  # because the recipe itself forbids extra keys.
347
- import base64
348
- import json
349
348
 
350
349
  monkeypatch.setenv(
351
350
  CustomSource.SAMPLING_CURSOR_ENV,
352
- base64.b64encode(json.dumps(cursor).encode()).decode(),
351
+ encode_sampling_cursor(cursor),
353
352
  )
354
353
  second = get_source(dict(recipe), source_id="s", runner_id="r")
355
354
  try:
@@ -378,13 +377,11 @@ def test_an_automatic_window_keeps_the_notebooks_stored_cursor(
378
377
  ) -> None:
379
378
  # GENESIS field report P15: a window stopped the notebook before it reached
380
379
  # ctx.set_cursor(), and the positional offset replaced its whole state.
381
- import base64
382
- import json
383
380
 
384
381
  stored = {"no_data": {"51000-0013": "2026-09-13"}, "seed_applied": True}
385
382
  monkeypatch.setenv(
386
383
  CustomSource.SAMPLING_CURSOR_ENV,
387
- base64.b64encode(json.dumps(stored).encode()).decode(),
384
+ encode_sampling_cursor(stored),
388
385
  )
389
386
  recipe = build_recipe(counting_notebook(25))
390
387
  recipe["sampling"] = {"strategy": "AUTOMATIC", "rows_per_page": 10}
@@ -1020,8 +1017,6 @@ def test_random_is_bounded_and_actually_random_without_cooperation(source) -> No
1020
1017
 
1021
1018
 
1022
1019
  def test_automatic_pages_without_cooperation(monkeypatch) -> None:
1023
- import base64
1024
- import json
1025
1020
 
1026
1021
  recipe = build_recipe(IGNORES_CTX)
1027
1022
  recipe["sampling"] = {"strategy": "AUTOMATIC", "rows_per_page": 10}
@@ -1032,7 +1027,7 @@ def test_automatic_pages_without_cooperation(monkeypatch) -> None:
1032
1027
  if cursor is not None:
1033
1028
  monkeypatch.setenv(
1034
1029
  CustomSource.SAMPLING_CURSOR_ENV,
1035
- base64.b64encode(json.dumps(cursor).encode()).decode(),
1030
+ encode_sampling_cursor(cursor),
1036
1031
  )
1037
1032
  instance = get_source(dict(recipe), source_id="s", runner_id="r")
1038
1033
  try:
@@ -1050,8 +1045,6 @@ def test_a_notebook_can_take_over_paging_from_the_runtime(monkeypatch) -> None:
1050
1045
  # Without this, run N makes extract() produce N*page items to deliver page
1051
1046
  # of them -- fine for a list in memory, quadratic when each item is a
1052
1047
  # request. Reading ctx.offset hands the skipping to the notebook.
1053
- import base64
1054
- import json
1055
1048
 
1056
1049
  notebook = """from classifyre import Asset, ctx
1057
1050
 
@@ -1070,7 +1063,7 @@ def extract():
1070
1063
 
1071
1064
  monkeypatch.setenv(
1072
1065
  CustomSource.SAMPLING_CURSOR_ENV,
1073
- base64.b64encode(json.dumps({"assets": 20}).encode()).decode(),
1066
+ encode_sampling_cursor({"assets": 20}),
1074
1067
  )
1075
1068
  instance = get_source(dict(recipe), source_id="s", runner_id="r")
1076
1069
  try:
@@ -11,6 +11,7 @@ from src.models.generated_single_asset_scan_results import AssetType as OutputAs
11
11
  from src.sources.asset_metadata import resolve_fields
12
12
  from src.sources.dropbox.source import DropboxObjectRef, DropboxScanTarget, DropboxSource
13
13
  from src.sources.object_storage.base import ContentSnapshot
14
+ from src.utils.sampling_cursor import encode_sampling_cursor
14
15
 
15
16
 
16
17
  def _recipe(
@@ -146,12 +147,9 @@ def test_dropbox_sampling_automatic_advances_window_across_runs(monkeypatch):
146
147
  assert [item.key for item in first] == [f"/f{index:02d}.txt" for index in range(10)]
147
148
  assert cursor == {"objects": 10}
148
149
 
149
- import base64
150
- import json
151
-
152
150
  monkeypatch.setenv(
153
151
  DropboxSource.SAMPLING_CURSOR_ENV,
154
- base64.b64encode(json.dumps(cursor).encode()).decode(),
152
+ encode_sampling_cursor(cursor),
155
153
  )
156
154
  resumed = DropboxSource(_recipe(strategy="AUTOMATIC", rows_per_page=10))
157
155
  second = resumed._apply_sampling(refs)
@@ -1,13 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import base64
4
- import json
5
3
  from typing import Any
6
4
 
7
5
  import pytest
8
6
  import requests
9
7
 
10
8
  from src.sources.elasticsearch.source import ElasticsearchSource
9
+ from src.utils.sampling_cursor import encode_sampling_cursor
11
10
 
12
11
  _INDICES = [
13
12
  {
@@ -237,7 +236,7 @@ def test_elasticsearch_automatic_strategy_starts_at_offset_zero(
237
236
  def test_elasticsearch_automatic_strategy_resumes_and_wraps_on_underfill(
238
237
  _patch_requests: dict[str, Any], monkeypatch: pytest.MonkeyPatch
239
238
  ) -> None:
240
- saved_cursor = base64.b64encode(json.dumps({"index:orders": 10}).encode()).decode()
239
+ saved_cursor = encode_sampling_cursor({"index:orders": 10})
241
240
  monkeypatch.setenv("CLASSIFYRE_SAMPLING_CURSOR", saved_cursor)
242
241
 
243
242
  src = ElasticsearchSource(_recipe(sampling={"strategy": "AUTOMATIC", "rows_per_page": 10}))
@@ -274,7 +273,7 @@ async def test_elasticsearch_all_strategy_scrolls_the_whole_index(
274
273
  def test_elasticsearch_automatic_strategy_wraps_at_max_result_window(
275
274
  _patch_requests: dict[str, Any], monkeypatch: pytest.MonkeyPatch
276
275
  ) -> None:
277
- saved_cursor = base64.b64encode(json.dumps({"index:orders": 10}).encode()).decode()
276
+ saved_cursor = encode_sampling_cursor({"index:orders": 10})
278
277
  monkeypatch.setenv("CLASSIFYRE_SAMPLING_CURSOR", saved_cursor)
279
278
 
280
279
  src = ElasticsearchSource(_recipe(sampling={"strategy": "AUTOMATIC", "rows_per_page": 10}))
@@ -13,6 +13,7 @@ from src.sources.google_workspace.source import (
13
13
  FileRef,
14
14
  GoogleWorkspaceSource,
15
15
  )
16
+ from src.utils.sampling_cursor import encode_sampling_cursor
16
17
 
17
18
 
18
19
  def _base_recipe(auth_mode: str = "service_account", **overrides: object) -> dict:
@@ -140,11 +141,9 @@ class TestSampling:
140
141
  assert cursor_after_first["drive_items:drive-1"] == 10
141
142
 
142
143
  # Simulate a second run reading the persisted cursor.
143
- import base64
144
- import json
145
144
  import os
146
145
 
147
- encoded = base64.b64encode(json.dumps(cursor_after_first).encode("utf-8")).decode("utf-8")
146
+ encoded = encode_sampling_cursor(cursor_after_first)
148
147
  os.environ["CLASSIFYRE_SAMPLING_CURSOR"] = encoded
149
148
  try:
150
149
  source2 = GoogleWorkspaceSource(recipe)
@@ -158,9 +157,7 @@ class TestSampling:
158
157
  assert cursor_after_second["drive_items:drive-1"] == 20
159
158
 
160
159
  # A third page underfills (only 4 items remain) and should wrap to 0.
161
- os.environ["CLASSIFYRE_SAMPLING_CURSOR"] = base64.b64encode(
162
- json.dumps(cursor_after_second).encode("utf-8")
163
- ).decode("utf-8")
160
+ os.environ["CLASSIFYRE_SAMPLING_CURSOR"] = encode_sampling_cursor(cursor_after_second)
164
161
  try:
165
162
  source3 = GoogleWorkspaceSource(recipe)
166
163
  third = source3._apply_sampling(items, "drive-1")
@@ -11,6 +11,7 @@ from src.models.generated_single_asset_scan_results import AssetType as OutputAs
11
11
  from src.sources.asset_metadata import resolve_fields
12
12
  from src.sources.hugging_face.source import HuggingFaceObjectRef, HuggingFaceSource
13
13
  from src.sources.object_storage.base import ContentSnapshot
14
+ from src.utils.sampling_cursor import encode_sampling_cursor
14
15
 
15
16
  REPO_SHA = "0f1e2d3c4b5a69788796a5b4c3d2e1f00f1e2d3c"
16
17
 
@@ -462,8 +463,6 @@ def test_hugging_face_sampling_random_is_deterministic():
462
463
 
463
464
 
464
465
  def test_hugging_face_sampling_automatic_advances_window_across_runs(monkeypatch):
465
- import base64
466
- import json
467
466
 
468
467
  refs = [_ref(f"data/f{index:02d}.parquet", days_ago=index) for index in range(25)]
469
468
 
@@ -476,7 +475,7 @@ def test_hugging_face_sampling_automatic_advances_window_across_runs(monkeypatch
476
475
 
477
476
  monkeypatch.setenv(
478
477
  HuggingFaceSource.SAMPLING_CURSOR_ENV,
479
- base64.b64encode(json.dumps(cursor).encode()).decode(),
478
+ encode_sampling_cursor(cursor),
480
479
  )
481
480
  resumed = _source(strategy="AUTOMATIC", rows_per_page=10)
482
481
  second = resumed._apply_sampling(iter(refs))
@@ -1,13 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import base64
4
- import json
5
4
  from typing import Any
6
5
 
7
6
  import pytest
8
7
 
9
8
  from src.models.generated_input import SamplingStrategy
10
9
  from src.sources.kafka.source import KafkaSource
10
+ from src.utils.sampling_cursor import encode_sampling_cursor
11
11
 
12
12
  CURSOR_ENV = "CLASSIFYRE_SAMPLING_CURSOR"
13
13
 
@@ -19,7 +19,7 @@ _CA_PEM = "-----BEGIN CERTIFICATE-----\nZmFrZS1jYQ==\n-----END CERTIFICATE-----"
19
19
 
20
20
 
21
21
  def _encode_cursor(cursor: dict[str, Any]) -> str:
22
- return base64.b64encode(json.dumps(cursor).encode()).decode()
22
+ return encode_sampling_cursor(cursor)
23
23
 
24
24
 
25
25
  # ── confluent-kafka fakes ────────────────────────────────────────────────
@@ -1,13 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import base64
4
- import json
5
3
  from typing import Any
6
4
 
7
5
  import pytest
8
6
  import requests
9
7
 
10
8
  from src.sources.meilisearch.source import MeilisearchSource
9
+ from src.utils.sampling_cursor import encode_sampling_cursor
11
10
 
12
11
  _INDEX_LIST_PAGE1 = {
13
12
  "results": [
@@ -227,7 +226,7 @@ def test_meilisearch_automatic_strategy_starts_at_offset_zero(
227
226
  def test_meilisearch_automatic_strategy_resumes_and_wraps_on_underfill(
228
227
  _patch_requests: dict[str, Any], monkeypatch: pytest.MonkeyPatch
229
228
  ) -> None:
230
- saved_cursor = base64.b64encode(json.dumps({"index:products": 10}).encode()).decode()
229
+ saved_cursor = encode_sampling_cursor({"index:products": 10})
231
230
  monkeypatch.setenv("CLASSIFYRE_SAMPLING_CURSOR", saved_cursor)
232
231
 
233
232
  src = MeilisearchSource(_recipe(sampling={"strategy": "AUTOMATIC", "rows_per_page": 10}))
@@ -1,13 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import base64
4
- import json
5
3
  from typing import Any
6
4
 
7
5
  import pytest
8
6
  import requests
9
7
 
10
8
  from src.sources.opensearch.source import OpenSearchSource
9
+ from src.utils.sampling_cursor import encode_sampling_cursor
11
10
 
12
11
  _INDICES = [
13
12
  {
@@ -235,7 +234,7 @@ def test_opensearch_automatic_strategy_starts_at_offset_zero(
235
234
  def test_opensearch_automatic_strategy_resumes_and_wraps_on_underfill(
236
235
  _patch_requests: dict[str, Any], monkeypatch: pytest.MonkeyPatch
237
236
  ) -> None:
238
- saved_cursor = base64.b64encode(json.dumps({"index:logs-app": 10}).encode()).decode()
237
+ saved_cursor = encode_sampling_cursor({"index:logs-app": 10})
239
238
  monkeypatch.setenv("CLASSIFYRE_SAMPLING_CURSOR", saved_cursor)
240
239
 
241
240
  src = OpenSearchSource(_recipe(sampling={"strategy": "AUTOMATIC", "rows_per_page": 10}))
@@ -2,8 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import base64
6
- import json
7
5
  from collections.abc import AsyncGenerator
8
6
  from types import SimpleNamespace
9
7
  from typing import Any
@@ -12,6 +10,7 @@ import pytest
12
10
 
13
11
  from src.models.generated_single_asset_scan_results import SingleAssetScanResults
14
12
  from src.sources.base import BaseSource
13
+ from src.utils.sampling_cursor import encode_sampling_cursor
15
14
 
16
15
  CURSOR_ENV = "CLASSIFYRE_SAMPLING_CURSOR"
17
16
 
@@ -47,7 +46,7 @@ def _src(rows: int = 3) -> _DummySource:
47
46
 
48
47
 
49
48
  def _encode(cursor: dict[str, Any]) -> str:
50
- return base64.b64encode(json.dumps(cursor).encode()).decode()
49
+ return encode_sampling_cursor(cursor)
51
50
 
52
51
 
53
52
  def test_default_strategy_is_automatic() -> None:
@@ -0,0 +1,60 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import json
5
+
6
+ import pytest
7
+
8
+ from src.notebook.sdk import Context
9
+ from src.sources.base import BaseSource
10
+ from src.utils.sampling_cursor import (
11
+ MAX_ENCODED_CURSOR_BYTES,
12
+ check_cursor_fits,
13
+ decode_sampling_cursor,
14
+ encode_sampling_cursor,
15
+ )
16
+
17
+
18
+ def _person_companies(persons: int) -> dict[str, list[str]]:
19
+ """The shape that broke a production source: a person -> companies map."""
20
+ return {
21
+ f"person-{i:06d}--19{i % 100:02d}-01-01": [f"{i:06d}a", f"{i + 1:06d}b"]
22
+ for i in range(persons)
23
+ }
24
+
25
+
26
+ def test_cursor_round_trips() -> None:
27
+ cursor = {"cohort": {"register": {"newest": "606601k"}}, "companies": 1200}
28
+ assert decode_sampling_cursor(encode_sampling_cursor(cursor)) == cursor
29
+
30
+
31
+ def test_a_cursor_too_large_as_plain_base64_fits_once_compressed() -> None:
32
+ cursor = {"person_companies": _person_companies(2400)}
33
+ plain = base64.b64encode(json.dumps(cursor).encode()).decode()
34
+ assert len(plain) > MAX_ENCODED_CURSOR_BYTES
35
+ assert len(encode_sampling_cursor(cursor)) < MAX_ENCODED_CURSOR_BYTES
36
+ check_cursor_fits(cursor)
37
+
38
+
39
+ def test_a_cursor_that_cannot_start_the_next_run_is_refused() -> None:
40
+ # Random-looking values, so compression cannot rescue it.
41
+ cursor = {str(i): base64.b64encode(i.to_bytes(4, "big") * 12).decode() for i in range(40000)}
42
+ with pytest.raises(ValueError, match="over the 131072-byte limit"):
43
+ check_cursor_fits(cursor)
44
+
45
+
46
+ def test_set_cursor_refuses_an_oversized_cursor_and_keeps_the_last_good_one() -> None:
47
+ ctx = Context()
48
+ ctx.set_cursor({"offset": 5})
49
+ huge = {str(i): base64.b64encode(i.to_bytes(4, "big") * 12).decode() for i in range(40000)}
50
+ with pytest.raises(ValueError, match=r"ctx\.query_assets\(\)"):
51
+ ctx.set_cursor(huge)
52
+ assert ctx.next_cursor == {"offset": 5}
53
+
54
+
55
+ def test_a_malformed_cursor_is_ignored(monkeypatch: pytest.MonkeyPatch) -> None:
56
+ class _Source:
57
+ SAMPLING_CURSOR_ENV = BaseSource.SAMPLING_CURSOR_ENV
58
+
59
+ monkeypatch.setenv(BaseSource.SAMPLING_CURSOR_ENV, "not-a-cursor")
60
+ assert BaseSource._load_sampling_cursor(_Source()) == {} # type: ignore[arg-type]
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import base64
4
- import json
5
3
  from datetime import UTC, datetime, timedelta
6
4
 
7
5
  import pytest
@@ -9,6 +7,7 @@ import pytest
9
7
  from src.sources import get_source, list_available_sources
10
8
  from src.sources.object_storage.base import ContentSnapshot, ObjectRef
11
9
  from src.sources.sandbox.source import SandboxSource
10
+ from src.utils.sampling_cursor import encode_sampling_cursor
12
11
 
13
12
 
14
13
  def _recipe(strategy: str = "ALL", rows_per_page: int = 10) -> dict:
@@ -76,7 +75,7 @@ def test_sandbox_automatic_sampling_uses_persisted_rolling_window(monkeypatch) -
76
75
 
77
76
  monkeypatch.setenv(
78
77
  "CLASSIFYRE_SAMPLING_CURSOR",
79
- base64.b64encode(json.dumps(cursor).encode()).decode(),
78
+ encode_sampling_cursor(cursor),
80
79
  )
81
80
  second = SandboxSource(_recipe("AUTOMATIC"), source_id="source-1")
82
81
  try:
@@ -2,13 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import base64
6
- import json
7
5
  from typing import Any
8
6
 
9
7
  import pytest
10
8
 
11
9
  from src.sources.mysql.source import MySQLSource, TableRef
10
+ from src.utils.sampling_cursor import encode_sampling_cursor
12
11
 
13
12
  CURSOR_ENV = "CLASSIFYRE_SAMPLING_CURSOR"
14
13
  PAGE = 10 # rows_per_page (MySQL config enforces a minimum of 10)
@@ -94,7 +93,7 @@ def _make_source(
94
93
 
95
94
 
96
95
  def _encode(cursor: dict[str, Any]) -> str:
97
- return base64.b64encode(json.dumps(cursor).encode()).decode()
96
+ return encode_sampling_cursor(cursor)
98
97
 
99
98
 
100
99
  _TABLE = TableRef(database="app_db", schema=None, table="users")