wcp-library 1.5.6__py3-none-any.whl → 1.5.8__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.
@@ -9,55 +9,60 @@ import psycopg
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
11
 
12
- def retry(f: callable) -> callable:
12
+ def retry(func: callable) -> callable:
13
13
  """
14
14
  Decorator to retry a function
15
15
 
16
- :param f: function
16
+ :param func: function
17
17
  :return: function
18
18
  """
19
19
 
20
- @wraps(f)
20
+ @wraps(func)
21
21
  def wrapper(self, *args, **kwargs):
22
22
  self._retry_count = 0
23
23
  while True:
24
24
  try:
25
- return f(self, *args, **kwargs)
25
+ return func(self, *args, **kwargs)
26
26
  except (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError) as e:
27
- error_obj, = e.args
28
- if error_obj.full_code in self.retry_error_codes and self._retry_count < self.retry_limit:
29
- self._retry_count += 1
30
- logger.debug("Oracle connection error")
31
- logger.debug(error_obj.message)
32
- logger.info("Waiting 5 minutes before retrying Oracle connection")
33
- sleep(300)
34
- else:
35
- raise e
27
+ if isinstance(e, (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError, psycopg.DatabaseError)):
28
+ error_obj, = e.args
29
+ if error_obj.full_code in self.retry_error_codes and self._retry_count < self.retry_limit:
30
+ self._retry_count += 1
31
+ logger.debug("Oracle connection error")
32
+ logger.debug(error_obj.message)
33
+ logger.info("Waiting 5 minutes before retrying Oracle connection")
34
+ sleep(300)
35
+ else:
36
+ raise e
37
+ raise e
36
38
  return wrapper
37
39
 
38
40
 
39
- def async_retry(f: callable) -> callable:
41
+ def async_retry(func: callable) -> callable:
40
42
  """
41
43
  Decorator to retry a function
42
44
 
43
- :param f: function
45
+ :param func: function
44
46
  :return: function
45
47
  """
46
48
 
47
- @wraps(f)
49
+ @wraps(func)
48
50
  async def wrapper(self, *args, **kwargs):
49
51
  self._retry_count = 0
50
52
  while True:
51
53
  try:
52
- return await f(self, *args, **kwargs)
54
+ return await func(self, *args, **kwargs)
53
55
  except (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError) as e:
54
- error_obj, = e.args
55
- if error_obj.full_code in self.retry_error_codes and self._retry_count < self.retry_limit:
56
- self._retry_count += 1
57
- logger.debug(f"{self._db_service} connection error")
58
- logger.debug(error_obj.message)
59
- logger.info("Waiting 5 minutes before retrying Oracle connection")
60
- await asyncio.sleep(300)
56
+ if isinstance(e, (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError, psycopg.DatabaseError)):
57
+ error_obj, = e.args
58
+ if error_obj.full_code in self.retry_error_codes and self._retry_count < self.retry_limit:
59
+ self._retry_count += 1
60
+ logger.debug(f"{self._db_service} connection error")
61
+ logger.debug(error_obj.message)
62
+ logger.info("Waiting 5 minutes before retrying Oracle connection")
63
+ await asyncio.sleep(300)
64
+ else:
65
+ raise e
61
66
  else:
62
67
  raise e
63
68
  return wrapper
wcp_library/sql/oracle.py CHANGED
@@ -4,7 +4,7 @@ from typing import Optional
4
4
  import numpy as np
5
5
  import pandas as pd
6
6
  import oracledb
7
- from oracledb import ConnectionPool, AsyncConnectionPool
7
+ from oracledb import ConnectionPool, AsyncConnectionPool, Connection, AsyncConnection
8
8
 
9
9
  from wcp_library.sql import retry, async_retry
10
10
 
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
12
12
 
13
13
 
14
14
  def _connect_warehouse(username: str, password: str, hostname: str, port: int, database: str, min_connections: int,
15
- max_connections: int) -> ConnectionPool:
15
+ max_connections: int, use_pool: bool) -> ConnectionPool | Connection:
16
16
  """
17
17
  Create Warehouse Connection
18
18
 
@@ -23,23 +23,34 @@ def _connect_warehouse(username: str, password: str, hostname: str, port: int, d
23
23
  :param database: database
24
24
  :param min_connections:
25
25
  :param max_connections:
26
- :return: session_pool
26
+ :param use_pool: use connection pool
27
+ :return: session_pool | connection
27
28
  """
28
29
 
29
- dsn = oracledb.makedsn(hostname, port, sid=database)
30
- session_pool = oracledb.create_pool(
31
- user=username,
32
- password=password,
33
- dsn=dsn,
34
- min=min_connections,
35
- max=max_connections,
36
- increment=1,
37
- )
38
- return session_pool
30
+ if use_pool:
31
+ logger.debug(f"Creating connection pool with min size {min_connections} and max size {max_connections}")
32
+ dsn = oracledb.makedsn(hostname, port, sid=database)
33
+ session_pool = oracledb.create_pool(
34
+ user=username,
35
+ password=password,
36
+ dsn=dsn,
37
+ min=min_connections,
38
+ max=max_connections,
39
+ increment=1,
40
+ )
41
+ return session_pool
42
+ else:
43
+ logger.debug("Creating single connection")
44
+ connection = oracledb.connect(
45
+ user=username,
46
+ password=password,
47
+ dsn=oracledb.makedsn(hostname, port, sid=database)
48
+ )
49
+ return connection
39
50
 
40
51
 
41
52
  async def _async_connect_warehouse(username: str, password: str, hostname: str, port: int, database: str,
42
- min_connections: int, max_connections: int) -> AsyncConnectionPool:
53
+ min_connections: int, max_connections: int, use_pool: bool) -> AsyncConnectionPool | AsyncConnection:
43
54
  """
44
55
  Create Warehouse Connection
45
56
 
@@ -50,19 +61,30 @@ async def _async_connect_warehouse(username: str, password: str, hostname: str,
50
61
  :param database: database
51
62
  :param min_connections:
52
63
  :param max_connections:
53
- :return: session_pool
64
+ :param use_pool: use connection pool
65
+ :return: session_pool | connection
54
66
  """
55
67
 
56
- dsn = oracledb.makedsn(hostname, port, sid=database)
57
- session_pool = oracledb.create_pool_async(
58
- user=username,
59
- password=password,
60
- dsn=dsn,
61
- min=min_connections,
62
- max=max_connections,
63
- increment=1
64
- )
65
- return session_pool
68
+ if use_pool:
69
+ logger.debug(f"Creating async connection pool with min size {min_connections} and max size {max_connections}")
70
+ dsn = oracledb.makedsn(hostname, port, sid=database)
71
+ session_pool = oracledb.create_pool_async(
72
+ user=username,
73
+ password=password,
74
+ dsn=dsn,
75
+ min=min_connections,
76
+ max=max_connections,
77
+ increment=1
78
+ )
79
+ return session_pool
80
+ else:
81
+ logger.debug("Creating single async connection")
82
+ connection = await oracledb.connect_async(
83
+ user=username,
84
+ password=password,
85
+ dsn=oracledb.makedsn(hostname, port, sid=database)
86
+ )
87
+ return connection
66
88
 
67
89
 
68
90
  """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"""
@@ -75,15 +97,17 @@ class OracleConnection(object):
75
97
  :return: None
76
98
  """
77
99
 
78
- def __init__(self, min_connections: int = 2, max_connections: int = 5):
100
+ def __init__(self, use_pool: bool = False, min_connections: int = 2, max_connections: int = 5):
79
101
  self._username: Optional[str] = None
80
102
  self._password: Optional[str] = None
81
103
  self._hostname: Optional[str] = None
82
104
  self._port: Optional[int] = None
83
105
  self._database: Optional[str] = None
84
106
  self._sid: Optional[str] = None
107
+ self._connection: Optional[Connection] = None
85
108
  self._session_pool: Optional[ConnectionPool] = None
86
109
 
110
+ self.use_pool = use_pool
87
111
  self.min_connections = min_connections
88
112
  self.max_connections = max_connections
89
113
 
@@ -101,8 +125,27 @@ class OracleConnection(object):
101
125
 
102
126
  sid_or_service = self._database if self._database else self._sid
103
127
 
104
- self._session_pool = _connect_warehouse(self._username, self._password, self._hostname, self._port,
105
- sid_or_service, self.min_connections, self.max_connections)
128
+ connection = _connect_warehouse(self._username, self._password, self._hostname, self._port,
129
+ sid_or_service, self.min_connections, self.max_connections, self.use_pool)
130
+
131
+ if self.use_pool:
132
+ self._session_pool = connection
133
+ else:
134
+ self._connection = connection
135
+
136
+ def _get_connection(self) -> Connection:
137
+ """
138
+ Get the connection, either from the pool or create a new one
139
+
140
+ :return: Connection
141
+ """
142
+
143
+ if self.use_pool:
144
+ return self._session_pool.acquire()
145
+ else:
146
+ if not self._connection or not self._connection.is_healthy():
147
+ self._connect()
148
+ return self._connection
106
149
 
107
150
  def set_user(self, credentials_dict: dict) -> None:
108
151
  """
@@ -131,7 +174,12 @@ class OracleConnection(object):
131
174
  :return: None
132
175
  """
133
176
 
134
- self._session_pool.close()
177
+ if self.use_pool:
178
+ self._session_pool.close()
179
+ else:
180
+ if self._connection and self._connection.is_healthy():
181
+ self._connection.close()
182
+ self._connection = None
135
183
 
136
184
  @retry
137
185
  def execute(self, query: str) -> None:
@@ -142,11 +190,11 @@ class OracleConnection(object):
142
190
  :return: None
143
191
  """
144
192
 
145
- connection = self._session_pool.acquire()
146
- cursor = connection.cursor()
147
- cursor.execute(query)
148
- connection.commit()
149
- self._session_pool.release(connection)
193
+ connection = self._get_connection()
194
+ with connection:
195
+ cursor = connection.cursor()
196
+ cursor.execute(query)
197
+ connection.commit()
150
198
 
151
199
  @retry
152
200
  def safe_execute(self, query: str, packed_values: dict) -> None:
@@ -158,14 +206,14 @@ class OracleConnection(object):
158
206
  :return: None
159
207
  """
160
208
 
161
- connection = self._session_pool.acquire()
162
- cursor = connection.cursor()
163
- cursor.execute(query, packed_values)
164
- connection.commit()
165
- self._session_pool.release(connection)
209
+ connection = self._get_connection()
210
+ with connection:
211
+ cursor = connection.cursor()
212
+ cursor.execute(query, packed_values)
213
+ connection.commit()
166
214
 
167
215
  @retry
168
- def execute_multiple(self, queries: list[list[str, dict]]) -> None:
216
+ def execute_multiple(self, queries: list[tuple[str, dict]]) -> None:
169
217
  """
170
218
  Execute multiple queries
171
219
 
@@ -173,17 +221,17 @@ class OracleConnection(object):
173
221
  :return: None
174
222
  """
175
223
 
176
- connection = self._session_pool.acquire()
177
- cursor = connection.cursor()
178
- for item in queries:
179
- query = item[0]
180
- packed_values = item[1]
181
- if packed_values:
182
- cursor.execute(query, packed_values)
183
- else:
184
- cursor.execute(query)
185
- connection.commit()
186
- self._session_pool.release(connection)
224
+ connection = self._get_connection()
225
+ with connection:
226
+ cursor = connection.cursor()
227
+ for item in queries:
228
+ query = item[0]
229
+ packed_values = item[1]
230
+ if packed_values:
231
+ cursor.execute(query, packed_values)
232
+ else:
233
+ cursor.execute(query)
234
+ connection.commit()
187
235
 
188
236
  @retry
189
237
  def execute_many(self, query: str, dictionary: list[dict]) -> None:
@@ -195,11 +243,11 @@ class OracleConnection(object):
195
243
  :return: None
196
244
  """
197
245
 
198
- connection = self._session_pool.acquire()
199
- cursor = connection.cursor()
200
- cursor.executemany(query, dictionary)
201
- connection.commit()
202
- self._session_pool.release(connection)
246
+ connection = self._get_connection()
247
+ with connection:
248
+ cursor = connection.cursor()
249
+ cursor.executemany(query, dictionary)
250
+ connection.commit()
203
251
 
204
252
  @retry
205
253
  def fetch_data(self, query: str, packed_data=None) -> list:
@@ -211,14 +259,14 @@ class OracleConnection(object):
211
259
  :return: rows
212
260
  """
213
261
 
214
- connection = self._session_pool.acquire()
215
- cursor = connection.cursor()
216
- if packed_data:
217
- cursor.execute(query, packed_data)
218
- else:
219
- cursor.execute(query)
220
- rows = cursor.fetchall()
221
- self._session_pool.release(connection)
262
+ connection = self._get_connection()
263
+ with connection:
264
+ cursor = connection.cursor()
265
+ if packed_data:
266
+ cursor.execute(query, packed_data)
267
+ else:
268
+ cursor.execute(query)
269
+ rows = cursor.fetchall()
222
270
  return rows
223
271
 
224
272
  @retry
@@ -267,7 +315,7 @@ class OracleConnection(object):
267
315
  dfObj = dfObj.replace({np.nan: None})
268
316
  main_dict = dfObj.to_dict('records')
269
317
 
270
- query = """INSERT INTO {} ({}) VALUES ({})""".format(outputTableName, col, bind)
318
+ query = f"""INSERT INTO {outputTableName} ({col}) VALUES ({bind})"""
271
319
  self.execute_many(query, main_dict)
272
320
 
273
321
  @retry
@@ -279,7 +327,7 @@ class OracleConnection(object):
279
327
  :return: None
280
328
  """
281
329
 
282
- truncateQuery = """TRUNCATE TABLE {}""".format(tableName)
330
+ truncateQuery = f"""TRUNCATE TABLE {tableName}"""
283
331
  self.execute(truncateQuery)
284
332
 
285
333
  @retry
@@ -291,7 +339,7 @@ class OracleConnection(object):
291
339
  :return: None
292
340
  """
293
341
 
294
- deleteQuery = """DELETE FROM {}""".format(tableName)
342
+ deleteQuery = f"""DELETE FROM {tableName}"""
295
343
  self.execute(deleteQuery)
296
344
 
297
345
  def __del__(self) -> None:
@@ -301,7 +349,12 @@ class OracleConnection(object):
301
349
  :return: None
302
350
  """
303
351
 
304
- self._session_pool.close()
352
+ if self.use_pool:
353
+ self._session_pool.close()
354
+ else:
355
+ if self._connection and self._connection.is_healthy():
356
+ self._connection.close()
357
+ self._connection = None
305
358
 
306
359
 
307
360
  class AsyncOracleConnection(object):
@@ -311,7 +364,7 @@ class AsyncOracleConnection(object):
311
364
  :return: None
312
365
  """
313
366
 
314
- def __init__(self, min_connections: int = 2, max_connections: int = 5):
367
+ def __init__(self, use_pool: bool = False, min_connections: int = 2, max_connections: int = 5):
315
368
  self._db_service: str = "Oracle"
316
369
  self._username: Optional[str] = None
317
370
  self._password: Optional[str] = None
@@ -319,8 +372,10 @@ class AsyncOracleConnection(object):
319
372
  self._port: Optional[int] = None
320
373
  self._database: Optional[str] = None
321
374
  self._sid: Optional[str] = None
375
+ self._connection: Optional[AsyncConnection] = None
322
376
  self._session_pool: Optional[AsyncConnectionPool] = None
323
377
 
378
+ self.use_pool = use_pool
324
379
  self.min_connections = min_connections
325
380
  self.max_connections = max_connections
326
381
 
@@ -338,8 +393,28 @@ class AsyncOracleConnection(object):
338
393
 
339
394
  sid_or_service = self._database if self._database else self._sid
340
395
 
341
- self._session_pool = await _async_connect_warehouse(self._username, self._password, self._hostname, self._port,
342
- sid_or_service, self.min_connections, self.max_connections)
396
+ connection = await _async_connect_warehouse(self._username, self._password, self._hostname, self._port,
397
+ sid_or_service, self.min_connections, self.max_connections,
398
+ self.use_pool)
399
+
400
+ if self.use_pool:
401
+ self._session_pool = connection
402
+ else:
403
+ self._connection = connection
404
+
405
+ async def _get_connection(self) -> AsyncConnection:
406
+ """
407
+ Get the connection, either from the pool or create a new one
408
+
409
+ :return: AsyncConnection
410
+ """
411
+
412
+ if self.use_pool:
413
+ return await self._session_pool.acquire()
414
+ else:
415
+ if not self._connection or not self._connection.is_healthy():
416
+ await self._connect()
417
+ return self._connection
343
418
 
344
419
  async def set_user(self, credentials_dict: dict) -> None:
345
420
  """
@@ -368,7 +443,12 @@ class AsyncOracleConnection(object):
368
443
  :return: None
369
444
  """
370
445
 
371
- await self._session_pool.close()
446
+ if self.use_pool:
447
+ await self._session_pool.close()
448
+ else:
449
+ if self._connection and self._connection.is_healthy():
450
+ await self._connection.close()
451
+ self._connection = None
372
452
 
373
453
  @async_retry
374
454
  async def execute(self, query: str) -> None:
@@ -379,7 +459,8 @@ class AsyncOracleConnection(object):
379
459
  :return: None
380
460
  """
381
461
 
382
- async with self._session_pool.acquire() as connection:
462
+ connection = await self._get_connection()
463
+ async with connection:
383
464
  with connection.cursor() as cursor:
384
465
  await cursor.execute(query)
385
466
  await connection.commit()
@@ -394,13 +475,14 @@ class AsyncOracleConnection(object):
394
475
  :return: None
395
476
  """
396
477
 
397
- async with self._session_pool.acquire() as connection:
478
+ connection = await self._get_connection()
479
+ async with connection:
398
480
  with connection.cursor() as cursor:
399
481
  await cursor.execute(query, packed_values)
400
482
  await connection.commit()
401
483
 
402
484
  @async_retry
403
- async def execute_multiple(self, queries: list[list[str, dict]]) -> None:
485
+ async def execute_multiple(self, queries: list[tuple[str, dict]]) -> None:
404
486
  """
405
487
  Execute multiple queries
406
488
 
@@ -408,7 +490,8 @@ class AsyncOracleConnection(object):
408
490
  :return: None
409
491
  """
410
492
 
411
- async with self._session_pool.acquire() as connection:
493
+ connection = await self._get_connection()
494
+ async with connection:
412
495
  with connection.cursor() as cursor:
413
496
  for item in queries:
414
497
  query = item[0]
@@ -429,7 +512,8 @@ class AsyncOracleConnection(object):
429
512
  :return: None
430
513
  """
431
514
 
432
- async with self._session_pool.acquire() as connection:
515
+ connection = await self._get_connection()
516
+ async with connection:
433
517
  with connection.cursor() as cursor:
434
518
  await cursor.executemany(query, dictionary)
435
519
  await connection.commit()
@@ -444,7 +528,8 @@ class AsyncOracleConnection(object):
444
528
  :return: rows
445
529
  """
446
530
 
447
- async with self._session_pool.acquire() as connection:
531
+ connection = await self._get_connection()
532
+ async with connection:
448
533
  with connection.cursor() as cursor:
449
534
  if packed_data:
450
535
  await cursor.execute(query, packed_data)
@@ -499,7 +584,7 @@ class AsyncOracleConnection(object):
499
584
  dfObj = dfObj.replace({np.nan: None})
500
585
  main_dict = dfObj.to_dict('records')
501
586
 
502
- query = """INSERT INTO {} ({}) VALUES ({})""".format(outputTableName, col, bind)
587
+ query = f"""INSERT INTO {outputTableName} ({col}) VALUES ({bind})"""
503
588
  await self.execute_many(query, main_dict)
504
589
 
505
590
  @async_retry
@@ -511,7 +596,7 @@ class AsyncOracleConnection(object):
511
596
  :return: None
512
597
  """
513
598
 
514
- truncateQuery = """TRUNCATE TABLE {}""".format(tableName)
599
+ truncateQuery = f"""TRUNCATE TABLE {tableName}"""
515
600
  await self.execute(truncateQuery)
516
601
 
517
602
  @async_retry
@@ -523,5 +608,5 @@ class AsyncOracleConnection(object):
523
608
  :return: None
524
609
  """
525
610
 
526
- deleteQuery = """DELETE FROM {}""".format(tableName)
611
+ deleteQuery = f"""DELETE FROM {tableName}"""
527
612
  await self.execute(deleteQuery)
@@ -1,8 +1,11 @@
1
1
  import logging
2
- from typing import Optional
2
+ from contextlib import _GeneratorContextManager
3
+ from typing import Optional, Any
3
4
 
4
5
  import numpy as np
5
6
  import pandas as pd
7
+ import psycopg
8
+ from psycopg import AsyncConnection, Connection
6
9
  from psycopg.conninfo import make_conninfo
7
10
  from psycopg.sql import SQL
8
11
  from psycopg_pool import AsyncConnectionPool, ConnectionPool
@@ -13,7 +16,7 @@ logger = logging.getLogger(__name__)
13
16
 
14
17
 
15
18
  def _connect_warehouse(username: str, password: str, hostname: str, port: int, database: str, min_connections: int,
16
- max_connections: int) -> ConnectionPool:
19
+ max_connections: int, use_pool: bool) -> Connection | ConnectionPool:
17
20
  """
18
21
  Create Warehouse Connection
19
22
 
@@ -30,18 +33,24 @@ def _connect_warehouse(username: str, password: str, hostname: str, port: int, d
30
33
  conn_string = f"dbname={database} user={username} password={password} host={hostname} port={port}"
31
34
  conninfo = make_conninfo(conn_string)
32
35
 
33
- session_pool = ConnectionPool(
34
- conninfo=conninfo,
35
- min_size=min_connections,
36
- max_size=max_connections,
37
- kwargs={'options': '-c datestyle=ISO,YMD'},
38
- open=True
39
- )
40
- return session_pool
36
+ if use_pool:
37
+ logger.debug(f"Creating connection pool with min size {min_connections} and max size {max_connections}")
38
+ session_pool = ConnectionPool(
39
+ conninfo=conninfo,
40
+ min_size=min_connections,
41
+ max_size=max_connections,
42
+ kwargs={'options': '-c datestyle=ISO,YMD'},
43
+ open=True
44
+ )
45
+ return session_pool
46
+ else:
47
+ logger.debug("Creating single connection")
48
+ connection = psycopg.connect(conninfo=conninfo, options='-c datestyle=ISO,YMD')
49
+ return connection
41
50
 
42
51
 
43
52
  async def _async_connect_warehouse(username: str, password: str, hostname: str, port: int, database: str, min_connections: int,
44
- max_connections: int) -> AsyncConnectionPool:
53
+ max_connections: int, use_pool: bool) -> AsyncConnection | AsyncConnectionPool:
45
54
  """
46
55
  Create Warehouse Connection
47
56
 
@@ -58,14 +67,20 @@ async def _async_connect_warehouse(username: str, password: str, hostname: str,
58
67
  conn_string = f"dbname={database} user={username} password={password} host={hostname} port={port}"
59
68
  conninfo = make_conninfo(conn_string)
60
69
 
61
- session_pool = AsyncConnectionPool(
62
- conninfo=conninfo,
63
- min_size=min_connections,
64
- max_size=max_connections,
65
- kwargs={"options": "-c datestyle=ISO,YMD"},
66
- open=False
67
- )
68
- return session_pool
70
+ if use_pool:
71
+ logger.debug(f"Creating async connection pool with min size {min_connections} and max size {max_connections}")
72
+ session_pool = AsyncConnectionPool(
73
+ conninfo=conninfo,
74
+ min_size=min_connections,
75
+ max_size=max_connections,
76
+ kwargs={"options": "-c datestyle=ISO,YMD"},
77
+ open=False
78
+ )
79
+ return session_pool
80
+ else:
81
+ logger.debug("Creating single async connection")
82
+ connection = await AsyncConnection.connect(conninfo=conninfo, options='-c datestyle=ISO,YMD')
83
+ return connection
69
84
 
70
85
 
71
86
  """~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"""
@@ -78,14 +93,16 @@ class PostgresConnection(object):
78
93
  :return: None
79
94
  """
80
95
 
81
- def __init__(self, min_connections: int = 2, max_connections: int = 5):
96
+ def __init__(self, use_pool: bool = False, min_connections: int = 2, max_connections: int = 5):
82
97
  self._username: Optional[str] = None
83
98
  self._password: Optional[str] = None
84
99
  self._hostname: Optional[str] = None
85
100
  self._port: Optional[int] = None
86
101
  self._database: Optional[str] = None
102
+ self._connection: Optional[Connection] = None
87
103
  self._session_pool: Optional[ConnectionPool] = None
88
104
 
105
+ self.use_pool = use_pool
89
106
  self.min_connections = min_connections
90
107
  self.max_connections = max_connections
91
108
 
@@ -101,8 +118,30 @@ class PostgresConnection(object):
101
118
  :return: None
102
119
  """
103
120
 
104
- self._session_pool = _connect_warehouse(self._username, self._password, self._hostname, self._port,
105
- self._database, self.min_connections, self.max_connections)
121
+
122
+ self.connection = _connect_warehouse(self._username, self._password, self._hostname, self._port,
123
+ self._database, self.min_connections, self.max_connections, self.use_pool)
124
+
125
+ if self.use_pool:
126
+ self._session_pool = self.connection
127
+ self._session_pool.open()
128
+ else:
129
+ self._connection = self.connection
130
+
131
+ def _get_connection(self) -> _GeneratorContextManager[Any] | Connection:
132
+ """
133
+ Get the connection object
134
+
135
+ :return: connection
136
+ """
137
+
138
+ if self.use_pool:
139
+ connection = self._session_pool.connection()
140
+ return connection
141
+ else:
142
+ if self._connection is None or self._connection.closed:
143
+ self._connect()
144
+ return self._connection
106
145
 
107
146
  def set_user(self, credentials_dict: dict) -> None:
108
147
  """
@@ -127,7 +166,12 @@ class PostgresConnection(object):
127
166
  :return: None
128
167
  """
129
168
 
130
- self._session_pool.close()
169
+ if self.use_pool:
170
+ self._session_pool.close()
171
+ else:
172
+ if self._connection is not None and not self._connection.closed:
173
+ self._connection.close()
174
+ self._connection = None
131
175
 
132
176
  @retry
133
177
  def execute(self, query: SQL | str) -> None:
@@ -138,7 +182,8 @@ class PostgresConnection(object):
138
182
  :return: None
139
183
  """
140
184
 
141
- with self._session_pool.connection() as connection:
185
+ connection = self._get_connection()
186
+ with connection:
142
187
  connection.execute(query)
143
188
 
144
189
  @retry
@@ -151,11 +196,12 @@ class PostgresConnection(object):
151
196
  :return: None
152
197
  """
153
198
 
154
- with self._session_pool.connection() as connection:
199
+ connection = self._get_connection()
200
+ with connection:
155
201
  connection.execute(query, packed_values)
156
202
 
157
203
  @retry
158
- def execute_multiple(self, queries: list[list[SQL | str, dict]]) -> None:
204
+ def execute_multiple(self, queries: list[tuple[SQL | str, dict]]) -> None:
159
205
  """
160
206
  Execute multiple queries
161
207
 
@@ -163,7 +209,8 @@ class PostgresConnection(object):
163
209
  :return: None
164
210
  """
165
211
 
166
- with self._session_pool.connection() as connection:
212
+ connection = self._get_connection()
213
+ with connection:
167
214
  for item in queries:
168
215
  query = item[0]
169
216
  packed_values = item[1]
@@ -182,7 +229,8 @@ class PostgresConnection(object):
182
229
  :return: None
183
230
  """
184
231
 
185
- with self._session_pool.connection() as connection:
232
+ connection = self._get_connection()
233
+ with connection:
186
234
  cursor = connection.cursor()
187
235
  cursor.executemany(query, dictionary)
188
236
 
@@ -196,7 +244,8 @@ class PostgresConnection(object):
196
244
  :return: rows
197
245
  """
198
246
 
199
- with self._session_pool.connection() as connection:
247
+ connection = self._get_connection()
248
+ with connection:
200
249
  cursor = connection.cursor()
201
250
  if packed_data:
202
251
  cursor.execute(query, packed_data)
@@ -255,7 +304,7 @@ class PostgresConnection(object):
255
304
  if record[key] == '':
256
305
  record[key] = None
257
306
 
258
- query = """INSERT INTO {} ({}) VALUES ({})""".format(outputTableName, col, params)
307
+ query = f"INSERT INTO {outputTableName} ({col}) VALUES ({params})"
259
308
  self.execute_many(query, main_dict)
260
309
 
261
310
  @retry
@@ -267,7 +316,7 @@ class PostgresConnection(object):
267
316
  :return: None
268
317
  """
269
318
 
270
- truncateQuery = """TRUNCATE TABLE {}""".format(tableName)
319
+ truncateQuery = f"TRUNCATE TABLE {tableName}"
271
320
  self.execute(truncateQuery)
272
321
 
273
322
  @retry
@@ -279,7 +328,7 @@ class PostgresConnection(object):
279
328
  :return: None
280
329
  """
281
330
 
282
- deleteQuery = """DELETE FROM {}""".format(tableName)
331
+ deleteQuery = f"DELETE FROM {tableName}"
283
332
  self.execute(deleteQuery)
284
333
 
285
334
  def __del__(self) -> None:
@@ -289,7 +338,12 @@ class PostgresConnection(object):
289
338
  :return: None
290
339
  """
291
340
 
292
- self._session_pool.close()
341
+ if self._session_pool is not None:
342
+ self._session_pool.close()
343
+ else:
344
+ if self._connection is not None and not self._connection.closed:
345
+ self._connection.close()
346
+ self._connection = None
293
347
 
294
348
 
295
349
  class AsyncPostgresConnection(object):
@@ -299,14 +353,16 @@ class AsyncPostgresConnection(object):
299
353
  :return: None
300
354
  """
301
355
 
302
- def __init__(self, min_connections: int = 2, max_connections: int = 5):
356
+ def __init__(self, use_pool: bool = False, min_connections: int = 2, max_connections: int = 5):
303
357
  self._username: Optional[str] = None
304
358
  self._password: Optional[str] = None
305
359
  self._hostname: Optional[str] = None
306
360
  self._port: Optional[int] = None
307
361
  self._database: Optional[str] = None
362
+ self._connection: Optional[AsyncConnection] = None
308
363
  self._session_pool: Optional[AsyncConnectionPool] = None
309
364
 
365
+ self.use_pool = use_pool
310
366
  self.min_connections = min_connections
311
367
  self.max_connections = max_connections
312
368
 
@@ -322,9 +378,30 @@ class AsyncPostgresConnection(object):
322
378
  :return: None
323
379
  """
324
380
 
325
- self._session_pool = await _async_connect_warehouse(self._username, self._password, self._hostname, self._port,
326
- self._database, self.min_connections, self.max_connections)
327
- await self._session_pool.open()
381
+ connection = await _async_connect_warehouse(self._username, self._password, self._hostname, self._port,
382
+ self._database, self.min_connections, self.max_connections,
383
+ self.use_pool)
384
+ if self.use_pool:
385
+ self._session_pool = connection
386
+ await self._session_pool.open()
387
+ else:
388
+ self._connection = connection
389
+
390
+ async def _get_connection(self) -> AsyncConnection:
391
+ """
392
+ Get the connection object
393
+
394
+ :return: connection
395
+ """
396
+
397
+ if self.use_pool:
398
+ connection = await self._session_pool.getconn()
399
+ return connection
400
+ else:
401
+ if self._connection is None or self._connection.closed:
402
+ await self._connect()
403
+ return self._connection
404
+
328
405
 
329
406
  async def set_user(self, credentials_dict: dict) -> None:
330
407
  """
@@ -349,7 +426,12 @@ class AsyncPostgresConnection(object):
349
426
  :return: None
350
427
  """
351
428
 
352
- await self._session_pool.close()
429
+ if self.use_pool:
430
+ await self._session_pool.close()
431
+ else:
432
+ if self._connection is not None and not self._connection.closed:
433
+ await self._connection.close()
434
+ self._connection = None
353
435
 
354
436
  @async_retry
355
437
  async def execute(self, query: SQL | str) -> None:
@@ -360,9 +442,13 @@ class AsyncPostgresConnection(object):
360
442
  :return: None
361
443
  """
362
444
 
363
- async with self._session_pool.connection() as connection:
445
+ connection = await self._get_connection()
446
+ async with connection:
364
447
  await connection.execute(query)
365
448
 
449
+ if self.use_pool:
450
+ await self._session_pool.putconn(connection)
451
+
366
452
  @async_retry
367
453
  async def safe_execute(self, query: SQL | str, packed_values: dict) -> None:
368
454
  """
@@ -373,11 +459,15 @@ class AsyncPostgresConnection(object):
373
459
  :return: None
374
460
  """
375
461
 
376
- async with self._session_pool.connection() as connection:
462
+ connection = await self._get_connection()
463
+ async with connection:
377
464
  await connection.execute(query, packed_values)
378
465
 
466
+ if self.use_pool:
467
+ await self._session_pool.putconn(connection)
468
+
379
469
  @async_retry
380
- async def execute_multiple(self, queries: list[list[SQL | str, dict]]) -> None:
470
+ async def execute_multiple(self, queries: list[tuple[SQL | str, dict]]) -> None:
381
471
  """
382
472
  Execute multiple queries
383
473
 
@@ -385,7 +475,8 @@ class AsyncPostgresConnection(object):
385
475
  :return: None
386
476
  """
387
477
 
388
- async with self._session_pool.connection() as connection:
478
+ connection = await self._get_connection()
479
+ async with connection:
389
480
  for item in queries:
390
481
  query = item[0]
391
482
  packed_values = item[1]
@@ -394,6 +485,9 @@ class AsyncPostgresConnection(object):
394
485
  else:
395
486
  await connection.execute(query)
396
487
 
488
+ if self.use_pool:
489
+ await self._session_pool.putconn(connection)
490
+
397
491
  @async_retry
398
492
  async def execute_many(self, query: SQL | str, dictionary: list[dict]) -> None:
399
493
  """
@@ -404,10 +498,14 @@ class AsyncPostgresConnection(object):
404
498
  :return: None
405
499
  """
406
500
 
407
- async with self._session_pool.connection() as connection:
501
+ connection = await self._get_connection()
502
+ async with connection:
408
503
  cursor = connection.cursor()
409
504
  await cursor.executemany(query, dictionary)
410
505
 
506
+ if self.use_pool:
507
+ await self._session_pool.putconn(connection)
508
+
411
509
  @async_retry
412
510
  async def fetch_data(self, query: SQL | str, packed_data=None) -> list[tuple]:
413
511
  """
@@ -418,13 +516,17 @@ class AsyncPostgresConnection(object):
418
516
  :return: rows
419
517
  """
420
518
 
421
- async with self._session_pool.connection() as connection:
519
+ connection = await self._get_connection()
520
+ async with connection:
422
521
  cursor = connection.cursor()
423
522
  if packed_data:
424
523
  await cursor.execute(query, packed_data)
425
524
  else:
426
525
  await cursor.execute(query)
427
526
  rows = await cursor.fetchall()
527
+
528
+ if self.use_pool:
529
+ await self._session_pool.putconn(connection)
428
530
  return rows
429
531
 
430
532
  @async_retry
@@ -448,7 +550,7 @@ class AsyncPostgresConnection(object):
448
550
  params = param_list[0]
449
551
 
450
552
  main_dict = df.to_dict('records')
451
- query = """DELETE FROM {} WHERE {}""".format(outputTableName, params)
553
+ query = f"DELETE FROM {outputTableName} WHERE {params}"
452
554
  await self.execute_many(query, main_dict)
453
555
 
454
556
  @async_retry
@@ -477,7 +579,7 @@ class AsyncPostgresConnection(object):
477
579
  if record[key] == '':
478
580
  record[key] = None
479
581
 
480
- query = """INSERT INTO {} ({}) VALUES ({})""".format(outputTableName, col, params)
582
+ query = f"INSERT INTO {outputTableName} ({col}) VALUES ({params})"
481
583
  await self.execute_many(query, main_dict)
482
584
 
483
585
  @async_retry
@@ -489,7 +591,7 @@ class AsyncPostgresConnection(object):
489
591
  :return: None
490
592
  """
491
593
 
492
- truncateQuery = """TRUNCATE TABLE {}""".format(tableName)
594
+ truncateQuery = f"TRUNCATE TABLE {tableName}"
493
595
  await self.execute(truncateQuery)
494
596
 
495
597
  @async_retry
@@ -501,5 +603,5 @@ class AsyncPostgresConnection(object):
501
603
  :return: None
502
604
  """
503
605
 
504
- deleteQuery = """DELETE FROM {}""".format(tableName)
606
+ deleteQuery = f"DELETE FROM {tableName}"
505
607
  await self.execute(deleteQuery)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: wcp-library
3
- Version: 1.5.6
3
+ Version: 1.5.8
4
4
  Summary: Common utilites for internal development at WCP
5
5
  Author: Mitch-Petersen
6
6
  Author-email: mitch.petersen@wcap.ca
@@ -16,10 +16,10 @@ wcp_library/logging.py,sha256=e6gG7HFgUrMajUZs4Gs0atFfOJJmdmxN0GerfynNWlY,2061
16
16
  wcp_library/selenium/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  wcp_library/selenium/_selenium_driver.py,sha256=Es83ISNryOVhYGDo_xrr8nCLsbnVBeXsaz1sRiz7kLI,2961
18
18
  wcp_library/selenium/selenium_helper.py,sha256=OJvC0RlblfMWhmjNxiY582yuzkDgjzFZMuRz_8to3PY,2000
19
- wcp_library/sql/__init__.py,sha256=ocKH9-1HPDF5OhUKkpby3uNvQ6RBt2YD81nwwS90PgE,1980
20
- wcp_library/sql/oracle.py,sha256=jcGoH2iGkgxW-RJV5FRf_CwNzilkxPN6_pJ27te5Qe0,15815
21
- wcp_library/sql/postgres.py,sha256=lPcsmX0ejEgCRmNKWL9Wp_7R8sop5_KcWmpLieTGT1I,14938
19
+ wcp_library/sql/__init__.py,sha256=f0JyVyFyUjueQ1XdVmCgmRjzkFENmFKl3BOzrvv3i1I,2422
20
+ wcp_library/sql/oracle.py,sha256=L2UG-0jQNYSvTy9OAxRjWLIEIpfbLrIXeddYfuC3ipA,18812
21
+ wcp_library/sql/postgres.py,sha256=OH0p7sjQDyv1zqFfnvrsFh6R82LDh-fB5HW_FDfOMn8,18329
22
22
  wcp_library/time.py,sha256=ktSzhK7SZnGPNXobFexnhFGQAcriLCJQKxnO0fed8fQ,1740
23
- wcp_library-1.5.6.dist-info/METADATA,sha256=7JyNWin_He1VyxYXAw8MKRVto7xv3kP7cVpY8ZInU0U,1393
24
- wcp_library-1.5.6.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
25
- wcp_library-1.5.6.dist-info/RECORD,,
23
+ wcp_library-1.5.8.dist-info/METADATA,sha256=Kul1UZxy1MNUSUpNVUh0qvUWg5ohIsL6tA2f0Y7zkgo,1393
24
+ wcp_library-1.5.8.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
25
+ wcp_library-1.5.8.dist-info/RECORD,,