unstructured-ingest 0.3.13__py3-none-any.whl

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 unstructured-ingest might be problematic. Click here for more details.

Files changed (557) hide show
  1. test/__init__.py +0 -0
  2. test/integration/__init__.py +0 -0
  3. test/integration/chunkers/__init__.py +0 -0
  4. test/integration/chunkers/test_chunkers.py +31 -0
  5. test/integration/connectors/__init__.py +0 -0
  6. test/integration/connectors/conftest.py +38 -0
  7. test/integration/connectors/databricks/__init__.py +0 -0
  8. test/integration/connectors/databricks/test_volumes_native.py +269 -0
  9. test/integration/connectors/discord/__init__.py +0 -0
  10. test/integration/connectors/discord/test_discord.py +90 -0
  11. test/integration/connectors/duckdb/__init__.py +0 -0
  12. test/integration/connectors/duckdb/conftest.py +14 -0
  13. test/integration/connectors/duckdb/test_duckdb.py +89 -0
  14. test/integration/connectors/duckdb/test_motherduck.py +95 -0
  15. test/integration/connectors/elasticsearch/__init__.py +0 -0
  16. test/integration/connectors/elasticsearch/conftest.py +34 -0
  17. test/integration/connectors/elasticsearch/test_elasticsearch.py +330 -0
  18. test/integration/connectors/elasticsearch/test_opensearch.py +325 -0
  19. test/integration/connectors/sql/__init__.py +0 -0
  20. test/integration/connectors/sql/test_postgres.py +195 -0
  21. test/integration/connectors/sql/test_singlestore.py +176 -0
  22. test/integration/connectors/sql/test_snowflake.py +238 -0
  23. test/integration/connectors/sql/test_sqlite.py +162 -0
  24. test/integration/connectors/test_astradb.py +217 -0
  25. test/integration/connectors/test_azure_ai_search.py +255 -0
  26. test/integration/connectors/test_chroma.py +120 -0
  27. test/integration/connectors/test_confluence.py +113 -0
  28. test/integration/connectors/test_delta_table.py +185 -0
  29. test/integration/connectors/test_lancedb.py +247 -0
  30. test/integration/connectors/test_milvus.py +203 -0
  31. test/integration/connectors/test_mongodb.py +335 -0
  32. test/integration/connectors/test_neo4j.py +236 -0
  33. test/integration/connectors/test_notion.py +145 -0
  34. test/integration/connectors/test_onedrive.py +118 -0
  35. test/integration/connectors/test_pinecone.py +288 -0
  36. test/integration/connectors/test_qdrant.py +215 -0
  37. test/integration/connectors/test_redis.py +119 -0
  38. test/integration/connectors/test_s3.py +183 -0
  39. test/integration/connectors/test_vectara.py +270 -0
  40. test/integration/connectors/utils/__init__.py +0 -0
  41. test/integration/connectors/utils/constants.py +7 -0
  42. test/integration/connectors/utils/docker.py +151 -0
  43. test/integration/connectors/utils/docker_compose.py +59 -0
  44. test/integration/connectors/utils/validation/__init__.py +0 -0
  45. test/integration/connectors/utils/validation/destination.py +75 -0
  46. test/integration/connectors/utils/validation/equality.py +75 -0
  47. test/integration/connectors/utils/validation/source.py +299 -0
  48. test/integration/connectors/utils/validation/utils.py +36 -0
  49. test/integration/connectors/weaviate/__init__.py +0 -0
  50. test/integration/connectors/weaviate/conftest.py +15 -0
  51. test/integration/connectors/weaviate/test_cloud.py +34 -0
  52. test/integration/connectors/weaviate/test_local.py +131 -0
  53. test/integration/embedders/__init__.py +0 -0
  54. test/integration/embedders/conftest.py +13 -0
  55. test/integration/embedders/test_azure_openai.py +59 -0
  56. test/integration/embedders/test_bedrock.py +103 -0
  57. test/integration/embedders/test_huggingface.py +26 -0
  58. test/integration/embedders/test_mixedbread.py +71 -0
  59. test/integration/embedders/test_octoai.py +77 -0
  60. test/integration/embedders/test_openai.py +76 -0
  61. test/integration/embedders/test_togetherai.py +71 -0
  62. test/integration/embedders/test_vertexai.py +65 -0
  63. test/integration/embedders/test_voyageai.py +65 -0
  64. test/integration/embedders/utils.py +68 -0
  65. test/integration/partitioners/__init__.py +0 -0
  66. test/integration/partitioners/test_partitioner.py +75 -0
  67. test/integration/utils.py +15 -0
  68. test/unit/__init__.py +0 -0
  69. test/unit/embed/__init__.py +0 -0
  70. test/unit/embed/test_mixedbreadai.py +42 -0
  71. test/unit/embed/test_octoai.py +27 -0
  72. test/unit/embed/test_openai.py +20 -0
  73. test/unit/embed/test_vertexai.py +25 -0
  74. test/unit/embed/test_voyageai.py +24 -0
  75. test/unit/test_error.py +27 -0
  76. test/unit/test_logger.py +78 -0
  77. test/unit/test_utils.py +184 -0
  78. test/unit/v2/__init__.py +0 -0
  79. test/unit/v2/chunkers/__init__.py +0 -0
  80. test/unit/v2/chunkers/test_chunkers.py +49 -0
  81. test/unit/v2/connectors/__init__.py +0 -0
  82. test/unit/v2/connectors/test_confluence.py +39 -0
  83. test/unit/v2/embedders/__init__.py +0 -0
  84. test/unit/v2/embedders/test_bedrock.py +36 -0
  85. test/unit/v2/embedders/test_huggingface.py +48 -0
  86. test/unit/v2/embedders/test_mixedbread.py +37 -0
  87. test/unit/v2/embedders/test_octoai.py +35 -0
  88. test/unit/v2/embedders/test_openai.py +35 -0
  89. test/unit/v2/embedders/test_togetherai.py +37 -0
  90. test/unit/v2/embedders/test_vertexai.py +37 -0
  91. test/unit/v2/embedders/test_voyageai.py +38 -0
  92. test/unit/v2/partitioners/__init__.py +0 -0
  93. test/unit/v2/partitioners/test_partitioner.py +63 -0
  94. test/unit/v2/test_interfaces.py +26 -0
  95. test/unit/v2/test_utils.py +82 -0
  96. test/unit/v2/utils/__init__.py +0 -0
  97. test/unit/v2/utils/data_generator.py +32 -0
  98. unstructured_ingest/__init__.py +1 -0
  99. unstructured_ingest/__version__.py +1 -0
  100. unstructured_ingest/cli/__init__.py +14 -0
  101. unstructured_ingest/cli/base/__init__.py +0 -0
  102. unstructured_ingest/cli/base/cmd.py +19 -0
  103. unstructured_ingest/cli/base/dest.py +87 -0
  104. unstructured_ingest/cli/base/src.py +57 -0
  105. unstructured_ingest/cli/cli.py +37 -0
  106. unstructured_ingest/cli/cmd_factory.py +12 -0
  107. unstructured_ingest/cli/cmds/__init__.py +145 -0
  108. unstructured_ingest/cli/cmds/airtable.py +69 -0
  109. unstructured_ingest/cli/cmds/astradb.py +99 -0
  110. unstructured_ingest/cli/cmds/azure_ai_search.py +65 -0
  111. unstructured_ingest/cli/cmds/biomed.py +52 -0
  112. unstructured_ingest/cli/cmds/chroma.py +104 -0
  113. unstructured_ingest/cli/cmds/clarifai.py +71 -0
  114. unstructured_ingest/cli/cmds/confluence.py +69 -0
  115. unstructured_ingest/cli/cmds/databricks_volumes.py +163 -0
  116. unstructured_ingest/cli/cmds/delta_table.py +94 -0
  117. unstructured_ingest/cli/cmds/discord.py +47 -0
  118. unstructured_ingest/cli/cmds/elasticsearch.py +133 -0
  119. unstructured_ingest/cli/cmds/fsspec/__init__.py +0 -0
  120. unstructured_ingest/cli/cmds/fsspec/azure.py +94 -0
  121. unstructured_ingest/cli/cmds/fsspec/box.py +48 -0
  122. unstructured_ingest/cli/cmds/fsspec/dropbox.py +51 -0
  123. unstructured_ingest/cli/cmds/fsspec/fsspec.py +15 -0
  124. unstructured_ingest/cli/cmds/fsspec/gcs.py +71 -0
  125. unstructured_ingest/cli/cmds/fsspec/s3.py +74 -0
  126. unstructured_ingest/cli/cmds/fsspec/sftp.py +58 -0
  127. unstructured_ingest/cli/cmds/github.py +54 -0
  128. unstructured_ingest/cli/cmds/gitlab.py +54 -0
  129. unstructured_ingest/cli/cmds/google_drive.py +49 -0
  130. unstructured_ingest/cli/cmds/hubspot.py +70 -0
  131. unstructured_ingest/cli/cmds/jira.py +71 -0
  132. unstructured_ingest/cli/cmds/kafka.py +102 -0
  133. unstructured_ingest/cli/cmds/local.py +43 -0
  134. unstructured_ingest/cli/cmds/mongodb.py +72 -0
  135. unstructured_ingest/cli/cmds/notion.py +48 -0
  136. unstructured_ingest/cli/cmds/onedrive.py +66 -0
  137. unstructured_ingest/cli/cmds/opensearch.py +117 -0
  138. unstructured_ingest/cli/cmds/outlook.py +67 -0
  139. unstructured_ingest/cli/cmds/pinecone.py +71 -0
  140. unstructured_ingest/cli/cmds/qdrant.py +124 -0
  141. unstructured_ingest/cli/cmds/reddit.py +67 -0
  142. unstructured_ingest/cli/cmds/salesforce.py +58 -0
  143. unstructured_ingest/cli/cmds/sharepoint.py +66 -0
  144. unstructured_ingest/cli/cmds/slack.py +56 -0
  145. unstructured_ingest/cli/cmds/sql.py +66 -0
  146. unstructured_ingest/cli/cmds/vectara.py +66 -0
  147. unstructured_ingest/cli/cmds/weaviate.py +98 -0
  148. unstructured_ingest/cli/cmds/wikipedia.py +40 -0
  149. unstructured_ingest/cli/common.py +7 -0
  150. unstructured_ingest/cli/interfaces.py +663 -0
  151. unstructured_ingest/cli/utils.py +205 -0
  152. unstructured_ingest/connector/__init__.py +0 -0
  153. unstructured_ingest/connector/airtable.py +309 -0
  154. unstructured_ingest/connector/astradb.py +267 -0
  155. unstructured_ingest/connector/azure_ai_search.py +144 -0
  156. unstructured_ingest/connector/biomed.py +320 -0
  157. unstructured_ingest/connector/chroma.py +158 -0
  158. unstructured_ingest/connector/clarifai.py +122 -0
  159. unstructured_ingest/connector/confluence.py +285 -0
  160. unstructured_ingest/connector/databricks_volumes.py +137 -0
  161. unstructured_ingest/connector/delta_table.py +203 -0
  162. unstructured_ingest/connector/discord.py +180 -0
  163. unstructured_ingest/connector/elasticsearch.py +396 -0
  164. unstructured_ingest/connector/fsspec/__init__.py +0 -0
  165. unstructured_ingest/connector/fsspec/azure.py +78 -0
  166. unstructured_ingest/connector/fsspec/box.py +109 -0
  167. unstructured_ingest/connector/fsspec/dropbox.py +160 -0
  168. unstructured_ingest/connector/fsspec/fsspec.py +359 -0
  169. unstructured_ingest/connector/fsspec/gcs.py +82 -0
  170. unstructured_ingest/connector/fsspec/s3.py +62 -0
  171. unstructured_ingest/connector/fsspec/sftp.py +81 -0
  172. unstructured_ingest/connector/git.py +124 -0
  173. unstructured_ingest/connector/github.py +174 -0
  174. unstructured_ingest/connector/gitlab.py +142 -0
  175. unstructured_ingest/connector/google_drive.py +348 -0
  176. unstructured_ingest/connector/hubspot.py +278 -0
  177. unstructured_ingest/connector/jira.py +469 -0
  178. unstructured_ingest/connector/kafka.py +293 -0
  179. unstructured_ingest/connector/local.py +139 -0
  180. unstructured_ingest/connector/mongodb.py +284 -0
  181. unstructured_ingest/connector/notion/__init__.py +0 -0
  182. unstructured_ingest/connector/notion/client.py +248 -0
  183. unstructured_ingest/connector/notion/connector.py +469 -0
  184. unstructured_ingest/connector/notion/helpers.py +584 -0
  185. unstructured_ingest/connector/notion/interfaces.py +32 -0
  186. unstructured_ingest/connector/notion/types/__init__.py +0 -0
  187. unstructured_ingest/connector/notion/types/block.py +96 -0
  188. unstructured_ingest/connector/notion/types/blocks/__init__.py +63 -0
  189. unstructured_ingest/connector/notion/types/blocks/bookmark.py +40 -0
  190. unstructured_ingest/connector/notion/types/blocks/breadcrumb.py +21 -0
  191. unstructured_ingest/connector/notion/types/blocks/bulleted_list_item.py +31 -0
  192. unstructured_ingest/connector/notion/types/blocks/callout.py +94 -0
  193. unstructured_ingest/connector/notion/types/blocks/child_database.py +23 -0
  194. unstructured_ingest/connector/notion/types/blocks/child_page.py +23 -0
  195. unstructured_ingest/connector/notion/types/blocks/code.py +43 -0
  196. unstructured_ingest/connector/notion/types/blocks/column_list.py +35 -0
  197. unstructured_ingest/connector/notion/types/blocks/divider.py +22 -0
  198. unstructured_ingest/connector/notion/types/blocks/embed.py +36 -0
  199. unstructured_ingest/connector/notion/types/blocks/equation.py +23 -0
  200. unstructured_ingest/connector/notion/types/blocks/file.py +49 -0
  201. unstructured_ingest/connector/notion/types/blocks/heading.py +37 -0
  202. unstructured_ingest/connector/notion/types/blocks/image.py +21 -0
  203. unstructured_ingest/connector/notion/types/blocks/link_preview.py +24 -0
  204. unstructured_ingest/connector/notion/types/blocks/link_to_page.py +29 -0
  205. unstructured_ingest/connector/notion/types/blocks/numbered_list.py +29 -0
  206. unstructured_ingest/connector/notion/types/blocks/paragraph.py +31 -0
  207. unstructured_ingest/connector/notion/types/blocks/pdf.py +49 -0
  208. unstructured_ingest/connector/notion/types/blocks/quote.py +37 -0
  209. unstructured_ingest/connector/notion/types/blocks/synced_block.py +57 -0
  210. unstructured_ingest/connector/notion/types/blocks/table.py +63 -0
  211. unstructured_ingest/connector/notion/types/blocks/table_of_contents.py +23 -0
  212. unstructured_ingest/connector/notion/types/blocks/template.py +30 -0
  213. unstructured_ingest/connector/notion/types/blocks/todo.py +42 -0
  214. unstructured_ingest/connector/notion/types/blocks/toggle.py +37 -0
  215. unstructured_ingest/connector/notion/types/blocks/unsupported.py +20 -0
  216. unstructured_ingest/connector/notion/types/blocks/video.py +22 -0
  217. unstructured_ingest/connector/notion/types/database.py +73 -0
  218. unstructured_ingest/connector/notion/types/database_properties/__init__.py +106 -0
  219. unstructured_ingest/connector/notion/types/database_properties/checkbox.py +38 -0
  220. unstructured_ingest/connector/notion/types/database_properties/created_by.py +35 -0
  221. unstructured_ingest/connector/notion/types/database_properties/created_time.py +34 -0
  222. unstructured_ingest/connector/notion/types/database_properties/date.py +41 -0
  223. unstructured_ingest/connector/notion/types/database_properties/email.py +36 -0
  224. unstructured_ingest/connector/notion/types/database_properties/files.py +37 -0
  225. unstructured_ingest/connector/notion/types/database_properties/formula.py +49 -0
  226. unstructured_ingest/connector/notion/types/database_properties/last_edited_by.py +34 -0
  227. unstructured_ingest/connector/notion/types/database_properties/last_edited_time.py +34 -0
  228. unstructured_ingest/connector/notion/types/database_properties/multiselect.py +73 -0
  229. unstructured_ingest/connector/notion/types/database_properties/number.py +49 -0
  230. unstructured_ingest/connector/notion/types/database_properties/people.py +40 -0
  231. unstructured_ingest/connector/notion/types/database_properties/phone_number.py +36 -0
  232. unstructured_ingest/connector/notion/types/database_properties/relation.py +67 -0
  233. unstructured_ingest/connector/notion/types/database_properties/rich_text.py +43 -0
  234. unstructured_ingest/connector/notion/types/database_properties/rollup.py +56 -0
  235. unstructured_ingest/connector/notion/types/database_properties/select.py +68 -0
  236. unstructured_ingest/connector/notion/types/database_properties/status.py +80 -0
  237. unstructured_ingest/connector/notion/types/database_properties/title.py +37 -0
  238. unstructured_ingest/connector/notion/types/database_properties/unique_id.py +50 -0
  239. unstructured_ingest/connector/notion/types/database_properties/url.py +37 -0
  240. unstructured_ingest/connector/notion/types/database_properties/verification.py +78 -0
  241. unstructured_ingest/connector/notion/types/date.py +26 -0
  242. unstructured_ingest/connector/notion/types/file.py +51 -0
  243. unstructured_ingest/connector/notion/types/page.py +45 -0
  244. unstructured_ingest/connector/notion/types/parent.py +66 -0
  245. unstructured_ingest/connector/notion/types/rich_text.py +189 -0
  246. unstructured_ingest/connector/notion/types/user.py +76 -0
  247. unstructured_ingest/connector/onedrive.py +232 -0
  248. unstructured_ingest/connector/opensearch.py +218 -0
  249. unstructured_ingest/connector/outlook.py +285 -0
  250. unstructured_ingest/connector/pinecone.py +140 -0
  251. unstructured_ingest/connector/qdrant.py +144 -0
  252. unstructured_ingest/connector/reddit.py +166 -0
  253. unstructured_ingest/connector/registry.py +109 -0
  254. unstructured_ingest/connector/salesforce.py +301 -0
  255. unstructured_ingest/connector/sharepoint.py +573 -0
  256. unstructured_ingest/connector/slack.py +224 -0
  257. unstructured_ingest/connector/sql.py +199 -0
  258. unstructured_ingest/connector/vectara.py +253 -0
  259. unstructured_ingest/connector/weaviate.py +190 -0
  260. unstructured_ingest/connector/wikipedia.py +208 -0
  261. unstructured_ingest/embed/__init__.py +0 -0
  262. unstructured_ingest/embed/azure_openai.py +31 -0
  263. unstructured_ingest/embed/bedrock.py +193 -0
  264. unstructured_ingest/embed/huggingface.py +52 -0
  265. unstructured_ingest/embed/interfaces.py +117 -0
  266. unstructured_ingest/embed/mixedbreadai.py +233 -0
  267. unstructured_ingest/embed/octoai.py +130 -0
  268. unstructured_ingest/embed/openai.py +116 -0
  269. unstructured_ingest/embed/togetherai.py +106 -0
  270. unstructured_ingest/embed/vertexai.py +126 -0
  271. unstructured_ingest/embed/voyageai.py +130 -0
  272. unstructured_ingest/enhanced_dataclass/__init__.py +4 -0
  273. unstructured_ingest/enhanced_dataclass/core.py +99 -0
  274. unstructured_ingest/enhanced_dataclass/dataclasses.py +54 -0
  275. unstructured_ingest/enhanced_dataclass/json_mixin.py +125 -0
  276. unstructured_ingest/error.py +49 -0
  277. unstructured_ingest/ingest_backoff/__init__.py +3 -0
  278. unstructured_ingest/ingest_backoff/_common.py +102 -0
  279. unstructured_ingest/ingest_backoff/_wrapper.py +122 -0
  280. unstructured_ingest/interfaces.py +852 -0
  281. unstructured_ingest/logger.py +130 -0
  282. unstructured_ingest/main.py +11 -0
  283. unstructured_ingest/pipeline/__init__.py +22 -0
  284. unstructured_ingest/pipeline/copy.py +19 -0
  285. unstructured_ingest/pipeline/doc_factory.py +12 -0
  286. unstructured_ingest/pipeline/interfaces.py +270 -0
  287. unstructured_ingest/pipeline/partition.py +60 -0
  288. unstructured_ingest/pipeline/permissions.py +12 -0
  289. unstructured_ingest/pipeline/pipeline.py +117 -0
  290. unstructured_ingest/pipeline/reformat/__init__.py +0 -0
  291. unstructured_ingest/pipeline/reformat/chunking.py +134 -0
  292. unstructured_ingest/pipeline/reformat/embedding.py +64 -0
  293. unstructured_ingest/pipeline/source.py +77 -0
  294. unstructured_ingest/pipeline/utils.py +6 -0
  295. unstructured_ingest/pipeline/write.py +18 -0
  296. unstructured_ingest/processor.py +93 -0
  297. unstructured_ingest/runner/__init__.py +104 -0
  298. unstructured_ingest/runner/airtable.py +35 -0
  299. unstructured_ingest/runner/astradb.py +34 -0
  300. unstructured_ingest/runner/base_runner.py +89 -0
  301. unstructured_ingest/runner/biomed.py +45 -0
  302. unstructured_ingest/runner/confluence.py +35 -0
  303. unstructured_ingest/runner/delta_table.py +34 -0
  304. unstructured_ingest/runner/discord.py +35 -0
  305. unstructured_ingest/runner/elasticsearch.py +40 -0
  306. unstructured_ingest/runner/fsspec/__init__.py +0 -0
  307. unstructured_ingest/runner/fsspec/azure.py +30 -0
  308. unstructured_ingest/runner/fsspec/box.py +28 -0
  309. unstructured_ingest/runner/fsspec/dropbox.py +30 -0
  310. unstructured_ingest/runner/fsspec/fsspec.py +40 -0
  311. unstructured_ingest/runner/fsspec/gcs.py +28 -0
  312. unstructured_ingest/runner/fsspec/s3.py +28 -0
  313. unstructured_ingest/runner/fsspec/sftp.py +28 -0
  314. unstructured_ingest/runner/github.py +37 -0
  315. unstructured_ingest/runner/gitlab.py +37 -0
  316. unstructured_ingest/runner/google_drive.py +35 -0
  317. unstructured_ingest/runner/hubspot.py +35 -0
  318. unstructured_ingest/runner/jira.py +35 -0
  319. unstructured_ingest/runner/kafka.py +34 -0
  320. unstructured_ingest/runner/local.py +23 -0
  321. unstructured_ingest/runner/mongodb.py +34 -0
  322. unstructured_ingest/runner/notion.py +61 -0
  323. unstructured_ingest/runner/onedrive.py +35 -0
  324. unstructured_ingest/runner/opensearch.py +40 -0
  325. unstructured_ingest/runner/outlook.py +33 -0
  326. unstructured_ingest/runner/reddit.py +35 -0
  327. unstructured_ingest/runner/salesforce.py +33 -0
  328. unstructured_ingest/runner/sharepoint.py +35 -0
  329. unstructured_ingest/runner/slack.py +33 -0
  330. unstructured_ingest/runner/utils.py +47 -0
  331. unstructured_ingest/runner/wikipedia.py +35 -0
  332. unstructured_ingest/runner/writers/__init__.py +48 -0
  333. unstructured_ingest/runner/writers/astradb.py +22 -0
  334. unstructured_ingest/runner/writers/azure_ai_search.py +24 -0
  335. unstructured_ingest/runner/writers/base_writer.py +26 -0
  336. unstructured_ingest/runner/writers/chroma.py +22 -0
  337. unstructured_ingest/runner/writers/clarifai.py +19 -0
  338. unstructured_ingest/runner/writers/databricks_volumes.py +25 -0
  339. unstructured_ingest/runner/writers/delta_table.py +24 -0
  340. unstructured_ingest/runner/writers/elasticsearch.py +24 -0
  341. unstructured_ingest/runner/writers/fsspec/__init__.py +0 -0
  342. unstructured_ingest/runner/writers/fsspec/azure.py +24 -0
  343. unstructured_ingest/runner/writers/fsspec/box.py +21 -0
  344. unstructured_ingest/runner/writers/fsspec/dropbox.py +21 -0
  345. unstructured_ingest/runner/writers/fsspec/gcs.py +19 -0
  346. unstructured_ingest/runner/writers/fsspec/s3.py +21 -0
  347. unstructured_ingest/runner/writers/kafka.py +21 -0
  348. unstructured_ingest/runner/writers/mongodb.py +21 -0
  349. unstructured_ingest/runner/writers/opensearch.py +26 -0
  350. unstructured_ingest/runner/writers/pinecone.py +21 -0
  351. unstructured_ingest/runner/writers/qdrant.py +19 -0
  352. unstructured_ingest/runner/writers/sql.py +22 -0
  353. unstructured_ingest/runner/writers/vectara.py +22 -0
  354. unstructured_ingest/runner/writers/weaviate.py +21 -0
  355. unstructured_ingest/utils/__init__.py +0 -0
  356. unstructured_ingest/utils/chunking.py +56 -0
  357. unstructured_ingest/utils/compression.py +118 -0
  358. unstructured_ingest/utils/data_prep.py +200 -0
  359. unstructured_ingest/utils/dep_check.py +78 -0
  360. unstructured_ingest/utils/google_filetype.py +9 -0
  361. unstructured_ingest/utils/string_and_date_utils.py +49 -0
  362. unstructured_ingest/utils/table.py +73 -0
  363. unstructured_ingest/v2/__init__.py +1 -0
  364. unstructured_ingest/v2/cli/__init__.py +0 -0
  365. unstructured_ingest/v2/cli/base/__init__.py +4 -0
  366. unstructured_ingest/v2/cli/base/cmd.py +269 -0
  367. unstructured_ingest/v2/cli/base/dest.py +85 -0
  368. unstructured_ingest/v2/cli/base/importer.py +34 -0
  369. unstructured_ingest/v2/cli/base/src.py +85 -0
  370. unstructured_ingest/v2/cli/cli.py +24 -0
  371. unstructured_ingest/v2/cli/cmds.py +14 -0
  372. unstructured_ingest/v2/cli/utils/__init__.py +0 -0
  373. unstructured_ingest/v2/cli/utils/click.py +237 -0
  374. unstructured_ingest/v2/cli/utils/model_conversion.py +222 -0
  375. unstructured_ingest/v2/constants.py +2 -0
  376. unstructured_ingest/v2/errors.py +18 -0
  377. unstructured_ingest/v2/interfaces/__init__.py +32 -0
  378. unstructured_ingest/v2/interfaces/connector.py +50 -0
  379. unstructured_ingest/v2/interfaces/downloader.py +89 -0
  380. unstructured_ingest/v2/interfaces/file_data.py +116 -0
  381. unstructured_ingest/v2/interfaces/indexer.py +30 -0
  382. unstructured_ingest/v2/interfaces/process.py +19 -0
  383. unstructured_ingest/v2/interfaces/processor.py +88 -0
  384. unstructured_ingest/v2/interfaces/upload_stager.py +102 -0
  385. unstructured_ingest/v2/interfaces/uploader.py +53 -0
  386. unstructured_ingest/v2/logger.py +126 -0
  387. unstructured_ingest/v2/main.py +11 -0
  388. unstructured_ingest/v2/otel.py +111 -0
  389. unstructured_ingest/v2/pipeline/__init__.py +0 -0
  390. unstructured_ingest/v2/pipeline/interfaces.py +211 -0
  391. unstructured_ingest/v2/pipeline/otel.py +32 -0
  392. unstructured_ingest/v2/pipeline/pipeline.py +384 -0
  393. unstructured_ingest/v2/pipeline/steps/__init__.py +0 -0
  394. unstructured_ingest/v2/pipeline/steps/chunk.py +80 -0
  395. unstructured_ingest/v2/pipeline/steps/download.py +207 -0
  396. unstructured_ingest/v2/pipeline/steps/embed.py +79 -0
  397. unstructured_ingest/v2/pipeline/steps/filter.py +35 -0
  398. unstructured_ingest/v2/pipeline/steps/index.py +86 -0
  399. unstructured_ingest/v2/pipeline/steps/partition.py +79 -0
  400. unstructured_ingest/v2/pipeline/steps/stage.py +65 -0
  401. unstructured_ingest/v2/pipeline/steps/uncompress.py +50 -0
  402. unstructured_ingest/v2/pipeline/steps/upload.py +58 -0
  403. unstructured_ingest/v2/processes/__init__.py +18 -0
  404. unstructured_ingest/v2/processes/chunker.py +124 -0
  405. unstructured_ingest/v2/processes/connector_registry.py +69 -0
  406. unstructured_ingest/v2/processes/connectors/__init__.py +117 -0
  407. unstructured_ingest/v2/processes/connectors/airtable.py +235 -0
  408. unstructured_ingest/v2/processes/connectors/astradb.py +402 -0
  409. unstructured_ingest/v2/processes/connectors/azure_ai_search.py +276 -0
  410. unstructured_ingest/v2/processes/connectors/chroma.py +190 -0
  411. unstructured_ingest/v2/processes/connectors/confluence.py +207 -0
  412. unstructured_ingest/v2/processes/connectors/couchbase.py +334 -0
  413. unstructured_ingest/v2/processes/connectors/databricks/__init__.py +52 -0
  414. unstructured_ingest/v2/processes/connectors/databricks/volumes.py +208 -0
  415. unstructured_ingest/v2/processes/connectors/databricks/volumes_aws.py +87 -0
  416. unstructured_ingest/v2/processes/connectors/databricks/volumes_azure.py +102 -0
  417. unstructured_ingest/v2/processes/connectors/databricks/volumes_gcp.py +85 -0
  418. unstructured_ingest/v2/processes/connectors/databricks/volumes_native.py +86 -0
  419. unstructured_ingest/v2/processes/connectors/delta_table.py +191 -0
  420. unstructured_ingest/v2/processes/connectors/discord.py +158 -0
  421. unstructured_ingest/v2/processes/connectors/duckdb/__init__.py +15 -0
  422. unstructured_ingest/v2/processes/connectors/duckdb/base.py +100 -0
  423. unstructured_ingest/v2/processes/connectors/duckdb/duckdb.py +127 -0
  424. unstructured_ingest/v2/processes/connectors/duckdb/motherduck.py +126 -0
  425. unstructured_ingest/v2/processes/connectors/elasticsearch/__init__.py +19 -0
  426. unstructured_ingest/v2/processes/connectors/elasticsearch/elasticsearch.py +470 -0
  427. unstructured_ingest/v2/processes/connectors/elasticsearch/opensearch.py +195 -0
  428. unstructured_ingest/v2/processes/connectors/fsspec/__init__.py +37 -0
  429. unstructured_ingest/v2/processes/connectors/fsspec/azure.py +197 -0
  430. unstructured_ingest/v2/processes/connectors/fsspec/box.py +170 -0
  431. unstructured_ingest/v2/processes/connectors/fsspec/dropbox.py +168 -0
  432. unstructured_ingest/v2/processes/connectors/fsspec/fsspec.py +332 -0
  433. unstructured_ingest/v2/processes/connectors/fsspec/gcs.py +197 -0
  434. unstructured_ingest/v2/processes/connectors/fsspec/s3.py +185 -0
  435. unstructured_ingest/v2/processes/connectors/fsspec/sftp.py +171 -0
  436. unstructured_ingest/v2/processes/connectors/fsspec/utils.py +17 -0
  437. unstructured_ingest/v2/processes/connectors/gitlab.py +268 -0
  438. unstructured_ingest/v2/processes/connectors/google_drive.py +348 -0
  439. unstructured_ingest/v2/processes/connectors/kafka/__init__.py +17 -0
  440. unstructured_ingest/v2/processes/connectors/kafka/cloud.py +121 -0
  441. unstructured_ingest/v2/processes/connectors/kafka/kafka.py +273 -0
  442. unstructured_ingest/v2/processes/connectors/kafka/local.py +103 -0
  443. unstructured_ingest/v2/processes/connectors/kdbai.py +148 -0
  444. unstructured_ingest/v2/processes/connectors/lancedb/__init__.py +30 -0
  445. unstructured_ingest/v2/processes/connectors/lancedb/aws.py +43 -0
  446. unstructured_ingest/v2/processes/connectors/lancedb/azure.py +43 -0
  447. unstructured_ingest/v2/processes/connectors/lancedb/cloud.py +42 -0
  448. unstructured_ingest/v2/processes/connectors/lancedb/gcp.py +44 -0
  449. unstructured_ingest/v2/processes/connectors/lancedb/lancedb.py +169 -0
  450. unstructured_ingest/v2/processes/connectors/lancedb/local.py +44 -0
  451. unstructured_ingest/v2/processes/connectors/local.py +217 -0
  452. unstructured_ingest/v2/processes/connectors/milvus.py +225 -0
  453. unstructured_ingest/v2/processes/connectors/mongodb.py +361 -0
  454. unstructured_ingest/v2/processes/connectors/neo4j.py +385 -0
  455. unstructured_ingest/v2/processes/connectors/notion/__init__.py +0 -0
  456. unstructured_ingest/v2/processes/connectors/notion/client.py +349 -0
  457. unstructured_ingest/v2/processes/connectors/notion/connector.py +346 -0
  458. unstructured_ingest/v2/processes/connectors/notion/helpers.py +448 -0
  459. unstructured_ingest/v2/processes/connectors/notion/interfaces.py +32 -0
  460. unstructured_ingest/v2/processes/connectors/notion/types/__init__.py +0 -0
  461. unstructured_ingest/v2/processes/connectors/notion/types/block.py +96 -0
  462. unstructured_ingest/v2/processes/connectors/notion/types/blocks/__init__.py +63 -0
  463. unstructured_ingest/v2/processes/connectors/notion/types/blocks/bookmark.py +40 -0
  464. unstructured_ingest/v2/processes/connectors/notion/types/blocks/breadcrumb.py +21 -0
  465. unstructured_ingest/v2/processes/connectors/notion/types/blocks/bulleted_list_item.py +31 -0
  466. unstructured_ingest/v2/processes/connectors/notion/types/blocks/callout.py +94 -0
  467. unstructured_ingest/v2/processes/connectors/notion/types/blocks/child_database.py +23 -0
  468. unstructured_ingest/v2/processes/connectors/notion/types/blocks/child_page.py +23 -0
  469. unstructured_ingest/v2/processes/connectors/notion/types/blocks/code.py +43 -0
  470. unstructured_ingest/v2/processes/connectors/notion/types/blocks/column_list.py +35 -0
  471. unstructured_ingest/v2/processes/connectors/notion/types/blocks/divider.py +22 -0
  472. unstructured_ingest/v2/processes/connectors/notion/types/blocks/embed.py +36 -0
  473. unstructured_ingest/v2/processes/connectors/notion/types/blocks/equation.py +23 -0
  474. unstructured_ingest/v2/processes/connectors/notion/types/blocks/file.py +49 -0
  475. unstructured_ingest/v2/processes/connectors/notion/types/blocks/heading.py +37 -0
  476. unstructured_ingest/v2/processes/connectors/notion/types/blocks/image.py +21 -0
  477. unstructured_ingest/v2/processes/connectors/notion/types/blocks/link_preview.py +24 -0
  478. unstructured_ingest/v2/processes/connectors/notion/types/blocks/link_to_page.py +29 -0
  479. unstructured_ingest/v2/processes/connectors/notion/types/blocks/numbered_list.py +29 -0
  480. unstructured_ingest/v2/processes/connectors/notion/types/blocks/paragraph.py +31 -0
  481. unstructured_ingest/v2/processes/connectors/notion/types/blocks/pdf.py +49 -0
  482. unstructured_ingest/v2/processes/connectors/notion/types/blocks/quote.py +37 -0
  483. unstructured_ingest/v2/processes/connectors/notion/types/blocks/synced_block.py +57 -0
  484. unstructured_ingest/v2/processes/connectors/notion/types/blocks/table.py +63 -0
  485. unstructured_ingest/v2/processes/connectors/notion/types/blocks/table_of_contents.py +23 -0
  486. unstructured_ingest/v2/processes/connectors/notion/types/blocks/template.py +30 -0
  487. unstructured_ingest/v2/processes/connectors/notion/types/blocks/todo.py +42 -0
  488. unstructured_ingest/v2/processes/connectors/notion/types/blocks/toggle.py +37 -0
  489. unstructured_ingest/v2/processes/connectors/notion/types/blocks/unsupported.py +20 -0
  490. unstructured_ingest/v2/processes/connectors/notion/types/blocks/video.py +22 -0
  491. unstructured_ingest/v2/processes/connectors/notion/types/database.py +73 -0
  492. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/__init__.py +106 -0
  493. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/checkbox.py +38 -0
  494. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/created_by.py +35 -0
  495. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/created_time.py +34 -0
  496. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/date.py +41 -0
  497. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/email.py +36 -0
  498. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/files.py +37 -0
  499. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/formula.py +49 -0
  500. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/last_edited_by.py +34 -0
  501. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/last_edited_time.py +34 -0
  502. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/multiselect.py +73 -0
  503. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/number.py +49 -0
  504. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/people.py +41 -0
  505. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/phone_number.py +36 -0
  506. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/relation.py +67 -0
  507. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/rich_text.py +43 -0
  508. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/rollup.py +56 -0
  509. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/select.py +69 -0
  510. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/status.py +81 -0
  511. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/title.py +37 -0
  512. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/unique_id.py +50 -0
  513. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/url.py +37 -0
  514. unstructured_ingest/v2/processes/connectors/notion/types/database_properties/verification.py +78 -0
  515. unstructured_ingest/v2/processes/connectors/notion/types/date.py +29 -0
  516. unstructured_ingest/v2/processes/connectors/notion/types/file.py +54 -0
  517. unstructured_ingest/v2/processes/connectors/notion/types/page.py +45 -0
  518. unstructured_ingest/v2/processes/connectors/notion/types/parent.py +66 -0
  519. unstructured_ingest/v2/processes/connectors/notion/types/rich_text.py +189 -0
  520. unstructured_ingest/v2/processes/connectors/notion/types/user.py +79 -0
  521. unstructured_ingest/v2/processes/connectors/onedrive.py +447 -0
  522. unstructured_ingest/v2/processes/connectors/outlook.py +239 -0
  523. unstructured_ingest/v2/processes/connectors/pinecone.py +277 -0
  524. unstructured_ingest/v2/processes/connectors/qdrant/__init__.py +16 -0
  525. unstructured_ingest/v2/processes/connectors/qdrant/cloud.py +59 -0
  526. unstructured_ingest/v2/processes/connectors/qdrant/local.py +58 -0
  527. unstructured_ingest/v2/processes/connectors/qdrant/qdrant.py +160 -0
  528. unstructured_ingest/v2/processes/connectors/qdrant/server.py +60 -0
  529. unstructured_ingest/v2/processes/connectors/redisdb.py +182 -0
  530. unstructured_ingest/v2/processes/connectors/salesforce.py +303 -0
  531. unstructured_ingest/v2/processes/connectors/sharepoint.py +448 -0
  532. unstructured_ingest/v2/processes/connectors/slack.py +248 -0
  533. unstructured_ingest/v2/processes/connectors/sql/__init__.py +27 -0
  534. unstructured_ingest/v2/processes/connectors/sql/postgres.py +162 -0
  535. unstructured_ingest/v2/processes/connectors/sql/singlestore.py +166 -0
  536. unstructured_ingest/v2/processes/connectors/sql/snowflake.py +210 -0
  537. unstructured_ingest/v2/processes/connectors/sql/sql.py +434 -0
  538. unstructured_ingest/v2/processes/connectors/sql/sqlite.py +168 -0
  539. unstructured_ingest/v2/processes/connectors/utils.py +29 -0
  540. unstructured_ingest/v2/processes/connectors/vectara.py +350 -0
  541. unstructured_ingest/v2/processes/connectors/weaviate/__init__.py +22 -0
  542. unstructured_ingest/v2/processes/connectors/weaviate/cloud.py +165 -0
  543. unstructured_ingest/v2/processes/connectors/weaviate/embedded.py +90 -0
  544. unstructured_ingest/v2/processes/connectors/weaviate/local.py +73 -0
  545. unstructured_ingest/v2/processes/connectors/weaviate/weaviate.py +267 -0
  546. unstructured_ingest/v2/processes/embedder.py +195 -0
  547. unstructured_ingest/v2/processes/filter.py +60 -0
  548. unstructured_ingest/v2/processes/partitioner.py +188 -0
  549. unstructured_ingest/v2/processes/uncompress.py +61 -0
  550. unstructured_ingest/v2/unstructured_api.py +128 -0
  551. unstructured_ingest/v2/utils.py +61 -0
  552. unstructured_ingest-0.3.13.dist-info/LICENSE.md +201 -0
  553. unstructured_ingest-0.3.13.dist-info/METADATA +205 -0
  554. unstructured_ingest-0.3.13.dist-info/RECORD +557 -0
  555. unstructured_ingest-0.3.13.dist-info/WHEEL +5 -0
  556. unstructured_ingest-0.3.13.dist-info/entry_points.txt +2 -0
  557. unstructured_ingest-0.3.13.dist-info/top_level.txt +2 -0
@@ -0,0 +1,162 @@
1
+ import json
2
+ import sqlite3
3
+ import tempfile
4
+ from pathlib import Path
5
+
6
+ import pytest
7
+ from _pytest.fixtures import TopRequest
8
+
9
+ from test.integration.connectors.utils.constants import DESTINATION_TAG, SOURCE_TAG, env_setup_path
10
+ from test.integration.connectors.utils.validation.destination import (
11
+ StagerValidationConfigs,
12
+ stager_validation,
13
+ )
14
+ from test.integration.connectors.utils.validation.source import (
15
+ SourceValidationConfigs,
16
+ source_connector_validation,
17
+ )
18
+ from unstructured_ingest.v2.interfaces import FileData, SourceIdentifiers
19
+ from unstructured_ingest.v2.processes.connectors.sql.sqlite import (
20
+ CONNECTOR_TYPE,
21
+ SQLiteConnectionConfig,
22
+ SQLiteDownloader,
23
+ SQLiteDownloaderConfig,
24
+ SQLiteIndexer,
25
+ SQLiteIndexerConfig,
26
+ SQLiteUploader,
27
+ SQLiteUploadStager,
28
+ )
29
+
30
+ SEED_DATA_ROWS = 10
31
+
32
+
33
+ @pytest.fixture
34
+ def source_database_setup() -> Path:
35
+ with tempfile.TemporaryDirectory() as tmpdir:
36
+ db_path = Path(tmpdir) / "mock_database.db"
37
+ db_init_path = env_setup_path / "sql" / "sqlite" / "source" / "sqlite-schema.sql"
38
+ assert db_init_path.exists()
39
+ assert db_init_path.is_file()
40
+ with sqlite3.connect(database=db_path) as sqlite_connection:
41
+ cursor = sqlite_connection.cursor()
42
+ with db_init_path.open("r") as f:
43
+ query = f.read()
44
+ cursor.executescript(query)
45
+ for i in range(SEED_DATA_ROWS):
46
+ sql_statment = f"INSERT INTO cars (brand, price) " f"VALUES ('brand{i}', {i})"
47
+ cursor.execute(sql_statment)
48
+
49
+ sqlite_connection.commit()
50
+ cursor.close()
51
+ yield db_path
52
+
53
+
54
+ @pytest.mark.asyncio
55
+ @pytest.mark.tags(CONNECTOR_TYPE, SOURCE_TAG, "sql")
56
+ async def test_sqlite_source(source_database_setup: Path, temp_dir: Path):
57
+ connection_config = SQLiteConnectionConfig(database_path=source_database_setup)
58
+ indexer = SQLiteIndexer(
59
+ connection_config=connection_config,
60
+ index_config=SQLiteIndexerConfig(table_name="cars", id_column="car_id", batch_size=6),
61
+ )
62
+ downloader = SQLiteDownloader(
63
+ connection_config=connection_config,
64
+ download_config=SQLiteDownloaderConfig(fields=["car_id", "brand"], download_dir=temp_dir),
65
+ )
66
+ await source_connector_validation(
67
+ indexer=indexer,
68
+ downloader=downloader,
69
+ configs=SourceValidationConfigs(
70
+ test_id="sqlite",
71
+ expected_num_files=SEED_DATA_ROWS,
72
+ expected_number_indexed_file_data=2,
73
+ validate_downloaded_files=True,
74
+ ),
75
+ )
76
+
77
+
78
+ @pytest.fixture
79
+ def destination_database_setup(temp_dir: Path) -> Path:
80
+ # Provision the local file that sqlite points to to have the desired schema for the integration
81
+ # tests and make sure the file and connection get cleaned up by using a context manager.
82
+ db_path = temp_dir / "elements.db"
83
+ db_init_path = env_setup_path / "sql" / "sqlite" / "destination" / "sqlite-schema.sql"
84
+ assert db_init_path.exists()
85
+ assert db_init_path.is_file()
86
+ with sqlite3.connect(database=db_path) as sqlite_connection:
87
+ with db_init_path.open("r") as f:
88
+ query = f.read()
89
+ cursor = sqlite_connection.cursor()
90
+ cursor.executescript(query)
91
+ return db_path
92
+
93
+
94
+ def validate_destination(db_path: Path, expected_num_elements: int):
95
+ # Run the following validations:
96
+ # * Check that the number of records in the table match the expected value
97
+ connection = None
98
+ try:
99
+ connection = sqlite3.connect(database=db_path)
100
+ query = "select count(*) from elements;"
101
+ cursor = connection.cursor()
102
+ cursor.execute(query)
103
+ count = cursor.fetchone()[0]
104
+ assert (
105
+ count == expected_num_elements
106
+ ), f"dest check failed: got {count}, expected {expected_num_elements}"
107
+ finally:
108
+ if connection:
109
+ connection.close()
110
+
111
+
112
+ @pytest.mark.asyncio
113
+ @pytest.mark.tags(CONNECTOR_TYPE, DESTINATION_TAG, "sql")
114
+ async def test_sqlite_destination(
115
+ upload_file: Path, temp_dir: Path, destination_database_setup: Path
116
+ ):
117
+ # the sqlite destination connector doesn't leverage the file data but is required as an input,
118
+ # mocking it with arbitrary values to meet the base requirements:
119
+ mock_file_data = FileData(
120
+ identifier="mock file data",
121
+ connector_type=CONNECTOR_TYPE,
122
+ source_identifiers=SourceIdentifiers(filename=upload_file.name, fullpath=upload_file.name),
123
+ )
124
+ stager = SQLiteUploadStager()
125
+ staged_path = stager.run(
126
+ elements_filepath=upload_file,
127
+ file_data=mock_file_data,
128
+ output_dir=temp_dir,
129
+ output_filename=upload_file.name,
130
+ )
131
+
132
+ # The stager should append the `.json` suffix to the output filename passed in.
133
+ assert staged_path.suffix == upload_file.suffix
134
+
135
+ uploader = SQLiteUploader(
136
+ connection_config=SQLiteConnectionConfig(database_path=destination_database_setup)
137
+ )
138
+ uploader.precheck()
139
+ uploader.run(path=staged_path, file_data=mock_file_data)
140
+
141
+ with staged_path.open("r") as f:
142
+ staged_data = json.load(f)
143
+ validate_destination(db_path=destination_database_setup, expected_num_elements=len(staged_data))
144
+
145
+ uploader.run(path=staged_path, file_data=mock_file_data)
146
+ validate_destination(db_path=destination_database_setup, expected_num_elements=len(staged_data))
147
+
148
+
149
+ @pytest.mark.parametrize("upload_file_str", ["upload_file_ndjson", "upload_file"])
150
+ def test_sqlite_stager(
151
+ request: TopRequest,
152
+ upload_file_str: str,
153
+ tmp_path: Path,
154
+ ):
155
+ upload_file: Path = request.getfixturevalue(upload_file_str)
156
+ stager = SQLiteUploadStager()
157
+ stager_validation(
158
+ configs=StagerValidationConfigs(test_id=CONNECTOR_TYPE, expected_count=22),
159
+ input_file=upload_file,
160
+ stager=stager,
161
+ tmp_dir=tmp_path,
162
+ )
@@ -0,0 +1,217 @@
1
+ import json
2
+ import os
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+ from uuid import uuid4
6
+
7
+ import pytest
8
+ from _pytest.fixtures import TopRequest
9
+ from astrapy import Collection
10
+ from astrapy import DataAPIClient as AstraDBClient
11
+
12
+ from test.integration.connectors.utils.constants import DESTINATION_TAG, SOURCE_TAG
13
+ from test.integration.connectors.utils.validation.destination import (
14
+ StagerValidationConfigs,
15
+ stager_validation,
16
+ )
17
+ from test.integration.connectors.utils.validation.source import (
18
+ SourceValidationConfigs,
19
+ source_connector_validation,
20
+ )
21
+ from test.integration.utils import requires_env
22
+ from unstructured_ingest.v2.interfaces import FileData, SourceIdentifiers
23
+ from unstructured_ingest.v2.processes.connectors.astradb import (
24
+ CONNECTOR_TYPE,
25
+ AstraDBAccessConfig,
26
+ AstraDBConnectionConfig,
27
+ AstraDBDownloader,
28
+ AstraDBDownloaderConfig,
29
+ AstraDBIndexer,
30
+ AstraDBIndexerConfig,
31
+ AstraDBUploader,
32
+ AstraDBUploaderConfig,
33
+ AstraDBUploadStager,
34
+ DestinationConnectionError,
35
+ SourceConnectionError,
36
+ )
37
+
38
+ EXISTENT_COLLECTION_NAME = "ingest_test_src"
39
+ NONEXISTENT_COLLECTION_NAME = "nonexistant"
40
+
41
+
42
+ @pytest.fixture
43
+ def connection_config() -> AstraDBConnectionConfig:
44
+ return AstraDBConnectionConfig(
45
+ access_config=AstraDBAccessConfig(
46
+ token=os.environ["ASTRA_DB_APPLICATION_TOKEN"],
47
+ api_endpoint=os.environ["ASTRA_DB_API_ENDPOINT"],
48
+ )
49
+ )
50
+
51
+
52
+ @pytest.mark.tags(CONNECTOR_TYPE, SOURCE_TAG, DESTINATION_TAG)
53
+ @requires_env("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT")
54
+ def test_precheck_succeeds(connection_config: AstraDBConnectionConfig):
55
+ indexer = AstraDBIndexer(
56
+ connection_config=connection_config,
57
+ index_config=AstraDBIndexerConfig(collection_name=EXISTENT_COLLECTION_NAME),
58
+ )
59
+ uploader = AstraDBUploader(
60
+ connection_config=connection_config,
61
+ upload_config=AstraDBUploaderConfig(collection_name=EXISTENT_COLLECTION_NAME),
62
+ )
63
+ indexer.precheck()
64
+ uploader.precheck()
65
+
66
+
67
+ @pytest.mark.tags(CONNECTOR_TYPE, SOURCE_TAG, DESTINATION_TAG)
68
+ @requires_env("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT")
69
+ def test_precheck_fails(connection_config: AstraDBConnectionConfig):
70
+ indexer = AstraDBIndexer(
71
+ connection_config=connection_config,
72
+ index_config=AstraDBIndexerConfig(collection_name=NONEXISTENT_COLLECTION_NAME),
73
+ )
74
+ uploader = AstraDBUploader(
75
+ connection_config=connection_config,
76
+ upload_config=AstraDBUploaderConfig(collection_name=NONEXISTENT_COLLECTION_NAME),
77
+ )
78
+ with pytest.raises(expected_exception=SourceConnectionError):
79
+ indexer.precheck()
80
+ with pytest.raises(expected_exception=DestinationConnectionError):
81
+ uploader.precheck()
82
+
83
+
84
+ @dataclass(frozen=True)
85
+ class EnvData:
86
+ api_endpoint: str
87
+ token: str
88
+
89
+
90
+ def get_env_data() -> EnvData:
91
+ return EnvData(
92
+ api_endpoint=os.environ["ASTRA_DB_API_ENDPOINT"],
93
+ token=os.environ["ASTRA_DB_APPLICATION_TOKEN"],
94
+ )
95
+
96
+
97
+ @pytest.fixture
98
+ def collection(upload_file: Path) -> Collection:
99
+ random_id = str(uuid4())[:8]
100
+ collection_name = f"utic_test_{random_id}"
101
+ with upload_file.open("r") as upload_fp:
102
+ upload_data = json.load(upload_fp)
103
+ first_content = upload_data[0]
104
+ embeddings = first_content["embeddings"]
105
+ embedding_dimension = len(embeddings)
106
+ my_client = AstraDBClient()
107
+ env_data = get_env_data()
108
+ astra_db = my_client.get_database(
109
+ api_endpoint=env_data.api_endpoint,
110
+ token=env_data.token,
111
+ )
112
+ collection = astra_db.create_collection(collection_name, dimension=embedding_dimension)
113
+ try:
114
+ yield collection
115
+ finally:
116
+ astra_db.drop_collection(collection)
117
+
118
+
119
+ @pytest.mark.asyncio
120
+ @pytest.mark.tags(CONNECTOR_TYPE, SOURCE_TAG)
121
+ @requires_env("ASTRA_DB_API_ENDPOINT", "ASTRA_DB_APPLICATION_TOKEN")
122
+ async def test_astra_search_source(
123
+ tmp_path: Path,
124
+ ):
125
+ env_data = get_env_data()
126
+ collection_name = "ingest_test_src"
127
+ connection_config = AstraDBConnectionConfig(
128
+ access_config=AstraDBAccessConfig(token=env_data.token, api_endpoint=env_data.api_endpoint)
129
+ )
130
+ indexer = AstraDBIndexer(
131
+ index_config=AstraDBIndexerConfig(
132
+ collection_name=collection_name,
133
+ ),
134
+ connection_config=connection_config,
135
+ )
136
+ downloader = AstraDBDownloader(
137
+ connection_config=connection_config,
138
+ download_config=AstraDBDownloaderConfig(download_dir=tmp_path),
139
+ )
140
+
141
+ await source_connector_validation(
142
+ indexer=indexer,
143
+ downloader=downloader,
144
+ configs=SourceValidationConfigs(
145
+ test_id=CONNECTOR_TYPE,
146
+ expected_num_files=5,
147
+ expected_number_indexed_file_data=1,
148
+ validate_downloaded_files=True,
149
+ ),
150
+ )
151
+
152
+
153
+ @pytest.mark.asyncio
154
+ @pytest.mark.tags(CONNECTOR_TYPE, DESTINATION_TAG)
155
+ @requires_env("ASTRA_DB_API_ENDPOINT", "ASTRA_DB_APPLICATION_TOKEN")
156
+ async def test_astra_search_destination(
157
+ upload_file: Path,
158
+ collection: Collection,
159
+ tmp_path: Path,
160
+ ):
161
+ file_data = FileData(
162
+ source_identifiers=SourceIdentifiers(fullpath=upload_file.name, filename=upload_file.name),
163
+ connector_type=CONNECTOR_TYPE,
164
+ identifier="mock file data",
165
+ )
166
+ stager = AstraDBUploadStager()
167
+ env_data = get_env_data()
168
+ uploader = AstraDBUploader(
169
+ connection_config=AstraDBConnectionConfig(
170
+ access_config=AstraDBAccessConfig(
171
+ api_endpoint=env_data.api_endpoint, token=env_data.token
172
+ ),
173
+ ),
174
+ upload_config=AstraDBUploaderConfig(collection_name=collection.name),
175
+ )
176
+ staged_filepath = stager.run(
177
+ elements_filepath=upload_file,
178
+ file_data=file_data,
179
+ output_dir=tmp_path,
180
+ output_filename=upload_file.name,
181
+ )
182
+ uploader.precheck()
183
+ uploader.run(path=staged_filepath, file_data=file_data)
184
+
185
+ # Run validation
186
+ with staged_filepath.open() as f:
187
+ staged_elements = json.load(f)
188
+ expected_count = len(staged_elements)
189
+ current_count = collection.count_documents(filter={}, upper_bound=expected_count * 2)
190
+ assert current_count == expected_count, (
191
+ f"Expected count ({expected_count}) doesn't match how "
192
+ f"much came back from collection: {current_count}"
193
+ )
194
+
195
+ # Rerun and make sure the same documents get updated
196
+ uploader.run(path=staged_filepath, file_data=file_data)
197
+ current_count = collection.count_documents(filter={}, upper_bound=expected_count * 2)
198
+ assert current_count == expected_count, (
199
+ f"Expected count ({expected_count}) doesn't match how "
200
+ f"much came back from collection: {current_count}"
201
+ )
202
+
203
+
204
+ @pytest.mark.parametrize("upload_file_str", ["upload_file_ndjson", "upload_file"])
205
+ def test_astra_stager(
206
+ request: TopRequest,
207
+ upload_file_str: str,
208
+ tmp_path: Path,
209
+ ):
210
+ upload_file: Path = request.getfixturevalue(upload_file_str)
211
+ stager = AstraDBUploadStager()
212
+ stager_validation(
213
+ configs=StagerValidationConfigs(test_id=CONNECTOR_TYPE, expected_count=22),
214
+ input_file=upload_file,
215
+ stager=stager,
216
+ tmp_dir=tmp_path,
217
+ )
@@ -0,0 +1,255 @@
1
+ import json
2
+ import os
3
+ import time
4
+ from pathlib import Path
5
+ from uuid import uuid4
6
+
7
+ import pytest
8
+ from _pytest.fixtures import TopRequest
9
+ from azure.core.credentials import AzureKeyCredential
10
+ from azure.search.documents import SearchClient
11
+ from azure.search.documents.indexes import SearchIndexClient
12
+ from azure.search.documents.indexes.models import (
13
+ ComplexField,
14
+ CorsOptions,
15
+ HnswAlgorithmConfiguration,
16
+ HnswParameters,
17
+ SearchField,
18
+ SearchFieldDataType,
19
+ SearchIndex,
20
+ SimpleField,
21
+ VectorSearch,
22
+ VectorSearchAlgorithmMetric,
23
+ VectorSearchProfile,
24
+ )
25
+
26
+ from test.integration.connectors.utils.constants import (
27
+ DESTINATION_TAG,
28
+ )
29
+ from test.integration.connectors.utils.validation.destination import (
30
+ StagerValidationConfigs,
31
+ stager_validation,
32
+ )
33
+ from test.integration.utils import requires_env
34
+ from unstructured_ingest.v2.interfaces import FileData, SourceIdentifiers
35
+ from unstructured_ingest.v2.processes.connectors.azure_ai_search import (
36
+ CONNECTOR_TYPE,
37
+ RECORD_ID_LABEL,
38
+ AzureAISearchAccessConfig,
39
+ AzureAISearchConnectionConfig,
40
+ AzureAISearchUploader,
41
+ AzureAISearchUploaderConfig,
42
+ AzureAISearchUploadStager,
43
+ AzureAISearchUploadStagerConfig,
44
+ )
45
+
46
+ repo_path = Path(__file__).parent.resolve()
47
+
48
+ API_KEY = "AZURE_SEARCH_API_KEY"
49
+ ENDPOINT = "https://ingest-test-azure-cognitive-search.search.windows.net"
50
+
51
+
52
+ def get_api_key() -> str:
53
+ key = os.environ[API_KEY]
54
+ return key
55
+
56
+
57
+ def get_fields() -> list:
58
+ data_source_fields = [
59
+ SimpleField(name="url", type=SearchFieldDataType.String),
60
+ SimpleField(name="version", type=SearchFieldDataType.String),
61
+ SimpleField(name="date_created", type=SearchFieldDataType.DateTimeOffset),
62
+ SimpleField(name="date_modified", type=SearchFieldDataType.DateTimeOffset),
63
+ SimpleField(name="date_processed", type=SearchFieldDataType.DateTimeOffset),
64
+ SimpleField(name="permissions_data", type=SearchFieldDataType.String),
65
+ SimpleField(name="record_locator", type=SearchFieldDataType.String),
66
+ ]
67
+ coordinates_fields = [
68
+ SimpleField(name="system", type=SearchFieldDataType.String),
69
+ SimpleField(name="layout_width", type=SearchFieldDataType.Double),
70
+ SimpleField(name="layout_height", type=SearchFieldDataType.Double),
71
+ SimpleField(name="points", type=SearchFieldDataType.String),
72
+ ]
73
+ metadata_fields = [
74
+ SimpleField(name="orig_elements", type=SearchFieldDataType.String),
75
+ SimpleField(name="category_depth", type=SearchFieldDataType.Int32),
76
+ SimpleField(name="parent_id", type=SearchFieldDataType.String),
77
+ SimpleField(name="attached_to_filename", type=SearchFieldDataType.String),
78
+ SimpleField(name="filetype", type=SearchFieldDataType.String),
79
+ SimpleField(name="last_modified", type=SearchFieldDataType.DateTimeOffset),
80
+ SimpleField(name="is_continuation", type=SearchFieldDataType.Boolean),
81
+ SimpleField(name="file_directory", type=SearchFieldDataType.String),
82
+ SimpleField(name="filename", type=SearchFieldDataType.String),
83
+ ComplexField(name="data_source", fields=data_source_fields),
84
+ ComplexField(name="coordinates", fields=coordinates_fields),
85
+ SimpleField(
86
+ name="languages", type=SearchFieldDataType.Collection(SearchFieldDataType.String)
87
+ ),
88
+ SimpleField(name="page_number", type=SearchFieldDataType.String),
89
+ SimpleField(name="links", type=SearchFieldDataType.Collection(SearchFieldDataType.String)),
90
+ SimpleField(name="page_name", type=SearchFieldDataType.String),
91
+ SimpleField(name="url", type=SearchFieldDataType.String),
92
+ SimpleField(
93
+ name="link_urls", type=SearchFieldDataType.Collection(SearchFieldDataType.String)
94
+ ),
95
+ SimpleField(
96
+ name="link_texts", type=SearchFieldDataType.Collection(SearchFieldDataType.String)
97
+ ),
98
+ SimpleField(
99
+ name="sent_from", type=SearchFieldDataType.Collection(SearchFieldDataType.String)
100
+ ),
101
+ SimpleField(
102
+ name="sent_to", type=SearchFieldDataType.Collection(SearchFieldDataType.String)
103
+ ),
104
+ SimpleField(name="subject", type=SearchFieldDataType.String),
105
+ SimpleField(name="section", type=SearchFieldDataType.String),
106
+ SimpleField(name="header_footer_type", type=SearchFieldDataType.String),
107
+ SimpleField(
108
+ name="emphasized_text_contents",
109
+ type=SearchFieldDataType.Collection(SearchFieldDataType.String),
110
+ ),
111
+ SimpleField(
112
+ name="emphasized_text_tags",
113
+ type=SearchFieldDataType.Collection(SearchFieldDataType.String),
114
+ ),
115
+ SimpleField(name="text_as_html", type=SearchFieldDataType.String),
116
+ SimpleField(name="regex_metadata", type=SearchFieldDataType.String),
117
+ SimpleField(name="detection_class_prob", type=SearchFieldDataType.Double),
118
+ ]
119
+ fields = [
120
+ SimpleField(name="id", type=SearchFieldDataType.String, key=True),
121
+ SimpleField(name=RECORD_ID_LABEL, type=SearchFieldDataType.String, filterable=True),
122
+ SimpleField(name="element_id", type=SearchFieldDataType.String),
123
+ SimpleField(name="text", type=SearchFieldDataType.String),
124
+ SimpleField(name="type", type=SearchFieldDataType.String),
125
+ ComplexField(name="metadata", fields=metadata_fields),
126
+ SearchField(
127
+ name="embeddings",
128
+ type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
129
+ vector_search_dimensions=384,
130
+ vector_search_profile_name="embeddings-config-profile",
131
+ ),
132
+ ]
133
+ return fields
134
+
135
+
136
+ def get_vector_search() -> VectorSearch:
137
+ return VectorSearch(
138
+ algorithms=[
139
+ HnswAlgorithmConfiguration(
140
+ name="hnsw-config",
141
+ parameters=HnswParameters(
142
+ metric=VectorSearchAlgorithmMetric.COSINE,
143
+ ),
144
+ )
145
+ ],
146
+ profiles=[
147
+ VectorSearchProfile(
148
+ name="embeddings-config-profile", algorithm_configuration_name="hnsw-config"
149
+ )
150
+ ],
151
+ )
152
+
153
+
154
+ def get_search_index_client() -> SearchIndexClient:
155
+ api_key = get_api_key()
156
+ return SearchIndexClient(ENDPOINT, AzureKeyCredential(api_key))
157
+
158
+
159
+ @pytest.fixture
160
+ def index() -> str:
161
+ random_id = str(uuid4())[:8]
162
+ index_name = f"utic-test-{random_id}"
163
+ client = get_search_index_client()
164
+ index = SearchIndex(
165
+ name=index_name,
166
+ fields=get_fields(),
167
+ vector_search=get_vector_search(),
168
+ cors_options=CorsOptions(allowed_origins=["*"], max_age_in_seconds=60),
169
+ )
170
+ print(f"creating index: {index_name}")
171
+ client.create_index(index=index)
172
+ try:
173
+ yield index_name
174
+ finally:
175
+ print(f"deleting index: {index_name}")
176
+ client.delete_index(index)
177
+
178
+
179
+ def validate_count(
180
+ search_client: SearchClient, expected_count: int, retries: int = 10, interval: int = 1
181
+ ) -> None:
182
+ index_count = search_client.get_document_count()
183
+ if index_count == expected_count:
184
+ return
185
+ tries = 0
186
+ while tries < retries:
187
+ time.sleep(interval)
188
+ index_count = search_client.get_document_count()
189
+ if index_count == expected_count:
190
+ break
191
+ assert index_count == expected_count, (
192
+ f"Expected count ({expected_count}) doesn't match how "
193
+ f"much came back from index: {index_count}"
194
+ )
195
+
196
+
197
+ @pytest.mark.asyncio
198
+ @pytest.mark.tags(CONNECTOR_TYPE, DESTINATION_TAG)
199
+ @requires_env("AZURE_SEARCH_API_KEY")
200
+ async def test_azure_ai_search_destination(
201
+ upload_file: Path,
202
+ index: str,
203
+ tmp_path: Path,
204
+ ):
205
+ file_data = FileData(
206
+ source_identifiers=SourceIdentifiers(fullpath=upload_file.name, filename=upload_file.name),
207
+ connector_type=CONNECTOR_TYPE,
208
+ identifier="mock file data",
209
+ )
210
+ stager = AzureAISearchUploadStager(upload_stager_config=AzureAISearchUploadStagerConfig())
211
+
212
+ uploader = AzureAISearchUploader(
213
+ connection_config=AzureAISearchConnectionConfig(
214
+ access_config=AzureAISearchAccessConfig(key=get_api_key()),
215
+ endpoint=ENDPOINT,
216
+ index=index,
217
+ ),
218
+ upload_config=AzureAISearchUploaderConfig(),
219
+ )
220
+ staged_filepath = stager.run(
221
+ elements_filepath=upload_file,
222
+ file_data=file_data,
223
+ output_dir=tmp_path,
224
+ output_filename=upload_file.name,
225
+ )
226
+ uploader.precheck()
227
+ uploader.run(path=staged_filepath, file_data=file_data)
228
+
229
+ # Run validation
230
+ with staged_filepath.open() as f:
231
+ staged_elements = json.load(f)
232
+ expected_count = len(staged_elements)
233
+ with uploader.connection_config.get_search_client() as search_client:
234
+ validate_count(search_client=search_client, expected_count=expected_count)
235
+
236
+ # Rerun and make sure the same documents get updated
237
+ uploader.run(path=staged_filepath, file_data=file_data)
238
+ with uploader.connection_config.get_search_client() as search_client:
239
+ validate_count(search_client=search_client, expected_count=expected_count)
240
+
241
+
242
+ @pytest.mark.parametrize("upload_file_str", ["upload_file_ndjson", "upload_file"])
243
+ def test_azure_ai_search_stager(
244
+ request: TopRequest,
245
+ upload_file_str: str,
246
+ tmp_path: Path,
247
+ ):
248
+ upload_file: Path = request.getfixturevalue(upload_file_str)
249
+ stager = AzureAISearchUploadStager()
250
+ stager_validation(
251
+ configs=StagerValidationConfigs(test_id=CONNECTOR_TYPE, expected_count=22),
252
+ input_file=upload_file,
253
+ stager=stager,
254
+ tmp_dir=tmp_path,
255
+ )