sunholo 0.124.0__tar.gz → 0.125.1__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 (188) hide show
  1. {sunholo-0.124.0/src/sunholo.egg-info → sunholo-0.125.1}/PKG-INFO +1 -1
  2. {sunholo-0.124.0 → sunholo-0.125.1}/pyproject.toml +1 -1
  3. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/alloydb_client.py +181 -19
  4. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/gcs/download_url.py +1 -1
  5. {sunholo-0.124.0 → sunholo-0.125.1/src/sunholo.egg-info}/PKG-INFO +1 -1
  6. {sunholo-0.124.0 → sunholo-0.125.1}/LICENSE.txt +0 -0
  7. {sunholo-0.124.0 → sunholo-0.125.1}/MANIFEST.in +0 -0
  8. {sunholo-0.124.0 → sunholo-0.125.1}/README.md +0 -0
  9. {sunholo-0.124.0 → sunholo-0.125.1}/setup.cfg +0 -0
  10. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/__init__.py +0 -0
  11. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/__init__.py +0 -0
  12. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/chat_history.py +0 -0
  13. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/dispatch_to_qa.py +0 -0
  14. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/fastapi/__init__.py +0 -0
  15. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/fastapi/base.py +0 -0
  16. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
  17. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/flask/__init__.py +0 -0
  18. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/flask/base.py +0 -0
  19. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/flask/qna_routes.py +0 -0
  20. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/flask/vac_routes.py +0 -0
  21. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/langserve.py +0 -0
  22. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/pubsub.py +0 -0
  23. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/route.py +0 -0
  24. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/special_commands.py +0 -0
  25. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/agents/swagger.py +0 -0
  26. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/archive/__init__.py +0 -0
  27. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/archive/archive.py +0 -0
  28. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/auth/__init__.py +0 -0
  29. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/auth/gcloud.py +0 -0
  30. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/auth/refresh.py +0 -0
  31. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/auth/run.py +0 -0
  32. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/azure/__init__.py +0 -0
  33. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/azure/auth.py +0 -0
  34. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/azure/blobs.py +0 -0
  35. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/azure/event_grid.py +0 -0
  36. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/bots/__init__.py +0 -0
  37. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/bots/discord.py +0 -0
  38. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/bots/github_webhook.py +0 -0
  39. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/bots/webapp.py +0 -0
  40. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/__init__.py +0 -0
  41. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/azure.py +0 -0
  42. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/doc_handling.py +0 -0
  43. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/encode_metadata.py +0 -0
  44. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/images.py +0 -0
  45. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/loaders.py +0 -0
  46. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/message_data.py +0 -0
  47. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/pdfs.py +0 -0
  48. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/process_chunker_data.py +0 -0
  49. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/publish.py +0 -0
  50. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/pubsub.py +0 -0
  51. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/chunker/splitter.py +0 -0
  52. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/__init__.py +0 -0
  53. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/chat_vac.py +0 -0
  54. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/cli.py +0 -0
  55. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/cli_init.py +0 -0
  56. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/configs.py +0 -0
  57. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/deploy.py +0 -0
  58. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/embedder.py +0 -0
  59. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/merge_texts.py +0 -0
  60. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/run_proxy.py +0 -0
  61. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/sun_rich.py +0 -0
  62. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/swagger.py +0 -0
  63. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/cli/vertex.py +0 -0
  64. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/components/__init__.py +0 -0
  65. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/components/llm.py +0 -0
  66. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/components/retriever.py +0 -0
  67. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/components/vectorstore.py +0 -0
  68. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/custom_logging.py +0 -0
  69. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/__init__.py +0 -0
  70. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/alloydb.py +0 -0
  71. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/database.py +0 -0
  72. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/lancedb.py +0 -0
  73. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/sql/sb/create_function.sql +0 -0
  74. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
  75. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/sql/sb/create_table.sql +0 -0
  76. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  77. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
  78. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/sql/sb/setup.sql +0 -0
  79. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/static_dbs.py +0 -0
  80. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/database/uuid.py +0 -0
  81. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/discovery_engine/__init__.py +0 -0
  82. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
  83. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/discovery_engine/cli.py +0 -0
  84. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/discovery_engine/create_new.py +0 -0
  85. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  86. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  87. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/embedder/__init__.py +0 -0
  88. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/embedder/embed_chunk.py +0 -0
  89. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/embedder/embed_metadata.py +0 -0
  90. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/excel/__init__.py +0 -0
  91. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/excel/plugin.py +0 -0
  92. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/gcs/__init__.py +0 -0
  93. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/gcs/add_file.py +0 -0
  94. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/gcs/download_folder.py +0 -0
  95. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/gcs/extract_and_sign.py +0 -0
  96. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/gcs/metadata.py +0 -0
  97. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/__init__.py +0 -0
  98. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/file_handling.py +0 -0
  99. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/genaiv2.py +0 -0
  100. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/images.py +0 -0
  101. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/init.py +0 -0
  102. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/process_funcs_cls.py +0 -0
  103. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/genai/safety.py +0 -0
  104. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/invoke/__init__.py +0 -0
  105. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/invoke/async_class.py +0 -0
  106. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/invoke/direct_vac_func.py +0 -0
  107. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
  108. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/langchain_types.py +0 -0
  109. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/langfuse/__init__.py +0 -0
  110. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/langfuse/callback.py +0 -0
  111. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/langfuse/evals.py +0 -0
  112. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/langfuse/prompts.py +0 -0
  113. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/llamaindex/__init__.py +0 -0
  114. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/llamaindex/get_files.py +0 -0
  115. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/llamaindex/import_files.py +0 -0
  116. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
  117. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/llamaindex/user_history.py +0 -0
  118. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/lookup/__init__.py +0 -0
  119. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/lookup/model_lookup.yaml +0 -0
  120. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/mcp/__init__.py +0 -0
  121. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/mcp/cli.py +0 -0
  122. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/ollama/__init__.py +0 -0
  123. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/ollama/ollama_images.py +0 -0
  124. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/pubsub/__init__.py +0 -0
  125. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/pubsub/process_pubsub.py +0 -0
  126. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/pubsub/pubsub_manager.py +0 -0
  127. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/qna/__init__.py +0 -0
  128. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/qna/parsers.py +0 -0
  129. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/qna/retry.py +0 -0
  130. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/senses/__init__.py +0 -0
  131. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/senses/stream_voice.py +0 -0
  132. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/streaming/__init__.py +0 -0
  133. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/streaming/content_buffer.py +0 -0
  134. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/streaming/langserve.py +0 -0
  135. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/streaming/stream_lookup.py +0 -0
  136. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/streaming/streaming.py +0 -0
  137. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/summarise/__init__.py +0 -0
  138. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/summarise/summarise.py +0 -0
  139. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/__init__.py +0 -0
  140. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/agent_service.py +0 -0
  141. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/app.py +0 -0
  142. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/my_log.py +0 -0
  143. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/tools/__init__.py +0 -0
  144. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
  145. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/agent/vac_service.py +0 -0
  146. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/project/__init__.py +0 -0
  147. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/project/app.py +0 -0
  148. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/project/my_log.py +0 -0
  149. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/project/vac_service.py +0 -0
  150. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/system_services/__init__.py +0 -0
  151. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/system_services/app.py +0 -0
  152. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/templates/system_services/my_log.py +0 -0
  153. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/terraform/__init__.py +0 -0
  154. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/terraform/tfvars_editor.py +0 -0
  155. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/tools/__init__.py +0 -0
  156. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/tools/web_browser.py +0 -0
  157. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/__init__.py +0 -0
  158. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/api_key.py +0 -0
  159. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/big_context.py +0 -0
  160. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/config.py +0 -0
  161. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/config_class.py +0 -0
  162. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/config_schema.py +0 -0
  163. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/gcp.py +0 -0
  164. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/gcp_project.py +0 -0
  165. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/mime.py +0 -0
  166. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/parsers.py +0 -0
  167. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/timedelta.py +0 -0
  168. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/user_ids.py +0 -0
  169. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/utils/version.py +0 -0
  170. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/__init__.py +0 -0
  171. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/extensions_call.py +0 -0
  172. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/extensions_class.py +0 -0
  173. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/genai_functions.py +0 -0
  174. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/init.py +0 -0
  175. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/memory_tools.py +0 -0
  176. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/safety.py +0 -0
  177. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo/vertex/type_dict_to_json.py +0 -0
  178. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo.egg-info/SOURCES.txt +0 -0
  179. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo.egg-info/dependency_links.txt +0 -0
  180. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo.egg-info/entry_points.txt +0 -0
  181. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo.egg-info/requires.txt +0 -0
  182. {sunholo-0.124.0 → sunholo-0.125.1}/src/sunholo.egg-info/top_level.txt +0 -0
  183. {sunholo-0.124.0 → sunholo-0.125.1}/tests/test_async.py +0 -0
  184. {sunholo-0.124.0 → sunholo-0.125.1}/tests/test_async_genai2.py +0 -0
  185. {sunholo-0.124.0 → sunholo-0.125.1}/tests/test_chat_history.py +0 -0
  186. {sunholo-0.124.0 → sunholo-0.125.1}/tests/test_config.py +0 -0
  187. {sunholo-0.124.0 → sunholo-0.125.1}/tests/test_genai2.py +0 -0
  188. {sunholo-0.124.0 → sunholo-0.125.1}/tests/test_unstructured.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.124.0
3
+ Version: 0.125.1
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sunholo"
7
- version = "0.124.0"
7
+ version = "0.125.1"
8
8
  description = "Large Language Model DevOps - a package to help deploy LLMs to the Cloud."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -584,7 +584,8 @@ class AlloyDBClient:
584
584
 
585
585
  async def create_table_from_schema(self, table_name: str, schema_data: dict, users: list = None):
586
586
  """
587
- Creates or ensures a table exists based on the structure of the provided schema data.
587
+ Creates or ensures a table exists based on the structure of the provided schema data,
588
+ with special handling for expandable lists.
588
589
 
589
590
  Args:
590
591
  table_name (str): Name of the table to create
@@ -596,22 +597,32 @@ class AlloyDBClient:
596
597
  """
597
598
  # Generate column definitions from schema data
598
599
  columns = []
600
+
599
601
  for key, value in schema_data.items():
600
- if isinstance(value, dict):
601
- # For nested objects, store as JSONB
602
- columns.append(f'"{key}" JSONB')
603
- elif isinstance(value, list):
604
- # For arrays, store as JSONB
605
- columns.append(f'"{key}" JSONB')
606
- elif isinstance(value, int):
607
- columns.append(f'"{key}" INTEGER')
608
- elif isinstance(value, float):
609
- columns.append(f'"{key}" NUMERIC')
610
- elif isinstance(value, bool):
611
- columns.append(f'"{key}" BOOLEAN')
602
+ # Check if this is a specially marked expandable list
603
+ if isinstance(value, dict) and value.get("__is_expandable_list__", False):
604
+ # Handle expandable lists - we need to examine the first item to determine column types
605
+ items = value.get("items", [])
606
+
607
+ # Add an index column for this list
608
+ columns.append(f'"{key}_index" INTEGER')
609
+
610
+ if items and isinstance(items[0], dict):
611
+ # If the first item is a dictionary, we need to create columns for all its keys
612
+ sample_item = items[0]
613
+ # Flatten the dictionary with the key as prefix
614
+ flattened_item = self._flatten_dict_for_schema(sample_item, key, "_")
615
+
616
+ # Add columns for all keys in the flattened dictionary
617
+ for item_key, item_value in flattened_item.items():
618
+ item_column = self._get_column_definition(item_key, item_value)
619
+ columns.append(item_column)
620
+ else:
621
+ # If items are simple values, just add a column for the list key itself
622
+ columns.append(self._get_column_definition(key, items[0] if items else None))
612
623
  else:
613
- # Default to TEXT for strings and other types
614
- columns.append(f'"{key}" TEXT')
624
+ # Regular handling for non-list fields
625
+ columns.append(self._get_column_definition(key, value))
615
626
 
616
627
  # Add metadata columns
617
628
  columns.extend([
@@ -651,9 +662,159 @@ class AlloyDBClient:
651
662
 
652
663
  return result
653
664
 
665
+ def _get_column_definition(self, key, value):
666
+ """
667
+ Helper method to get SQL column definition from a key and value.
668
+
669
+ Args:
670
+ key (str): The column name
671
+ value: The value to determine the column type
672
+
673
+ Returns:
674
+ str: SQL column definition
675
+ """
676
+ if value is None:
677
+ # For unknown types (None), default to TEXT
678
+ return f'"{key}" TEXT'
679
+ elif isinstance(value, dict):
680
+ # For nested objects, store as JSONB
681
+ return f'"{key}" JSONB'
682
+ elif isinstance(value, list):
683
+ # For arrays, store as JSONB
684
+ return f'"{key}" JSONB'
685
+ elif isinstance(value, int):
686
+ return f'"{key}" INTEGER'
687
+ elif isinstance(value, float):
688
+ return f'"{key}" NUMERIC'
689
+ elif isinstance(value, bool):
690
+ return f'"{key}" BOOLEAN'
691
+ else:
692
+ # Default to TEXT for strings and other types
693
+ return f'"{key}" TEXT'
694
+
695
+ def _flatten_dict_for_schema(self, nested_dict, parent_key='', separator='.'):
696
+ """
697
+ Flatten a nested dictionary for schema creation.
698
+
699
+ Args:
700
+ nested_dict (dict): The nested dictionary to flatten
701
+ parent_key (str): The parent key for the current recursion level
702
+ separator (str): The separator to use between key levels
703
+
704
+ Returns:
705
+ dict: A flattened dictionary
706
+ """
707
+ flattened = {}
708
+
709
+ for key, value in nested_dict.items():
710
+ # Create the new key with parent_key if it exists
711
+ new_key = f"{parent_key}{separator}{key}" if parent_key else key
712
+
713
+ # If value is a dictionary, recursively flatten it
714
+ if isinstance(value, dict):
715
+ flattened.update(self._flatten_dict_for_schema(value, new_key, separator))
716
+ else:
717
+ # For simple values, just add them with the new key
718
+ flattened[new_key] = value
719
+
720
+ return flattened
721
+
722
+ def _flatten_dict(self, nested_dict, parent_key='', separator='.'):
723
+ """
724
+ Flatten a nested dictionary into a single-level dictionary with dot notation for keys.
725
+
726
+ Args:
727
+ nested_dict (dict): The nested dictionary to flatten
728
+ parent_key (str): The parent key for the current recursion level
729
+ separator (str): The separator to use between key levels (default: '.')
730
+
731
+ Returns:
732
+ dict: A flattened dictionary with special handling for lists
733
+ """
734
+ flattened = {}
735
+
736
+ for key, value in nested_dict.items():
737
+ # Create the new key with parent_key if it exists
738
+ new_key = f"{parent_key}{separator}{key}" if parent_key else key
739
+
740
+ # If value is a dictionary, recursively flatten it
741
+ if isinstance(value, dict):
742
+ flattened.update(self._flatten_dict(value, new_key, separator))
743
+ # Handle lists containing dictionaries or other values
744
+ elif isinstance(value, list):
745
+ # Mark lists for special processing during database insertion
746
+ # We'll use a special format to indicate this is a list that needs expansion
747
+ flattened[new_key] = {
748
+ "__is_expandable_list__": True,
749
+ "items": value
750
+ }
751
+ else:
752
+ # For simple values, just add them with the new key
753
+ flattened[new_key] = value
754
+
755
+ return flattened
756
+
654
757
  async def write_data_to_table(self, table_name: str, data: dict, metadata: dict = None):
655
758
  """
656
- Writes data to the specified table.
759
+ Writes data to the specified table, with special handling for expandable lists.
760
+
761
+ Args:
762
+ table_name (str): Name of the table
763
+ data (dict): Data to write to the table
764
+ metadata (dict, optional): Additional metadata to include
765
+
766
+ Returns:
767
+ List of results from SQL executions
768
+ """
769
+ # Find any expandable lists in the data
770
+ expandable_lists = {}
771
+ regular_data = {}
772
+
773
+ for key, value in data.items():
774
+ if isinstance(value, dict) and value.get("__is_expandable_list__", False):
775
+ expandable_lists[key] = value["items"]
776
+ else:
777
+ regular_data[key] = value
778
+
779
+ # If no expandable lists are found, do a simple insert
780
+ if not expandable_lists:
781
+ return await self._insert_single_row(table_name, regular_data, metadata)
782
+
783
+ # For expandable lists, we need to create multiple rows
784
+ results = []
785
+
786
+ # Create combinations of rows based on expandable lists
787
+ if expandable_lists:
788
+ # Get the first expandable list to start with
789
+ primary_list_key = next(iter(expandable_lists))
790
+ primary_list = expandable_lists[primary_list_key]
791
+
792
+ # For each item in the primary list, create a new row
793
+ for item_idx, item in enumerate(primary_list):
794
+ # Create a copy of the regular data
795
+ row_data = dict(regular_data)
796
+
797
+ # Add the current item from the primary list
798
+ if isinstance(item, dict):
799
+ # If it's a dictionary, flatten it with the primary key as prefix
800
+ flattened_item = self._flatten_dict(item, primary_list_key, "_")
801
+ row_data.update(flattened_item)
802
+ else:
803
+ # If it's a simple value, just add it with the list key
804
+ row_data[primary_list_key] = item
805
+
806
+ # Add item index for reference
807
+ row_data[f"{primary_list_key}_index"] = item_idx
808
+
809
+ # Insert this row
810
+ result = await self._insert_single_row(table_name, row_data, metadata)
811
+ results.append(result)
812
+
813
+ return results
814
+
815
+ async def _insert_single_row(self, table_name: str, data: dict, metadata: dict = None):
816
+ """
817
+ Inserts a single row of data into the specified table.
657
818
 
658
819
  Args:
659
820
  table_name (str): Name of the table
@@ -663,14 +824,15 @@ class AlloyDBClient:
663
824
  Returns:
664
825
  Result of SQL execution
665
826
  """
827
+
666
828
  # Create copies to avoid modifying the original data
667
829
  insert_data = dict(data)
668
830
 
669
831
  # Add metadata if provided
670
832
  if metadata:
671
- insert_data["source"] = metadata.get("objectId", metadata.get("source", "unknown"))
672
- insert_data["extraction_backend"] = metadata.get("extraction_backend", "unknown")
673
- insert_data["extraction_model"] = metadata.get("extraction_model", "unknown")
833
+ insert_data["source"] = metadata.get("objectId", metadata.get("source", "not-in-metadata"))
834
+ insert_data["extraction_backend"] = metadata.get("extraction_backend", "not-in-metadata")
835
+ insert_data["extraction_model"] = metadata.get("extraction_model", "not-in-metadata")
674
836
 
675
837
  # Prepare column names and values for SQL
676
838
  columns = [f'"{key}"' for key in insert_data.keys()]
@@ -36,7 +36,7 @@ def get_image_from_gcs(gs_uri: str) -> Image.Image: # type: ignore
36
36
  except IOError as e:
37
37
  raise ValueError("Unable to open image from bytes:", e)
38
38
 
39
- def get_bytes_from_gcs(gs_uri) -> Optional[bytes]:
39
+ def get_bytes_from_gcs(gs_uri: str) -> Optional[bytes]:
40
40
  """
41
41
  Downloads a file from Google Cloud Storage and returns its bytes.
42
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.124.0
3
+ Version: 0.125.1
4
4
  Summary: Large Language Model DevOps - a package to help deploy LLMs to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
File without changes
File without changes
File without changes
File without changes
File without changes