sunholo 0.123.2__py3-none-any.whl → 0.123.4__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.
@@ -228,22 +228,31 @@ class AlloyDBClient:
228
228
  def _execute_sql_langchain(self, sql_statement):
229
229
  return self.engine._fetch(query = sql_statement)
230
230
 
231
- def _execute_sql_pg8000(self, sql_statement):
232
- """Executes a given SQL statement with error handling.
231
+ def _execute_sql_pg8000(self, sql_statement, params=None):
232
+ """
233
+ Executes a given SQL statement with error handling.
233
234
 
234
- - sql_statement (str): The SQL statement to execute.
235
- - Returns: The result of the execution, if any.
235
+ Args:
236
+ sql_statement (str): The SQL statement to execute.
237
+ params (dict or list, optional): Parameters for the SQL statement.
238
+
239
+ Returns:
240
+ The result of the execution, if any.
236
241
  """
237
242
  sql_ = sqlalchemy.text(sql_statement)
238
243
  result = None
239
244
  with self.engine.connect() as conn:
240
245
  try:
241
246
  log.info(f"Executing SQL statement: {sql_}")
242
- result = conn.execute(sql_)
247
+ if params:
248
+ result = conn.execute(sql_, params)
249
+ else:
250
+ result = conn.execute(sql_)
243
251
  except DatabaseError as e:
244
252
  if "already exists" in str(e):
245
253
  log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
246
254
  else:
255
+ log.error(f"Database error: {e}, SQL: {sql_statement}, Params: {params}")
247
256
  raise
248
257
  finally:
249
258
  conn.close()
@@ -253,6 +262,7 @@ class AlloyDBClient:
253
262
  async def execute_sql_async(self, sql_statement):
254
263
  log.info(f"Executing async SQL statement: {sql_statement}")
255
264
  if self.engine_type == "pg8000":
265
+ # dont use async???
256
266
  result = await self._execute_sql_async_pg8000(sql_statement)
257
267
  elif self.engine_type == "langchain":
258
268
  result = await self._execute_sql_async_langchain(sql_statement)
@@ -262,21 +272,38 @@ class AlloyDBClient:
262
272
  async def _execute_sql_async_langchain(self, sql_statement):
263
273
  return await self.engine._afetch(query = sql_statement)
264
274
 
265
- async def _execute_sql_async_pg8000(self, sql_statement):
266
- """Executes a given SQL statement asynchronously with error handling."""
275
+ async def _execute_sql_async_pg8000(self, sql_statement, values=None):
276
+ """Executes a given SQL statement asynchronously with error handling.
277
+
278
+ Args:
279
+ sql_statement (str): The SQL statement to execute
280
+ values (list, optional): Values for parameterized query
281
+
282
+ Returns:
283
+ Result of SQL execution
284
+ """
267
285
  sql_ = sqlalchemy.text(sql_statement)
268
286
  result = None
269
- async with self.engine.connect() as conn:
270
- try:
271
- log.info(f"Executing SQL statement asynchronously: {sql_}")
272
- result = await conn.execute(sql_)
273
- except DatabaseError as e:
274
- if "already exists" in str(e):
275
- log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
276
- else:
277
- raise
278
- finally:
279
- await conn.close()
287
+
288
+ # IMPORTANT: Don't use await here, the engine.connect() is synchronous
289
+ conn = self.engine.connect()
290
+ try:
291
+ log.info(f"Executing SQL statement asynchronously: {sql_}")
292
+ if values:
293
+ result = conn.execute(sql_, values)
294
+ else:
295
+ result = conn.execute(sql_)
296
+
297
+ # Explicitly commit transaction
298
+ await conn.commit()
299
+ except DatabaseError as e:
300
+ if "already exists" in str(e):
301
+ log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
302
+ else:
303
+ raise
304
+ finally:
305
+ # Close connection only here, not inside the context manager
306
+ conn.close()
280
307
 
281
308
  return result
282
309
 
@@ -495,42 +522,6 @@ class AlloyDBClient:
495
522
 
496
523
  self.grant_table_permissions(vectorstore_id, users)
497
524
 
498
- async def _execute_sql_async_pg8000(self, sql_statement, values=None):
499
- """Executes a given SQL statement asynchronously with error handling."""
500
- sql_ = sqlalchemy.text(sql_statement)
501
- result = None
502
- async with self.engine.connect() as conn:
503
- try:
504
- log.info(f"Executing SQL statement asynchronously: {sql_}")
505
- if values:
506
- result = await conn.execute(sql_, values)
507
- else:
508
- result = await conn.execute(sql_)
509
- except DatabaseError as e:
510
- if "already exists" in str(e):
511
- log.warning(f"Error ignored: {str(e)}. Assuming object already exists.")
512
- else:
513
- raise
514
- finally:
515
- await conn.close()
516
-
517
- return result
518
-
519
- async def _execute_sql_async_langchain(self, sql_statement, values=None):
520
- """Execute SQL asynchronously using langchain engine"""
521
- if values:
522
- # Implement parameterized queries for langchain engine
523
- # This would need to be adjusted based on how langchain engine handles parameters
524
- log.warning("Parameterized queries may not be fully supported with langchain engine")
525
- # For now, attempt a basic string substitution (not ideal for production)
526
- for value in values:
527
- if isinstance(value, str):
528
- sql_statement = sql_statement.replace("%s", f"'{value}'", 1)
529
- else:
530
- sql_statement = sql_statement.replace("%s", str(value), 1)
531
-
532
- return await self.engine._afetch(query=sql_statement)
533
-
534
525
  async def check_connection(self):
535
526
  """
536
527
  Checks if the database connection is still valid.
@@ -540,7 +531,7 @@ class AlloyDBClient:
540
531
  """
541
532
  try:
542
533
  # Simple query to check connection
543
- result = await self.execute_sql_async("SELECT 1")
534
+ _ = await self.execute_sql_async("SELECT 1")
544
535
  return True
545
536
  except Exception as e:
546
537
  log.warning(f"Database connection check failed: {e}")
@@ -565,7 +556,7 @@ class AlloyDBClient:
565
556
  # Re-create the engine
566
557
  self.engine = self._create_engine()
567
558
 
568
- log.info(f"Successfully reconnected to AlloyDB")
559
+ log.info("Successfully reconnected to AlloyDB")
569
560
  return True
570
561
  except Exception as e:
571
562
  log.error(f"Failed to reconnect to AlloyDB: {e}")
@@ -633,14 +624,24 @@ class AlloyDBClient:
633
624
  )
634
625
  '''
635
626
 
636
- # Execute SQL to create table
637
- result = await self.execute_sql_async(sql)
627
+ # Execute SQL to create table based on engine type
628
+ if self.engine_type == "pg8000":
629
+ # Use the synchronous method for pg8000
630
+ result = self._execute_sql_pg8000(sql)
631
+ else:
632
+ # Use the async method for langchain
633
+ result = await self._execute_sql_async_langchain(sql)
634
+
638
635
  log.info(f"Created or ensured table {table_name} exists")
639
636
 
640
637
  # Grant permissions if users are provided
641
638
  if users:
642
639
  for user in users:
643
- await self.execute_sql_async(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";')
640
+ grant_sql = f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";'
641
+ if self.engine_type == "pg8000":
642
+ self.execute_sql(grant_sql)
643
+ else:
644
+ await self._execute_sql_async_langchain(grant_sql)
644
645
 
645
646
  return result
646
647
 
@@ -665,15 +666,22 @@ class AlloyDBClient:
665
666
  insert_data["extraction_backend"] = metadata.get("extraction_backend", "unknown")
666
667
  insert_data["extraction_model"] = metadata.get("extraction_model", "unknown")
667
668
 
668
- # Prepare column names and placeholders for values
669
+ # Prepare column names and values for SQL
669
670
  columns = [f'"{key}"' for key in insert_data.keys()]
670
- placeholders = []
671
- values = []
672
671
 
673
- # Process values and create properly formatted placeholders
674
- for key, value in insert_data.items():
675
- values.append(json.dumps(value) if isinstance(value, (dict, list)) else value)
676
- placeholders.append("%s")
672
+ # Process values
673
+ processed_values = {}
674
+ for i, (key, value) in enumerate(insert_data.items()):
675
+ # Create a unique parameter name
676
+ param_name = f"param_{i}"
677
+ # For JSON values, convert to string
678
+ if isinstance(value, (dict, list)):
679
+ processed_values[param_name] = json.dumps(value)
680
+ else:
681
+ processed_values[param_name] = value
682
+
683
+ # Create placeholders using named parameters
684
+ placeholders = [f":{param_name}" for param_name in processed_values.keys()]
677
685
 
678
686
  # Create SQL statement for insertion
679
687
  columns_str = ", ".join(columns)
@@ -685,28 +693,14 @@ class AlloyDBClient:
685
693
  RETURNING id
686
694
  '''
687
695
 
688
- # Execute SQL to insert data
689
- result = await self.execute_sql_async(sql, values)
690
- log.info(f"Inserted data into table {table_name}")
691
-
692
- return result
693
-
694
- async def execute_sql_async(self, sql_statement, values=None):
695
- """
696
- Executes a given SQL statement asynchronously with optional parameter values.
697
-
698
- Args:
699
- sql_statement (str): The SQL statement to execute
700
- values (list, optional): Values for parameterized query
701
-
702
- Returns:
703
- Result of SQL execution
704
- """
705
- log.info(f"Executing async SQL statement: {sql_statement}")
696
+ # Execute SQL to insert data based on engine type
706
697
  if self.engine_type == "pg8000":
707
- result = await self._execute_sql_async_pg8000(sql_statement, values)
708
- elif self.engine_type == "langchain":
709
- result = await self._execute_sql_async_langchain(sql_statement, values)
698
+ # Use the synchronous method for pg8000 with properly formatted parameters
699
+ result = self._execute_sql_pg8000(sql, processed_values)
700
+ else:
701
+ # Use the async method for langchain
702
+ result = await self._execute_sql_async_langchain(sql, processed_values)
710
703
 
711
- return result
712
-
704
+ log.info(f"Inserted data into table {table_name}")
705
+
706
+ return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.123.2
3
+ Version: 0.123.4
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=uPRcdfrE1YXCUoDbaKopjlKXXP5deceEn08bJKUeWI4,27596
63
+ sunholo/database/alloydb_client.py,sha256=pppcmPx1liMmQSiKCdpNR6BLODbvEdICAQMz2EEjxnQ,27081
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.2.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
172
- sunholo-0.123.2.dist-info/METADATA,sha256=0w8jC9b0-_LEB8VnRcKIIbSlHCIJRFPyiuqwfTnbsm8,10001
173
- sunholo-0.123.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
174
- sunholo-0.123.2.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
175
- sunholo-0.123.2.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
176
- sunholo-0.123.2.dist-info/RECORD,,
171
+ sunholo-0.123.4.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
172
+ sunholo-0.123.4.dist-info/METADATA,sha256=iJAH2MBdmtJhWAoZmyMoVQZUGHs3Q8iuJYkC_JmRhSo,10001
173
+ sunholo-0.123.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
174
+ sunholo-0.123.4.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
175
+ sunholo-0.123.4.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
176
+ sunholo-0.123.4.dist-info/RECORD,,