cocoindex 0.1.72__tar.gz → 0.1.73__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 (291) hide show
  1. {cocoindex-0.1.72 → cocoindex-0.1.73}/Cargo.lock +1 -1
  2. {cocoindex-0.1.72 → cocoindex-0.1.73}/Cargo.toml +1 -1
  3. {cocoindex-0.1.72 → cocoindex-0.1.73}/PKG-INFO +1 -1
  4. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/data_types.mdx +2 -2
  5. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/ops/targets.md +7 -2
  6. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/README.md +6 -1
  7. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/main.py +12 -8
  8. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/convert.py +138 -95
  9. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/tests/test_convert.py +23 -2
  10. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/tests/test_typing.py +97 -207
  11. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/typing.py +173 -130
  12. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/mod.rs +0 -1
  13. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/qdrant.rs +112 -35
  14. cocoindex-0.1.72/src/llm/vertex_ai.rs +0 -1
  15. {cocoindex-0.1.72 → cocoindex-0.1.73}/.cargo/config.toml +0 -0
  16. {cocoindex-0.1.72 → cocoindex-0.1.73}/.env.lib_debug +0 -0
  17. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/ISSUE_TEMPLATE//360/237/220/233-bug-report.md" +0 -0
  18. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/ISSUE_TEMPLATE//360/237/222/241-feature-request.md" +0 -0
  19. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/scripts/update_version.sh +0 -0
  20. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/workflows/CI.yml +0 -0
  21. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/workflows/_doc_release.yml +0 -0
  22. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/workflows/_test.yml +0 -0
  23. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/workflows/docs.yml +0 -0
  24. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/workflows/format.yml +0 -0
  25. {cocoindex-0.1.72 → cocoindex-0.1.73}/.github/workflows/release.yml +0 -0
  26. {cocoindex-0.1.72 → cocoindex-0.1.73}/.gitignore +0 -0
  27. {cocoindex-0.1.72 → cocoindex-0.1.73}/.pre-commit-config.yaml +0 -0
  28. {cocoindex-0.1.72 → cocoindex-0.1.73}/CODE_OF_CONDUCT.md +0 -0
  29. {cocoindex-0.1.72 → cocoindex-0.1.73}/CONTRIBUTING.md +0 -0
  30. {cocoindex-0.1.72 → cocoindex-0.1.73}/LICENSE +0 -0
  31. {cocoindex-0.1.72 → cocoindex-0.1.73}/README.md +0 -0
  32. {cocoindex-0.1.72 → cocoindex-0.1.73}/dev/neo4j.yaml +0 -0
  33. {cocoindex-0.1.72 → cocoindex-0.1.73}/dev/postgres.yaml +0 -0
  34. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/.gitignore +0 -0
  35. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/README.md +0 -0
  36. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/about/community.md +0 -0
  37. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/about/contributing.md +0 -0
  38. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/ai/llm.mdx +0 -0
  39. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/basics.md +0 -0
  40. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/cli.mdx +0 -0
  41. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/custom_function.mdx +0 -0
  42. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/data_example.svg +0 -0
  43. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/flow_def.mdx +0 -0
  44. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/flow_example.svg +0 -0
  45. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/flow_methods.mdx +0 -0
  46. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/core/settings.mdx +0 -0
  47. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/getting_started/installation.md +0 -0
  48. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/getting_started/markdown_files.zip +0 -0
  49. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/getting_started/overview.md +0 -0
  50. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/getting_started/quickstart.md +0 -0
  51. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/ops/functions.md +0 -0
  52. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/ops/sources.md +0 -0
  53. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/query.mdx +0 -0
  54. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docs/tutorials/live_updates.md +0 -0
  55. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/docusaurus.config.ts +0 -0
  56. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/package.json +0 -0
  57. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/sidebars.ts +0 -0
  58. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/src/components/HomepageFeatures/index.tsx +0 -0
  59. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/src/components/HomepageFeatures/styles.module.css +0 -0
  60. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/src/css/custom.css +0 -0
  61. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/src/theme/Root.js +0 -0
  62. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/static/.nojekyll +0 -0
  63. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/static/img/docusaurus.png +0 -0
  64. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/static/img/favicon.ico +0 -0
  65. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/static/img/icon.svg +0 -0
  66. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/static/img/incremental-etl.gif +0 -0
  67. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/static/robots.txt +0 -0
  68. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/tsconfig.json +0 -0
  69. {cocoindex-0.1.72 → cocoindex-0.1.73}/docs/yarn.lock +0 -0
  70. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/amazon_s3_embedding/.env.example +0 -0
  71. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/amazon_s3_embedding/.gitignore +0 -0
  72. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/amazon_s3_embedding/README.md +0 -0
  73. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/amazon_s3_embedding/main.py +0 -0
  74. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/amazon_s3_embedding/pyproject.toml +0 -0
  75. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/azure_blob_embedding/.env.example +0 -0
  76. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/azure_blob_embedding/.gitignore +0 -0
  77. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/azure_blob_embedding/README.md +0 -0
  78. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/azure_blob_embedding/main.py +0 -0
  79. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/azure_blob_embedding/pyproject.toml +0 -0
  80. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/code_embedding/.env +0 -0
  81. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/code_embedding/README.md +0 -0
  82. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/code_embedding/main.py +0 -0
  83. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/code_embedding/pyproject.toml +0 -0
  84. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/docs_to_knowledge_graph/.env +0 -0
  85. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/docs_to_knowledge_graph/README.md +0 -0
  86. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/docs_to_knowledge_graph/main.py +0 -0
  87. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/docs_to_knowledge_graph/pyproject.toml +0 -0
  88. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/.env +0 -0
  89. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/images/Carter_welcomes_Reagan.jpg +0 -0
  90. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/images/Solvay_conference_1927.jpg +0 -0
  91. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/images/Steve_Jobs_and_Bill_Gates_(522695099).jpg +0 -0
  92. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/images/einplanck3.jpg +0 -0
  93. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/face_recognition/pyproject.toml +0 -0
  94. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/.dockerignore +0 -0
  95. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/.env +0 -0
  96. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/README.md +0 -0
  97. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/compose.yaml +0 -0
  98. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/dockerfile +0 -0
  99. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/files/1810.04805v2.md +0 -0
  100. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/main.py +0 -0
  101. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/fastapi_server_docker/requirements.txt +0 -0
  102. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/gdrive_text_embedding/.env.example +0 -0
  103. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/gdrive_text_embedding/.gitignore +0 -0
  104. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/gdrive_text_embedding/README.md +0 -0
  105. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/gdrive_text_embedding/main.py +0 -0
  106. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/gdrive_text_embedding/pyproject.toml +0 -0
  107. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/.env +0 -0
  108. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/README.md +0 -0
  109. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/.gitignore +0 -0
  110. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/index.html +0 -0
  111. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/package-lock.json +0 -0
  112. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/package.json +0 -0
  113. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/src/App.jsx +0 -0
  114. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/src/main.jsx +0 -0
  115. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/src/style.css +0 -0
  116. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/frontend/vite.config.js +0 -0
  117. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/img/cat1.jpeg +0 -0
  118. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/img/dog1.jpeg +0 -0
  119. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/img/elephant1.jpg +0 -0
  120. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/img/giraffe.jpg +0 -0
  121. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/main.py +0 -0
  122. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/image_search/pyproject.toml +0 -0
  123. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/live_updates/.env +0 -0
  124. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/live_updates/README.md +0 -0
  125. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/live_updates/data/bizarre_animals.md +0 -0
  126. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/live_updates/data/chunk_norris.md +0 -0
  127. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/live_updates/main.py +0 -0
  128. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/live_updates/pyproject.toml +0 -0
  129. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/.env +0 -0
  130. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/README.md +0 -0
  131. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/main.py +0 -0
  132. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/manuals/array.pdf +0 -0
  133. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/manuals/base64.pdf +0 -0
  134. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/manuals/copy.pdf +0 -0
  135. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/manuals/glob.pdf +0 -0
  136. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/manuals_llm_extraction/pyproject.toml +0 -0
  137. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/.env.example +0 -0
  138. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/.gitignore +0 -0
  139. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/README.md +0 -0
  140. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/main.py +0 -0
  141. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/papers/1706.03762v7.pdf +0 -0
  142. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/papers/1810.04805v2.pdf +0 -0
  143. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/papers/2502.06786v3.pdf +0 -0
  144. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/papers/2502.20346v1.pdf +0 -0
  145. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/paper_metadata/pyproject.toml +0 -0
  146. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/.env.example +0 -0
  147. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/README.md +0 -0
  148. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/data/README.md +0 -0
  149. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/data/patient_forms/Patient_Intake_Form_David_Artificial.docx +0 -0
  150. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/data/patient_forms/Patient_Intake_Form_Emily_Artificial.pdf +0 -0
  151. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/data/patient_forms/Patient_Intake_Form_Joe_Artificial.pdf +0 -0
  152. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/data/patient_forms/Patient_Intake_From_Jane_Artificial.docx +0 -0
  153. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/main.py +0 -0
  154. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/patient_intake_extraction/pyproject.toml +0 -0
  155. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/.env +0 -0
  156. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/README.md +0 -0
  157. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/main.py +0 -0
  158. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/pdf_files/1706.03762v7.pdf +0 -0
  159. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/pdf_files/1810.04805v2.pdf +0 -0
  160. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/pdf_files/rfc8259.pdf +0 -0
  161. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/pdf_embedding/pyproject.toml +0 -0
  162. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/.env +0 -0
  163. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/README.md +0 -0
  164. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/img/cocoinsight.png +0 -0
  165. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/img/neo4j.png +0 -0
  166. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/main.py +0 -0
  167. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p1.json +0 -0
  168. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p2.json +0 -0
  169. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p3.json +0 -0
  170. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p4.json +0 -0
  171. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p5.json +0 -0
  172. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p6.json +0 -0
  173. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p7.json +0 -0
  174. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p8.json +0 -0
  175. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/products/p9.json +0 -0
  176. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/product_recommendation/pyproject.toml +0 -0
  177. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/.env +0 -0
  178. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/README.md +0 -0
  179. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/Text_Embedding.ipynb +0 -0
  180. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/main.py +0 -0
  181. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/markdown_files/1706.03762v7.md +0 -0
  182. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/markdown_files/1810.04805v2.md +0 -0
  183. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/markdown_files/rfc8259.md +0 -0
  184. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding/pyproject.toml +0 -0
  185. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding_qdrant/.env +0 -0
  186. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding_qdrant/README.md +0 -0
  187. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding_qdrant/main.py +0 -0
  188. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding_qdrant/markdown_files/rfc8259.md +0 -0
  189. {cocoindex-0.1.72 → cocoindex-0.1.73}/examples/text_embedding_qdrant/pyproject.toml +0 -0
  190. {cocoindex-0.1.72 → cocoindex-0.1.73}/pyproject.toml +0 -0
  191. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/__init__.py +0 -0
  192. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/auth_registry.py +0 -0
  193. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/cli.py +0 -0
  194. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/flow.py +0 -0
  195. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/functions.py +0 -0
  196. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/index.py +0 -0
  197. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/lib.py +0 -0
  198. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/llm.py +0 -0
  199. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/op.py +0 -0
  200. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/py.typed +0 -0
  201. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/runtime.py +0 -0
  202. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/setting.py +0 -0
  203. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/setup.py +0 -0
  204. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/sources.py +0 -0
  205. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/targets.py +0 -0
  206. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/tests/__init__.py +0 -0
  207. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/tests/test_optional_database.py +0 -0
  208. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/tests/test_validation.py +0 -0
  209. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/utils.py +0 -0
  210. {cocoindex-0.1.72 → cocoindex-0.1.73}/python/cocoindex/validation.py +0 -0
  211. {cocoindex-0.1.72 → cocoindex-0.1.73}/ruff.toml +0 -0
  212. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/duration.rs +0 -0
  213. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/field_attrs.rs +0 -0
  214. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/json_schema.rs +0 -0
  215. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/mod.rs +0 -0
  216. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/schema.rs +0 -0
  217. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/spec.rs +0 -0
  218. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/base/value.rs +0 -0
  219. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/builder/analyzed_flow.rs +0 -0
  220. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/builder/analyzer.rs +0 -0
  221. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/builder/exec_ctx.rs +0 -0
  222. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/builder/flow_builder.rs +0 -0
  223. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/builder/mod.rs +0 -0
  224. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/builder/plan.rs +0 -0
  225. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/db_tracking.rs +0 -0
  226. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/db_tracking_setup.rs +0 -0
  227. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/dumper.rs +0 -0
  228. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/evaluator.rs +0 -0
  229. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/indexing_status.rs +0 -0
  230. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/live_updater.rs +0 -0
  231. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/memoization.rs +0 -0
  232. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/mod.rs +0 -0
  233. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/row_indexer.rs +0 -0
  234. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/source_indexer.rs +0 -0
  235. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/execution/stats.rs +0 -0
  236. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/lib.rs +0 -0
  237. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/lib_context.rs +0 -0
  238. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/anthropic.rs +0 -0
  239. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/gemini.rs +0 -0
  240. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/litellm.rs +0 -0
  241. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/ollama.rs +0 -0
  242. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/openai.rs +0 -0
  243. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/openrouter.rs +0 -0
  244. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/vllm.rs +0 -0
  245. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/llm/voyage.rs +0 -0
  246. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/factory_bases.rs +0 -0
  247. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/functions/embed_text.rs +0 -0
  248. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/functions/extract_by_llm.rs +0 -0
  249. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/functions/mod.rs +0 -0
  250. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/functions/parse_json.rs +0 -0
  251. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/functions/split_recursively.rs +0 -0
  252. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/functions/test_utils.rs +0 -0
  253. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/interface.rs +0 -0
  254. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/mod.rs +0 -0
  255. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/py_factory.rs +0 -0
  256. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/registration.rs +0 -0
  257. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/registry.rs +0 -0
  258. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/sdk.rs +0 -0
  259. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/sources/amazon_s3.rs +0 -0
  260. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/sources/azure_blob.rs +0 -0
  261. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/sources/google_drive.rs +0 -0
  262. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/sources/local_file.rs +0 -0
  263. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/sources/mod.rs +0 -0
  264. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/kuzu.rs +0 -0
  265. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/mod.rs +0 -0
  266. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/neo4j.rs +0 -0
  267. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/postgres.rs +0 -0
  268. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/shared/mod.rs +0 -0
  269. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/shared/property_graph.rs +0 -0
  270. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/ops/targets/shared/table_columns.rs +0 -0
  271. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/prelude.rs +0 -0
  272. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/py/convert.rs +0 -0
  273. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/py/mod.rs +0 -0
  274. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/server.rs +0 -0
  275. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/service/error.rs +0 -0
  276. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/service/flows.rs +0 -0
  277. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/service/mod.rs +0 -0
  278. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/settings.rs +0 -0
  279. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/setup/auth_registry.rs +0 -0
  280. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/setup/components.rs +0 -0
  281. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/setup/db_metadata.rs +0 -0
  282. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/setup/driver.rs +0 -0
  283. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/setup/mod.rs +0 -0
  284. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/setup/states.rs +0 -0
  285. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/concur_control.rs +0 -0
  286. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/db.rs +0 -0
  287. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/fingerprint.rs +0 -0
  288. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/immutable.rs +0 -0
  289. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/mod.rs +0 -0
  290. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/retryable.rs +0 -0
  291. {cocoindex-0.1.72 → cocoindex-0.1.73}/src/utils/yaml_ser.rs +0 -0
@@ -1297,7 +1297,7 @@ dependencies = [
1297
1297
 
1298
1298
  [[package]]
1299
1299
  name = "cocoindex"
1300
- version = "0.1.72"
1300
+ version = "0.1.73"
1301
1301
  dependencies = [
1302
1302
  "anyhow",
1303
1303
  "async-openai",
@@ -2,7 +2,7 @@
2
2
  name = "cocoindex"
3
3
  # Version used for local development is always higher than others to take precedence.
4
4
  # Will be overridden for specific release versions.
5
- version = "0.1.72"
5
+ version = "0.1.73"
6
6
  edition = "2024"
7
7
  rust-version = "1.88"
8
8
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cocoindex
3
- Version: 0.1.72
3
+ Version: 0.1.73
4
4
  Requires-Dist: click>=8.1.8
5
5
  Requires-Dist: rich>=14.0.0
6
6
  Requires-Dist: python-dotenv>=1.1.0
@@ -88,8 +88,8 @@ Optionally, it can have a fixed dimension. Noted as *Vector[Type]* or *Vector[Ty
88
88
  It supports the following Python types:
89
89
 
90
90
  * `cocoindex.Vector[T]` or `cocoindex.Vector[T, typing.Literal[Dim]]`, e.g. `cocoindex.Vector[cocoindex.Float32]` or `cocoindex.Vector[cocoindex.Float32, typing.Literal[384]]`
91
- * The underlying Python type is `numpy.typing.NDArray[T]` where `T` is a numpy numeric type (`numpy.int64`, `numpy.float32` or `numpy.float64`), or `list[T]` otherwise
92
- * `numpy.typing.NDArray[T]` where `T` is a numpy numeric type
91
+ * The underlying Python type is `numpy.typing.NDArray[T]` where `T` is a numpy numeric type (`numpy.int64`, `numpy.float32` or `numpy.float64`) or array type (`numpy.typing.NDArray[T]`), or `list[T]` otherwise
92
+ * `numpy.typing.NDArray[T]` where `T` is a numpy numeric type or array type
93
93
  * `list[T]`
94
94
 
95
95
 
@@ -63,11 +63,16 @@ Here's how CocoIndex data elements map to Qdrant elements during export:
63
63
  | a collected row | a point |
64
64
  | a field | a named vector, if fits into Qdrant vector; or a field within payload otherwise |
65
65
 
66
- *Vector[Float32, N]*, *Vector[Float64, N]* and *Vector[Int64, N]* types fit into Qdrant vector.
66
+ The following vector types fit into Qdrant vector:
67
+ * One-dimensional vectors with fixed dimension, e.g. *Vector[Float32, N]*, *Vector[Float64, N]* and *Vector[Int64, N]*.
68
+ We map them to [dense vectors](https://qdrant.tech/documentation/concepts/vectors/#dense-vectors).
69
+ * Two-dimensional vectors whose inner layer is a one-dimensional vector with fixed dimension, e.g. *Vector[Vector[Float32, N]]*, *Vector[Vector[Int64, N]]*, *Vector[Vector[Float64, N]]*. The outer layer may or may not have a fixed dimension.
70
+ We map them to [multivectors](https://qdrant.tech/documentation/concepts/vectors/#multivectors).
71
+
67
72
 
68
73
  :::warning vector type mapping to Qdrant
69
74
 
70
- Since vectors in Qdrant must have fixed dimension, we only map vectors of number types with fixed dimension (i.e. *Vector[cocoindex.Float32, N]*, *Vector[cocoindex.Float64, N]*, and *Vector[cocoindex.Int64, N]*) to Qdrant vectors.
75
+ Since vectors in Qdrant must have fixed dimension, we only map vectors of number types with fixed dimension to Qdrant vectors.
71
76
  For all other vector types, we map to Qdrant payload as JSON arrays.
72
77
 
73
78
  :::
@@ -21,7 +21,12 @@ We appreciate a star ⭐ at [CocoIndex Github](https://github.com/cocoindex-io/c
21
21
 
22
22
  1. [Install Postgres](https://cocoindex.io/docs/getting_started/installation#-install-postgres) if you don't have one.
23
23
 
24
- 2. dependencies:
24
+ 2. Install Qdrant
25
+ ```bash
26
+ docker run -d -p 6334:6334 -p 6333:6333 qdrant/qdrant
27
+ ```
28
+
29
+ 3. Install dependencies:
25
30
 
26
31
  ```bash
27
32
  pip install -e .
@@ -1,12 +1,15 @@
1
1
  import cocoindex
2
- import io
3
2
  import dataclasses
4
3
  import datetime
5
- import typing
4
+ import io
5
+ import os
6
6
 
7
7
  import face_recognition
8
- from PIL import Image
9
8
  import numpy as np
9
+ from PIL import Image
10
+
11
+ QDRANT_URL = os.getenv("QDRANT_URL", "http://localhost:6334/")
12
+ QDRANT_COLLECTION = "face_embeddings"
10
13
 
11
14
 
12
15
  @dataclasses.dataclass
@@ -35,7 +38,7 @@ MAX_IMAGE_WIDTH = 1280
35
38
  arg_relationship=(cocoindex.op.ArgRelationship.RECTS_BASE_IMAGE, "content"),
36
39
  )
37
40
  def extract_faces(content: bytes) -> list[FaceBase]:
38
- """Extract the first pages of a PDF."""
41
+ """Extract the faces from a image."""
39
42
  orig_img = Image.open(io.BytesIO(content)).convert("RGB")
40
43
 
41
44
  # The model is too slow on large images, so we resize them if too large.
@@ -90,7 +93,7 @@ def face_recognition_flow(
90
93
  flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope
91
94
  ) -> None:
92
95
  """
93
- Define an example flow that embeds files into a vector database.
96
+ Define an example flow that embeds files into Qdrant vector database.
94
97
  """
95
98
  data_scope["images"] = flow_builder.add_source(
96
99
  cocoindex.sources.LocalFile(path="images", binary=True),
@@ -108,13 +111,14 @@ def face_recognition_flow(
108
111
 
109
112
  # Collect embeddings
110
113
  face_embeddings.collect(
114
+ id=cocoindex.GeneratedField.UUID,
111
115
  filename=image["filename"],
112
116
  rect=face["rect"],
113
117
  embedding=face["embedding"],
114
118
  )
115
119
 
116
120
  face_embeddings.export(
117
- "face_embeddings",
118
- cocoindex.targets.Postgres(),
119
- primary_key_fields=["filename", "rect"],
121
+ QDRANT_COLLECTION,
122
+ cocoindex.targets.Qdrant(collection_name=QDRANT_COLLECTION),
123
+ primary_key_fields=["id"],
120
124
  )
@@ -13,12 +13,19 @@ import numpy as np
13
13
  from .typing import (
14
14
  KEY_FIELD_NAME,
15
15
  TABLE_TYPES,
16
- DtypeRegistry,
17
16
  analyze_type_info,
18
17
  encode_enriched_type,
19
- extract_ndarray_scalar_dtype,
20
18
  is_namedtuple_type,
21
19
  is_struct_type,
20
+ AnalyzedTypeInfo,
21
+ AnalyzedAnyType,
22
+ AnalyzedDictType,
23
+ AnalyzedListType,
24
+ AnalyzedBasicType,
25
+ AnalyzedUnionType,
26
+ AnalyzedUnknownType,
27
+ AnalyzedStructType,
28
+ is_numpy_number_type,
22
29
  )
23
30
 
24
31
 
@@ -79,46 +86,88 @@ def make_engine_value_decoder(
79
86
  Returns:
80
87
  A decoder from an engine value to a Python value.
81
88
  """
89
+
82
90
  src_type_kind = src_type["kind"]
83
91
 
84
- dst_is_any = (
85
- dst_annotation is None
86
- or dst_annotation is inspect.Parameter.empty
87
- or dst_annotation is Any
88
- )
89
- if dst_is_any:
90
- if src_type_kind == "Union":
91
- return lambda value: value[1]
92
- if src_type_kind == "Struct":
93
- return _make_engine_struct_to_dict_decoder(field_path, src_type["fields"])
94
- if src_type_kind in TABLE_TYPES:
95
- if src_type_kind == "LTable":
92
+ dst_type_info = analyze_type_info(dst_annotation)
93
+ dst_type_variant = dst_type_info.variant
94
+
95
+ if isinstance(dst_type_variant, AnalyzedUnknownType):
96
+ raise ValueError(
97
+ f"Type mismatch for `{''.join(field_path)}`: "
98
+ f"declared `{dst_type_info.core_type}`, an unsupported type"
99
+ )
100
+
101
+ if src_type_kind == "Struct":
102
+ return _make_engine_struct_value_decoder(
103
+ field_path,
104
+ src_type["fields"],
105
+ dst_type_info,
106
+ )
107
+
108
+ if src_type_kind in TABLE_TYPES:
109
+ field_path.append("[*]")
110
+ engine_fields_schema = src_type["row"]["fields"]
111
+
112
+ if src_type_kind == "LTable":
113
+ if isinstance(dst_type_variant, AnalyzedAnyType):
96
114
  return _make_engine_ltable_to_list_dict_decoder(
97
- field_path, src_type["row"]["fields"]
115
+ field_path, engine_fields_schema
116
+ )
117
+ if not isinstance(dst_type_variant, AnalyzedListType):
118
+ raise ValueError(
119
+ f"Type mismatch for `{''.join(field_path)}`: "
120
+ f"declared `{dst_type_info.core_type}`, a list type expected"
98
121
  )
99
- elif src_type_kind == "KTable":
122
+ row_decoder = _make_engine_struct_value_decoder(
123
+ field_path,
124
+ engine_fields_schema,
125
+ analyze_type_info(dst_type_variant.elem_type),
126
+ )
127
+
128
+ def decode(value: Any) -> Any | None:
129
+ if value is None:
130
+ return None
131
+ return [row_decoder(v) for v in value]
132
+
133
+ elif src_type_kind == "KTable":
134
+ if isinstance(dst_type_variant, AnalyzedAnyType):
100
135
  return _make_engine_ktable_to_dict_dict_decoder(
101
- field_path, src_type["row"]["fields"]
136
+ field_path, engine_fields_schema
137
+ )
138
+ if not isinstance(dst_type_variant, AnalyzedDictType):
139
+ raise ValueError(
140
+ f"Type mismatch for `{''.join(field_path)}`: "
141
+ f"declared `{dst_type_info.core_type}`, a dict type expected"
102
142
  )
103
- return lambda value: value
104
143
 
105
- # Handle struct -> dict binding for explicit dict annotations
106
- is_dict_annotation = False
107
- if dst_annotation is dict:
108
- is_dict_annotation = True
109
- elif getattr(dst_annotation, "__origin__", None) is dict:
110
- args = getattr(dst_annotation, "__args__", ())
111
- if args == (str, Any):
112
- is_dict_annotation = True
113
- if is_dict_annotation and src_type_kind == "Struct":
114
- return _make_engine_struct_to_dict_decoder(field_path, src_type["fields"])
144
+ key_field_schema = engine_fields_schema[0]
145
+ field_path.append(f".{key_field_schema.get('name', KEY_FIELD_NAME)}")
146
+ key_decoder = make_engine_value_decoder(
147
+ field_path, key_field_schema["type"], dst_type_variant.key_type
148
+ )
149
+ field_path.pop()
150
+ value_decoder = _make_engine_struct_value_decoder(
151
+ field_path,
152
+ engine_fields_schema[1:],
153
+ analyze_type_info(dst_type_variant.value_type),
154
+ )
115
155
 
116
- dst_type_info = analyze_type_info(dst_annotation)
156
+ def decode(value: Any) -> Any | None:
157
+ if value is None:
158
+ return None
159
+ return {key_decoder(v[0]): value_decoder(v[1:]) for v in value}
160
+
161
+ field_path.pop()
162
+ return decode
117
163
 
118
164
  if src_type_kind == "Union":
165
+ if isinstance(dst_type_variant, AnalyzedAnyType):
166
+ return lambda value: value[1]
167
+
119
168
  dst_type_variants = (
120
- dst_type_info.union_variant_types
121
- if dst_type_info.union_variant_types is not None
169
+ dst_type_variant.variant_types
170
+ if isinstance(dst_type_variant, AnalyzedUnionType)
122
171
  else [dst_annotation]
123
172
  )
124
173
  src_type_variants = src_type["types"]
@@ -142,43 +191,33 @@ def make_engine_value_decoder(
142
191
  decoders.append(decoder)
143
192
  return lambda value: decoders[value[0]](value[1])
144
193
 
145
- if not _is_type_kind_convertible_to(src_type_kind, dst_type_info.kind):
146
- raise ValueError(
147
- f"Type mismatch for `{''.join(field_path)}`: "
148
- f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_info.kind})"
149
- )
150
-
151
- if dst_type_info.kind in ("Float32", "Float64", "Int64"):
152
- dst_core_type = dst_type_info.core_type
153
-
154
- def decode_scalar(value: Any) -> Any | None:
155
- if value is None:
156
- if dst_type_info.nullable:
157
- return None
158
- raise ValueError(
159
- f"Received null for non-nullable scalar `{''.join(field_path)}`"
160
- )
161
- return dst_core_type(value)
162
-
163
- return decode_scalar
194
+ if isinstance(dst_type_variant, AnalyzedAnyType):
195
+ return lambda value: value
164
196
 
165
197
  if src_type_kind == "Vector":
166
198
  field_path_str = "".join(field_path)
199
+ if not isinstance(dst_type_variant, AnalyzedListType):
200
+ raise ValueError(
201
+ f"Type mismatch for `{''.join(field_path)}`: "
202
+ f"declared `{dst_type_info.core_type}`, a list type expected"
203
+ )
167
204
  expected_dim = (
168
- dst_type_info.vector_info.dim if dst_type_info.vector_info else None
205
+ dst_type_variant.vector_info.dim
206
+ if dst_type_variant and dst_type_variant.vector_info
207
+ else None
169
208
  )
170
209
 
171
- elem_decoder = None
210
+ vec_elem_decoder = None
172
211
  scalar_dtype = None
173
- if dst_type_info.np_number_type is None: # for Non-NDArray vector
174
- elem_decoder = make_engine_value_decoder(
212
+ if dst_type_variant and dst_type_info.base_type is np.ndarray:
213
+ if is_numpy_number_type(dst_type_variant.elem_type):
214
+ scalar_dtype = dst_type_variant.elem_type
215
+ else:
216
+ vec_elem_decoder = make_engine_value_decoder(
175
217
  field_path + ["[*]"],
176
218
  src_type["element_type"],
177
- dst_type_info.elem_type,
219
+ dst_type_variant and dst_type_variant.elem_type,
178
220
  )
179
- else: # for NDArray vector
180
- scalar_dtype = extract_ndarray_scalar_dtype(dst_type_info.np_number_type)
181
- _ = DtypeRegistry.validate_dtype_and_get_kind(scalar_dtype)
182
221
 
183
222
  def decode_vector(value: Any) -> Any | None:
184
223
  if value is None:
@@ -197,54 +236,33 @@ def make_engine_value_decoder(
197
236
  f"expected {expected_dim}, got {len(value)}"
198
237
  )
199
238
 
200
- if elem_decoder is not None: # for Non-NDArray vector
201
- return [elem_decoder(v) for v in value]
239
+ if vec_elem_decoder is not None: # for Non-NDArray vector
240
+ return [vec_elem_decoder(v) for v in value]
202
241
  else: # for NDArray vector
203
242
  return np.array(value, dtype=scalar_dtype)
204
243
 
205
244
  return decode_vector
206
245
 
207
- if dst_type_info.struct_type is not None:
208
- return _make_engine_struct_value_decoder(
209
- field_path, src_type["fields"], dst_type_info.struct_type
210
- )
211
-
212
- if src_type_kind in TABLE_TYPES:
213
- field_path.append("[*]")
214
- elem_type_info = analyze_type_info(dst_type_info.elem_type)
215
- if elem_type_info.struct_type is None:
246
+ if isinstance(dst_type_variant, AnalyzedBasicType):
247
+ if not _is_type_kind_convertible_to(src_type_kind, dst_type_variant.kind):
216
248
  raise ValueError(
217
249
  f"Type mismatch for `{''.join(field_path)}`: "
218
- f"declared `{dst_type_info.kind}`, a dataclass or NamedTuple type expected"
219
- )
220
- engine_fields_schema = src_type["row"]["fields"]
221
- if elem_type_info.key_type is not None:
222
- key_field_schema = engine_fields_schema[0]
223
- field_path.append(f".{key_field_schema.get('name', KEY_FIELD_NAME)}")
224
- key_decoder = make_engine_value_decoder(
225
- field_path, key_field_schema["type"], elem_type_info.key_type
226
- )
227
- field_path.pop()
228
- value_decoder = _make_engine_struct_value_decoder(
229
- field_path, engine_fields_schema[1:], elem_type_info.struct_type
250
+ f"passed in {src_type_kind}, declared {dst_annotation} ({dst_type_variant.kind})"
230
251
  )
231
252
 
232
- def decode(value: Any) -> Any | None:
233
- if value is None:
234
- return None
235
- return {key_decoder(v[0]): value_decoder(v[1:]) for v in value}
236
- else:
237
- elem_decoder = _make_engine_struct_value_decoder(
238
- field_path, engine_fields_schema, elem_type_info.struct_type
239
- )
253
+ if dst_type_variant.kind in ("Float32", "Float64", "Int64"):
254
+ dst_core_type = dst_type_info.core_type
240
255
 
241
- def decode(value: Any) -> Any | None:
256
+ def decode_scalar(value: Any) -> Any | None:
242
257
  if value is None:
243
- return None
244
- return [elem_decoder(v) for v in value]
258
+ if dst_type_info.nullable:
259
+ return None
260
+ raise ValueError(
261
+ f"Received null for non-nullable scalar `{''.join(field_path)}`"
262
+ )
263
+ return dst_core_type(value)
245
264
 
246
- field_path.pop()
247
- return decode
265
+ return decode_scalar
248
266
 
249
267
  return lambda value: value
250
268
 
@@ -252,11 +270,36 @@ def make_engine_value_decoder(
252
270
  def _make_engine_struct_value_decoder(
253
271
  field_path: list[str],
254
272
  src_fields: list[dict[str, Any]],
255
- dst_struct_type: type,
273
+ dst_type_info: AnalyzedTypeInfo,
256
274
  ) -> Callable[[list[Any]], Any]:
257
275
  """Make a decoder from an engine field values to a Python value."""
258
276
 
277
+ dst_type_variant = dst_type_info.variant
278
+
279
+ use_dict = False
280
+ if isinstance(dst_type_variant, AnalyzedAnyType):
281
+ use_dict = True
282
+ elif isinstance(dst_type_variant, AnalyzedDictType):
283
+ analyzed_key_type = analyze_type_info(dst_type_variant.key_type)
284
+ analyzed_value_type = analyze_type_info(dst_type_variant.value_type)
285
+ use_dict = (
286
+ isinstance(analyzed_key_type.variant, AnalyzedAnyType)
287
+ or (
288
+ isinstance(analyzed_key_type.variant, AnalyzedBasicType)
289
+ and analyzed_key_type.variant.kind == "Str"
290
+ )
291
+ ) and isinstance(analyzed_value_type.variant, AnalyzedAnyType)
292
+ if use_dict:
293
+ return _make_engine_struct_to_dict_decoder(field_path, src_fields)
294
+
295
+ if not isinstance(dst_type_variant, AnalyzedStructType):
296
+ raise ValueError(
297
+ f"Type mismatch for `{''.join(field_path)}`: "
298
+ f"declared `{dst_type_info.core_type}`, a dataclass, NamedTuple or dict[str, Any] expected"
299
+ )
300
+
259
301
  src_name_to_idx = {f["name"]: i for i, f in enumerate(src_fields)}
302
+ dst_struct_type = dst_type_variant.struct_type
260
303
 
261
304
  parameters: Mapping[str, inspect.Parameter]
262
305
  if dataclasses.is_dataclass(dst_struct_type):
@@ -105,7 +105,9 @@ def validate_full_roundtrip_to(
105
105
  for other_value, other_type in decoded_values:
106
106
  decoder = make_engine_value_decoder([], encoded_output_type, other_type)
107
107
  other_decoded_value = decoder(value_from_engine)
108
- assert eq(other_decoded_value, other_value)
108
+ assert eq(other_decoded_value, other_value), (
109
+ f"Expected {other_value} but got {other_decoded_value} for {other_type}"
110
+ )
109
111
 
110
112
 
111
113
  def validate_full_roundtrip(
@@ -1096,6 +1098,25 @@ def test_full_roundtrip_vector_numeric_types() -> None:
1096
1098
  validate_full_roundtrip(value_u64, Vector[np.uint64, Literal[3]])
1097
1099
 
1098
1100
 
1101
+ def test_full_roundtrip_vector_of_vector() -> None:
1102
+ """Test full roundtrip for vector of vector."""
1103
+ value_f32 = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=np.float32)
1104
+ validate_full_roundtrip(
1105
+ value_f32,
1106
+ Vector[Vector[np.float32, Literal[3]], Literal[2]],
1107
+ ([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], list[list[np.float32]]),
1108
+ ([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], list[list[cocoindex.Float32]]),
1109
+ (
1110
+ [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
1111
+ list[Vector[cocoindex.Float32, Literal[3]]],
1112
+ ),
1113
+ (
1114
+ value_f32,
1115
+ np.typing.NDArray[np.typing.NDArray[np.float32]],
1116
+ ),
1117
+ )
1118
+
1119
+
1099
1120
  def test_full_roundtrip_vector_other_types() -> None:
1100
1121
  """Test full roundtrip for Vector with non-numeric basic types."""
1101
1122
  uuid_list = [uuid.uuid4(), uuid.uuid4()]
@@ -1216,7 +1237,7 @@ def test_full_roundtrip_scalar_with_python_types() -> None:
1216
1237
  numpy_float: np.float64
1217
1238
  python_float: float
1218
1239
  string: str
1219
- annotated_int: Annotated[np.int64, TypeKind("int")]
1240
+ annotated_int: Annotated[np.int64, TypeKind("Int64")]
1220
1241
  annotated_float: Float32
1221
1242
 
1222
1243
  instance = MixedStruct(