sunholo 0.123.3__py3-none-any.whl → 0.123.5__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.
@@ -14,7 +14,6 @@ from .uuid import generate_uuid_from_object_id
14
14
  from ..custom_logging import log
15
15
  from ..utils import ConfigManager
16
16
  from ..components import get_embeddings
17
-
18
17
  class AlloyDBClient:
19
18
  """
20
19
  A class to manage interactions with an AlloyDB instance.
@@ -228,22 +227,31 @@ class AlloyDBClient:
228
227
  def _execute_sql_langchain(self, sql_statement):
229
228
  return self.engine._fetch(query = sql_statement)
230
229
 
231
- def _execute_sql_pg8000(self, sql_statement):
232
- """Executes a given SQL statement with error handling.
230
+ def _execute_sql_pg8000(self, sql_statement, params=None):
231
+ """
232
+ Executes a given SQL statement with error handling.
233
233
 
234
- - sql_statement (str): The SQL statement to execute.
235
- - Returns: The result of the execution, if any.
234
+ Args:
235
+ sql_statement (str): The SQL statement to execute.
236
+ params (dict or list, optional): Parameters for the SQL statement.
237
+
238
+ Returns:
239
+ The result of the execution, if any.
236
240
  """
237
241
  sql_ = sqlalchemy.text(sql_statement)
238
242
  result = None
239
243
  with self.engine.connect() as conn:
240
244
  try:
241
245
  log.info(f"Executing SQL statement: {sql_}")
242
- result = conn.execute(sql_)
246
+ if params:
247
+ result = conn.execute(sql_, params)
248
+ else:
249
+ result = conn.execute(sql_)
243
250
  except DatabaseError as e:
244
251
  if "already exists" in str(e):
245
252
  log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
246
253
  else:
254
+ log.error(f"Database error: {e}, SQL: {sql_statement}, Params: {params}")
247
255
  raise
248
256
  finally:
249
257
  conn.close()
@@ -253,6 +261,7 @@ class AlloyDBClient:
253
261
  async def execute_sql_async(self, sql_statement):
254
262
  log.info(f"Executing async SQL statement: {sql_statement}")
255
263
  if self.engine_type == "pg8000":
264
+ # dont use async???
256
265
  result = await self._execute_sql_async_pg8000(sql_statement)
257
266
  elif self.engine_type == "langchain":
258
267
  result = await self._execute_sql_async_langchain(sql_statement)
@@ -275,14 +284,14 @@ class AlloyDBClient:
275
284
  sql_ = sqlalchemy.text(sql_statement)
276
285
  result = None
277
286
 
278
- # Get connection directly, avoiding async with
279
- conn = await self.engine.connect()
287
+ # IMPORTANT: Don't use await here, the engine.connect() is synchronous
288
+ conn = self.engine.connect()
280
289
  try:
281
290
  log.info(f"Executing SQL statement asynchronously: {sql_}")
282
291
  if values:
283
- result = await conn.execute(sql_, values)
292
+ result = conn.execute(sql_, values)
284
293
  else:
285
- result = await conn.execute(sql_)
294
+ result = conn.execute(sql_)
286
295
 
287
296
  # Explicitly commit transaction
288
297
  await conn.commit()
@@ -293,7 +302,7 @@ class AlloyDBClient:
293
302
  raise
294
303
  finally:
295
304
  # Close connection only here, not inside the context manager
296
- await conn.close()
305
+ conn.close()
297
306
 
298
307
  return result
299
308
 
@@ -512,42 +521,6 @@ class AlloyDBClient:
512
521
 
513
522
  self.grant_table_permissions(vectorstore_id, users)
514
523
 
515
- async def _execute_sql_async_pg8000(self, sql_statement, values=None):
516
- """Executes a given SQL statement asynchronously with error handling."""
517
- sql_ = sqlalchemy.text(sql_statement)
518
- result = None
519
- async with self.engine.connect() as conn:
520
- try:
521
- log.info(f"Executing SQL statement asynchronously: {sql_}")
522
- if values:
523
- result = await conn.execute(sql_, values)
524
- else:
525
- result = await conn.execute(sql_)
526
- except DatabaseError as e:
527
- if "already exists" in str(e):
528
- log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
529
- else:
530
- raise
531
- finally:
532
- await conn.close()
533
-
534
- return result
535
-
536
- async def _execute_sql_async_langchain(self, sql_statement, values=None):
537
- """Execute SQL asynchronously using langchain engine"""
538
- if values:
539
- # Implement parameterized queries for langchain engine
540
- # This would need to be adjusted based on how langchain engine handles parameters
541
- log.warning("Parameterized queries may not be fully supported with langchain engine")
542
- # For now, attempt a basic string substitution (not ideal for production)
543
- for value in values:
544
- if isinstance(value, str):
545
- sql_statement = sql_statement.replace("%s", f"'{value}'", 1)
546
- else:
547
- sql_statement = sql_statement.replace("%s", str(value), 1)
548
-
549
- return await self.engine._afetch(query=sql_statement)
550
-
551
524
  async def check_connection(self):
552
525
  """
553
526
  Checks if the database connection is still valid.
@@ -556,9 +529,16 @@ class AlloyDBClient:
556
529
  bool: True if connection is valid, False otherwise
557
530
  """
558
531
  try:
559
- # Simple query to check connection
560
- _ = await self.execute_sql_async("SELECT 1")
561
- return True
532
+ # For pg8000 engine, use synchronous connection
533
+ if self.engine_type == "pg8000":
534
+ # Use direct synchronous query
535
+ with self.engine.connect() as conn:
536
+ conn.execute(sqlalchemy.text("SELECT 1"))
537
+ return True
538
+ else:
539
+ # For langchain, use async connection
540
+ await self._execute_sql_async_langchain("SELECT 1")
541
+ return True
562
542
  except Exception as e:
563
543
  log.warning(f"Database connection check failed: {e}")
564
544
  return False
@@ -650,15 +630,24 @@ class AlloyDBClient:
650
630
  )
651
631
  '''
652
632
 
653
- # Execute SQL to create table
654
- result = await self.execute_sql_async(sql)
633
+ # Execute SQL to create table based on engine type
634
+ if self.engine_type == "pg8000":
635
+ # Use the synchronous method for pg8000
636
+ result = self._execute_sql_pg8000(sql)
637
+ else:
638
+ # Use the async method for langchain
639
+ result = await self._execute_sql_async_langchain(sql)
640
+
655
641
  log.info(f"Created or ensured table {table_name} exists")
656
642
 
657
643
  # Grant permissions if users are provided
658
644
  if users:
659
645
  for user in users:
660
646
  grant_sql = f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";'
661
- await self.execute_sql_async(grant_sql)
647
+ if self.engine_type == "pg8000":
648
+ self.execute_sql(grant_sql)
649
+ else:
650
+ await self._execute_sql_async_langchain(grant_sql)
662
651
 
663
652
  return result
664
653
 
@@ -683,15 +672,22 @@ class AlloyDBClient:
683
672
  insert_data["extraction_backend"] = metadata.get("extraction_backend", "unknown")
684
673
  insert_data["extraction_model"] = metadata.get("extraction_model", "unknown")
685
674
 
686
- # Prepare column names and placeholders for values
675
+ # Prepare column names and values for SQL
687
676
  columns = [f'"{key}"' for key in insert_data.keys()]
688
- placeholders = []
689
- values = []
690
677
 
691
- # Process values and create properly formatted placeholders
692
- for key, value in insert_data.items():
693
- values.append(json.dumps(value) if isinstance(value, (dict, list)) else value)
694
- placeholders.append("%s")
678
+ # Process values
679
+ processed_values = {}
680
+ for i, (key, value) in enumerate(insert_data.items()):
681
+ # Create a unique parameter name
682
+ param_name = f"param_{i}"
683
+ # For JSON values, convert to string
684
+ if isinstance(value, (dict, list)):
685
+ processed_values[param_name] = json.dumps(value)
686
+ else:
687
+ processed_values[param_name] = value
688
+
689
+ # Create placeholders using named parameters
690
+ placeholders = [f":{param_name}" for param_name in processed_values.keys()]
695
691
 
696
692
  # Create SQL statement for insertion
697
693
  columns_str = ", ".join(columns)
@@ -703,8 +699,14 @@ class AlloyDBClient:
703
699
  RETURNING id
704
700
  '''
705
701
 
706
- # Execute SQL to insert data
707
- result = await self.execute_sql_async(sql, values)
702
+ # Execute SQL to insert data based on engine type
703
+ if self.engine_type == "pg8000":
704
+ # Use the synchronous method for pg8000 with properly formatted parameters
705
+ result = self._execute_sql_pg8000(sql, processed_values)
706
+ else:
707
+ # Use the async method for langchain
708
+ result = await self._execute_sql_async_langchain(sql, processed_values)
709
+
708
710
  log.info(f"Inserted data into table {table_name}")
709
711
 
710
712
  return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.123.3
3
+ Version: 0.123.5
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
@@ -60,7 +60,7 @@ sunholo/components/retriever.py,sha256=Wmchv3huAM4w7DIS-a5Lp9Hi7M8pE6vZdxgseiT9S
60
60
  sunholo/components/vectorstore.py,sha256=k7GS1Y5c6ZGXSDAJvyCes6dTjhDAi0fjGbVLqpyfzBc,5918
61
61
  sunholo/database/__init__.py,sha256=bpB5Nk21kwqYj-qdVnvNgXjLsbflnH4g-San7OHMqR4,283
62
62
  sunholo/database/alloydb.py,sha256=x1zUMB-EVWbE2Zvp4nAs2Z-tB_kOZmS45H2lwVHdYnk,11678
63
- sunholo/database/alloydb_client.py,sha256=yksz52Qnx8xCsW61TPKGqSGTehSukP8suKwShec4z54,27401
63
+ sunholo/database/alloydb_client.py,sha256=OCAi7Gopry7tiOOdjka-cldghFpxl6IXWWGEANmFVII,27414
64
64
  sunholo/database/database.py,sha256=VqhZdkXUNdvWn8sUcUV3YNby1JDVf7IykPVXWBtxo9U,7361
65
65
  sunholo/database/lancedb.py,sha256=DyfZntiFKBlVPaFooNN1Z6Pl-LAs4nxWKKuq8GBqN58,715
66
66
  sunholo/database/static_dbs.py,sha256=8cvcMwUK6c32AS2e_WguKXWMkFf5iN3g9WHzsh0C07Q,442
@@ -168,9 +168,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
168
168
  sunholo/vertex/memory_tools.py,sha256=tBZxqVZ4InTmdBvLlOYwoSEWu4-kGquc-gxDwZCC4FA,7667
169
169
  sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
170
170
  sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
171
- sunholo-0.123.3.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
172
- sunholo-0.123.3.dist-info/METADATA,sha256=BYdslKNSlXmkUMdV4JExD5JzamsfnwVfzIepQV9PsAA,10001
173
- sunholo-0.123.3.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
174
- sunholo-0.123.3.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
175
- sunholo-0.123.3.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
176
- sunholo-0.123.3.dist-info/RECORD,,
171
+ sunholo-0.123.5.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
172
+ sunholo-0.123.5.dist-info/METADATA,sha256=ahlMOD2O68Y-qNXEM0UmWYJt_6dZyPvjXxdDcB71T8Y,10001
173
+ sunholo-0.123.5.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
174
+ sunholo-0.123.5.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
175
+ sunholo-0.123.5.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
176
+ sunholo-0.123.5.dist-info/RECORD,,