wcp-library 1.5.7__py3-none-any.whl → 1.6.1__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.
- wcp_library/sql/__init__.py +8 -8
- wcp_library/sql/oracle.py +166 -81
- wcp_library/sql/postgres.py +163 -47
- {wcp_library-1.5.7.dist-info → wcp_library-1.6.1.dist-info}/METADATA +1 -1
- {wcp_library-1.5.7.dist-info → wcp_library-1.6.1.dist-info}/RECORD +6 -6
- {wcp_library-1.5.7.dist-info → wcp_library-1.6.1.dist-info}/WHEEL +0 -0
wcp_library/sql/__init__.py
CHANGED
@@ -9,20 +9,20 @@ import psycopg
|
|
9
9
|
logger = logging.getLogger(__name__)
|
10
10
|
|
11
11
|
|
12
|
-
def retry(
|
12
|
+
def retry(func: callable) -> callable:
|
13
13
|
"""
|
14
14
|
Decorator to retry a function
|
15
15
|
|
16
|
-
:param
|
16
|
+
:param func: function
|
17
17
|
:return: function
|
18
18
|
"""
|
19
19
|
|
20
|
-
@wraps(
|
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
|
25
|
+
return func(self, *args, **kwargs)
|
26
26
|
except (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError) as e:
|
27
27
|
if isinstance(e, (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError, psycopg.DatabaseError)):
|
28
28
|
error_obj, = e.args
|
@@ -38,20 +38,20 @@ def retry(f: callable) -> callable:
|
|
38
38
|
return wrapper
|
39
39
|
|
40
40
|
|
41
|
-
def async_retry(
|
41
|
+
def async_retry(func: callable) -> callable:
|
42
42
|
"""
|
43
43
|
Decorator to retry a function
|
44
44
|
|
45
|
-
:param
|
45
|
+
:param func: function
|
46
46
|
:return: function
|
47
47
|
"""
|
48
48
|
|
49
|
-
@wraps(
|
49
|
+
@wraps(func)
|
50
50
|
async def wrapper(self, *args, **kwargs):
|
51
51
|
self._retry_count = 0
|
52
52
|
while True:
|
53
53
|
try:
|
54
|
-
return await
|
54
|
+
return await func(self, *args, **kwargs)
|
55
55
|
except (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError) as e:
|
56
56
|
if isinstance(e, (oracledb.OperationalError, oracledb.DatabaseError, psycopg.OperationalError, psycopg.DatabaseError)):
|
57
57
|
error_obj, = e.args
|
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
|
-
:
|
26
|
+
:param use_pool: use connection pool
|
27
|
+
:return: session_pool | connection
|
27
28
|
"""
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
:
|
64
|
+
:param use_pool: use connection pool
|
65
|
+
:return: session_pool | connection
|
54
66
|
"""
|
55
67
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
105
|
-
|
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.
|
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.
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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.
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
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[
|
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.
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
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.
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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.
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
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 ({})"""
|
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 {}"""
|
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 {}"""
|
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.
|
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
|
-
|
342
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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[
|
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
|
-
|
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
|
-
|
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
|
-
|
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 ({})"""
|
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 {}"""
|
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 {}"""
|
611
|
+
deleteQuery = f"""DELETE FROM {tableName}"""
|
527
612
|
await self.execute(deleteQuery)
|
wcp_library/sql/postgres.py
CHANGED
@@ -3,6 +3,8 @@ from typing import Optional
|
|
3
3
|
|
4
4
|
import numpy as np
|
5
5
|
import pandas as pd
|
6
|
+
import psycopg
|
7
|
+
from psycopg import AsyncConnection, Connection
|
6
8
|
from psycopg.conninfo import make_conninfo
|
7
9
|
from psycopg.sql import SQL
|
8
10
|
from psycopg_pool import AsyncConnectionPool, ConnectionPool
|
@@ -13,7 +15,7 @@ logger = logging.getLogger(__name__)
|
|
13
15
|
|
14
16
|
|
15
17
|
def _connect_warehouse(username: str, password: str, hostname: str, port: int, database: str, min_connections: int,
|
16
|
-
max_connections: int) -> ConnectionPool:
|
18
|
+
max_connections: int, use_pool: bool) -> Connection | ConnectionPool:
|
17
19
|
"""
|
18
20
|
Create Warehouse Connection
|
19
21
|
|
@@ -30,18 +32,24 @@ def _connect_warehouse(username: str, password: str, hostname: str, port: int, d
|
|
30
32
|
conn_string = f"dbname={database} user={username} password={password} host={hostname} port={port}"
|
31
33
|
conninfo = make_conninfo(conn_string)
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
if use_pool:
|
36
|
+
logger.debug(f"Creating connection pool with min size {min_connections} and max size {max_connections}")
|
37
|
+
session_pool = ConnectionPool(
|
38
|
+
conninfo=conninfo,
|
39
|
+
min_size=min_connections,
|
40
|
+
max_size=max_connections,
|
41
|
+
kwargs={'options': '-c datestyle=ISO,YMD'},
|
42
|
+
open=True
|
43
|
+
)
|
44
|
+
return session_pool
|
45
|
+
else:
|
46
|
+
logger.debug("Creating single connection")
|
47
|
+
connection = psycopg.connect(conninfo=conninfo, options='-c datestyle=ISO,YMD')
|
48
|
+
return connection
|
41
49
|
|
42
50
|
|
43
51
|
async def _async_connect_warehouse(username: str, password: str, hostname: str, port: int, database: str, min_connections: int,
|
44
|
-
|
52
|
+
max_connections: int, use_pool: bool) -> AsyncConnection | AsyncConnectionPool:
|
45
53
|
"""
|
46
54
|
Create Warehouse Connection
|
47
55
|
|
@@ -58,14 +66,20 @@ async def _async_connect_warehouse(username: str, password: str, hostname: str,
|
|
58
66
|
conn_string = f"dbname={database} user={username} password={password} host={hostname} port={port}"
|
59
67
|
conninfo = make_conninfo(conn_string)
|
60
68
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
+
if use_pool:
|
70
|
+
logger.debug(f"Creating async connection pool with min size {min_connections} and max size {max_connections}")
|
71
|
+
session_pool = AsyncConnectionPool(
|
72
|
+
conninfo=conninfo,
|
73
|
+
min_size=min_connections,
|
74
|
+
max_size=max_connections,
|
75
|
+
kwargs={"options": "-c datestyle=ISO,YMD"},
|
76
|
+
open=False
|
77
|
+
)
|
78
|
+
return session_pool
|
79
|
+
else:
|
80
|
+
logger.debug("Creating single async connection")
|
81
|
+
connection = await AsyncConnection.connect(conninfo=conninfo, options='-c datestyle=ISO,YMD')
|
82
|
+
return connection
|
69
83
|
|
70
84
|
|
71
85
|
"""~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"""
|
@@ -78,14 +92,16 @@ class PostgresConnection(object):
|
|
78
92
|
:return: None
|
79
93
|
"""
|
80
94
|
|
81
|
-
def __init__(self, min_connections: int = 2, max_connections: int = 5):
|
95
|
+
def __init__(self, use_pool: bool = False, min_connections: int = 2, max_connections: int = 5):
|
82
96
|
self._username: Optional[str] = None
|
83
97
|
self._password: Optional[str] = None
|
84
98
|
self._hostname: Optional[str] = None
|
85
99
|
self._port: Optional[int] = None
|
86
100
|
self._database: Optional[str] = None
|
101
|
+
self._connection: Optional[Connection] = None
|
87
102
|
self._session_pool: Optional[ConnectionPool] = None
|
88
103
|
|
104
|
+
self.use_pool = use_pool
|
89
105
|
self.min_connections = min_connections
|
90
106
|
self.max_connections = max_connections
|
91
107
|
|
@@ -101,8 +117,30 @@ class PostgresConnection(object):
|
|
101
117
|
:return: None
|
102
118
|
"""
|
103
119
|
|
104
|
-
|
105
|
-
|
120
|
+
|
121
|
+
self.connection = _connect_warehouse(self._username, self._password, self._hostname, self._port,
|
122
|
+
self._database, self.min_connections, self.max_connections, self.use_pool)
|
123
|
+
|
124
|
+
if self.use_pool:
|
125
|
+
self._session_pool = self.connection
|
126
|
+
self._session_pool.open()
|
127
|
+
else:
|
128
|
+
self._connection = self.connection
|
129
|
+
|
130
|
+
def _get_connection(self) -> Connection:
|
131
|
+
"""
|
132
|
+
Get the connection object
|
133
|
+
|
134
|
+
:return: connection
|
135
|
+
"""
|
136
|
+
|
137
|
+
if self.use_pool:
|
138
|
+
connection = self._session_pool.getconn()
|
139
|
+
return connection
|
140
|
+
else:
|
141
|
+
if self._connection is None or self._connection.closed:
|
142
|
+
self._connect()
|
143
|
+
return self._connection
|
106
144
|
|
107
145
|
def set_user(self, credentials_dict: dict) -> None:
|
108
146
|
"""
|
@@ -127,7 +165,12 @@ class PostgresConnection(object):
|
|
127
165
|
:return: None
|
128
166
|
"""
|
129
167
|
|
130
|
-
self.
|
168
|
+
if self.use_pool:
|
169
|
+
self._session_pool.close()
|
170
|
+
else:
|
171
|
+
if self._connection is not None and not self._connection.closed:
|
172
|
+
self._connection.close()
|
173
|
+
self._connection = None
|
131
174
|
|
132
175
|
@retry
|
133
176
|
def execute(self, query: SQL | str) -> None:
|
@@ -138,9 +181,13 @@ class PostgresConnection(object):
|
|
138
181
|
:return: None
|
139
182
|
"""
|
140
183
|
|
141
|
-
|
184
|
+
connection = self._get_connection()
|
185
|
+
with connection:
|
142
186
|
connection.execute(query)
|
143
187
|
|
188
|
+
if self.use_pool:
|
189
|
+
self._session_pool.putconn(connection)
|
190
|
+
|
144
191
|
@retry
|
145
192
|
def safe_execute(self, query: SQL | str, packed_values: dict) -> None:
|
146
193
|
"""
|
@@ -151,11 +198,15 @@ class PostgresConnection(object):
|
|
151
198
|
:return: None
|
152
199
|
"""
|
153
200
|
|
154
|
-
|
201
|
+
connection = self._get_connection()
|
202
|
+
with connection:
|
155
203
|
connection.execute(query, packed_values)
|
156
204
|
|
205
|
+
if self.use_pool:
|
206
|
+
self._session_pool.putconn(connection)
|
207
|
+
|
157
208
|
@retry
|
158
|
-
def execute_multiple(self, queries: list[
|
209
|
+
def execute_multiple(self, queries: list[tuple[SQL | str, dict]]) -> None:
|
159
210
|
"""
|
160
211
|
Execute multiple queries
|
161
212
|
|
@@ -163,7 +214,8 @@ class PostgresConnection(object):
|
|
163
214
|
:return: None
|
164
215
|
"""
|
165
216
|
|
166
|
-
|
217
|
+
connection = self._get_connection()
|
218
|
+
with connection:
|
167
219
|
for item in queries:
|
168
220
|
query = item[0]
|
169
221
|
packed_values = item[1]
|
@@ -172,6 +224,9 @@ class PostgresConnection(object):
|
|
172
224
|
else:
|
173
225
|
connection.execute(query)
|
174
226
|
|
227
|
+
if self.use_pool:
|
228
|
+
self._session_pool.putconn(connection)
|
229
|
+
|
175
230
|
@retry
|
176
231
|
def execute_many(self, query: SQL | str, dictionary: list[dict]) -> None:
|
177
232
|
"""
|
@@ -182,10 +237,14 @@ class PostgresConnection(object):
|
|
182
237
|
:return: None
|
183
238
|
"""
|
184
239
|
|
185
|
-
|
240
|
+
connection = self._get_connection()
|
241
|
+
with connection:
|
186
242
|
cursor = connection.cursor()
|
187
243
|
cursor.executemany(query, dictionary)
|
188
244
|
|
245
|
+
if self.use_pool:
|
246
|
+
self._session_pool.putconn(connection)
|
247
|
+
|
189
248
|
@retry
|
190
249
|
def fetch_data(self, query: SQL | str, packed_data=None) -> list[tuple]:
|
191
250
|
"""
|
@@ -196,13 +255,17 @@ class PostgresConnection(object):
|
|
196
255
|
:return: rows
|
197
256
|
"""
|
198
257
|
|
199
|
-
|
258
|
+
connection = self._get_connection()
|
259
|
+
with connection:
|
200
260
|
cursor = connection.cursor()
|
201
261
|
if packed_data:
|
202
262
|
cursor.execute(query, packed_data)
|
203
263
|
else:
|
204
264
|
cursor.execute(query)
|
205
265
|
rows = cursor.fetchall()
|
266
|
+
|
267
|
+
if self.use_pool:
|
268
|
+
self._session_pool.putconn(connection)
|
206
269
|
return rows
|
207
270
|
|
208
271
|
@retry
|
@@ -255,7 +318,7 @@ class PostgresConnection(object):
|
|
255
318
|
if record[key] == '':
|
256
319
|
record[key] = None
|
257
320
|
|
258
|
-
query = "
|
321
|
+
query = f"INSERT INTO {outputTableName} ({col}) VALUES ({params})"
|
259
322
|
self.execute_many(query, main_dict)
|
260
323
|
|
261
324
|
@retry
|
@@ -267,7 +330,7 @@ class PostgresConnection(object):
|
|
267
330
|
:return: None
|
268
331
|
"""
|
269
332
|
|
270
|
-
truncateQuery = "
|
333
|
+
truncateQuery = f"TRUNCATE TABLE {tableName}"
|
271
334
|
self.execute(truncateQuery)
|
272
335
|
|
273
336
|
@retry
|
@@ -279,7 +342,7 @@ class PostgresConnection(object):
|
|
279
342
|
:return: None
|
280
343
|
"""
|
281
344
|
|
282
|
-
deleteQuery = "
|
345
|
+
deleteQuery = f"DELETE FROM {tableName}"
|
283
346
|
self.execute(deleteQuery)
|
284
347
|
|
285
348
|
def __del__(self) -> None:
|
@@ -289,7 +352,12 @@ class PostgresConnection(object):
|
|
289
352
|
:return: None
|
290
353
|
"""
|
291
354
|
|
292
|
-
self._session_pool
|
355
|
+
if self._session_pool is not None:
|
356
|
+
self._session_pool.close()
|
357
|
+
else:
|
358
|
+
if self._connection is not None and not self._connection.closed:
|
359
|
+
self._connection.close()
|
360
|
+
self._connection = None
|
293
361
|
|
294
362
|
|
295
363
|
class AsyncPostgresConnection(object):
|
@@ -299,14 +367,16 @@ class AsyncPostgresConnection(object):
|
|
299
367
|
:return: None
|
300
368
|
"""
|
301
369
|
|
302
|
-
def __init__(self, min_connections: int = 2, max_connections: int = 5):
|
370
|
+
def __init__(self, use_pool: bool = False, min_connections: int = 2, max_connections: int = 5):
|
303
371
|
self._username: Optional[str] = None
|
304
372
|
self._password: Optional[str] = None
|
305
373
|
self._hostname: Optional[str] = None
|
306
374
|
self._port: Optional[int] = None
|
307
375
|
self._database: Optional[str] = None
|
376
|
+
self._connection: Optional[AsyncConnection] = None
|
308
377
|
self._session_pool: Optional[AsyncConnectionPool] = None
|
309
378
|
|
379
|
+
self.use_pool = use_pool
|
310
380
|
self.min_connections = min_connections
|
311
381
|
self.max_connections = max_connections
|
312
382
|
|
@@ -322,9 +392,30 @@ class AsyncPostgresConnection(object):
|
|
322
392
|
:return: None
|
323
393
|
"""
|
324
394
|
|
325
|
-
|
326
|
-
|
327
|
-
|
395
|
+
connection = await _async_connect_warehouse(self._username, self._password, self._hostname, self._port,
|
396
|
+
self._database, self.min_connections, self.max_connections,
|
397
|
+
self.use_pool)
|
398
|
+
if self.use_pool:
|
399
|
+
self._session_pool = connection
|
400
|
+
await self._session_pool.open()
|
401
|
+
else:
|
402
|
+
self._connection = connection
|
403
|
+
|
404
|
+
async def _get_connection(self) -> AsyncConnection:
|
405
|
+
"""
|
406
|
+
Get the connection object
|
407
|
+
|
408
|
+
:return: connection
|
409
|
+
"""
|
410
|
+
|
411
|
+
if self.use_pool:
|
412
|
+
connection = await self._session_pool.getconn()
|
413
|
+
return connection
|
414
|
+
else:
|
415
|
+
if self._connection is None or self._connection.closed:
|
416
|
+
await self._connect()
|
417
|
+
return self._connection
|
418
|
+
|
328
419
|
|
329
420
|
async def set_user(self, credentials_dict: dict) -> None:
|
330
421
|
"""
|
@@ -349,7 +440,12 @@ class AsyncPostgresConnection(object):
|
|
349
440
|
:return: None
|
350
441
|
"""
|
351
442
|
|
352
|
-
|
443
|
+
if self.use_pool:
|
444
|
+
await self._session_pool.close()
|
445
|
+
else:
|
446
|
+
if self._connection is not None and not self._connection.closed:
|
447
|
+
await self._connection.close()
|
448
|
+
self._connection = None
|
353
449
|
|
354
450
|
@async_retry
|
355
451
|
async def execute(self, query: SQL | str) -> None:
|
@@ -360,9 +456,13 @@ class AsyncPostgresConnection(object):
|
|
360
456
|
:return: None
|
361
457
|
"""
|
362
458
|
|
363
|
-
|
459
|
+
connection = await self._get_connection()
|
460
|
+
async with connection:
|
364
461
|
await connection.execute(query)
|
365
462
|
|
463
|
+
if self.use_pool:
|
464
|
+
await self._session_pool.putconn(connection)
|
465
|
+
|
366
466
|
@async_retry
|
367
467
|
async def safe_execute(self, query: SQL | str, packed_values: dict) -> None:
|
368
468
|
"""
|
@@ -373,11 +473,15 @@ class AsyncPostgresConnection(object):
|
|
373
473
|
:return: None
|
374
474
|
"""
|
375
475
|
|
376
|
-
|
476
|
+
connection = await self._get_connection()
|
477
|
+
async with connection:
|
377
478
|
await connection.execute(query, packed_values)
|
378
479
|
|
480
|
+
if self.use_pool:
|
481
|
+
await self._session_pool.putconn(connection)
|
482
|
+
|
379
483
|
@async_retry
|
380
|
-
async def execute_multiple(self, queries: list[
|
484
|
+
async def execute_multiple(self, queries: list[tuple[SQL | str, dict]]) -> None:
|
381
485
|
"""
|
382
486
|
Execute multiple queries
|
383
487
|
|
@@ -385,7 +489,8 @@ class AsyncPostgresConnection(object):
|
|
385
489
|
:return: None
|
386
490
|
"""
|
387
491
|
|
388
|
-
|
492
|
+
connection = await self._get_connection()
|
493
|
+
async with connection:
|
389
494
|
for item in queries:
|
390
495
|
query = item[0]
|
391
496
|
packed_values = item[1]
|
@@ -394,6 +499,9 @@ class AsyncPostgresConnection(object):
|
|
394
499
|
else:
|
395
500
|
await connection.execute(query)
|
396
501
|
|
502
|
+
if self.use_pool:
|
503
|
+
await self._session_pool.putconn(connection)
|
504
|
+
|
397
505
|
@async_retry
|
398
506
|
async def execute_many(self, query: SQL | str, dictionary: list[dict]) -> None:
|
399
507
|
"""
|
@@ -404,10 +512,14 @@ class AsyncPostgresConnection(object):
|
|
404
512
|
:return: None
|
405
513
|
"""
|
406
514
|
|
407
|
-
|
515
|
+
connection = await self._get_connection()
|
516
|
+
async with connection:
|
408
517
|
cursor = connection.cursor()
|
409
518
|
await cursor.executemany(query, dictionary)
|
410
519
|
|
520
|
+
if self.use_pool:
|
521
|
+
await self._session_pool.putconn(connection)
|
522
|
+
|
411
523
|
@async_retry
|
412
524
|
async def fetch_data(self, query: SQL | str, packed_data=None) -> list[tuple]:
|
413
525
|
"""
|
@@ -418,13 +530,17 @@ class AsyncPostgresConnection(object):
|
|
418
530
|
:return: rows
|
419
531
|
"""
|
420
532
|
|
421
|
-
|
533
|
+
connection = await self._get_connection()
|
534
|
+
async with connection:
|
422
535
|
cursor = connection.cursor()
|
423
536
|
if packed_data:
|
424
537
|
await cursor.execute(query, packed_data)
|
425
538
|
else:
|
426
539
|
await cursor.execute(query)
|
427
540
|
rows = await cursor.fetchall()
|
541
|
+
|
542
|
+
if self.use_pool:
|
543
|
+
await self._session_pool.putconn(connection)
|
428
544
|
return rows
|
429
545
|
|
430
546
|
@async_retry
|
@@ -448,7 +564,7 @@ class AsyncPostgresConnection(object):
|
|
448
564
|
params = param_list[0]
|
449
565
|
|
450
566
|
main_dict = df.to_dict('records')
|
451
|
-
query = "
|
567
|
+
query = f"DELETE FROM {outputTableName} WHERE {params}"
|
452
568
|
await self.execute_many(query, main_dict)
|
453
569
|
|
454
570
|
@async_retry
|
@@ -477,7 +593,7 @@ class AsyncPostgresConnection(object):
|
|
477
593
|
if record[key] == '':
|
478
594
|
record[key] = None
|
479
595
|
|
480
|
-
query = "
|
596
|
+
query = f"INSERT INTO {outputTableName} ({col}) VALUES ({params})"
|
481
597
|
await self.execute_many(query, main_dict)
|
482
598
|
|
483
599
|
@async_retry
|
@@ -489,7 +605,7 @@ class AsyncPostgresConnection(object):
|
|
489
605
|
:return: None
|
490
606
|
"""
|
491
607
|
|
492
|
-
truncateQuery = "
|
608
|
+
truncateQuery = f"TRUNCATE TABLE {tableName}"
|
493
609
|
await self.execute(truncateQuery)
|
494
610
|
|
495
611
|
@async_retry
|
@@ -501,5 +617,5 @@ class AsyncPostgresConnection(object):
|
|
501
617
|
:return: None
|
502
618
|
"""
|
503
619
|
|
504
|
-
deleteQuery = "
|
620
|
+
deleteQuery = f"DELETE FROM {tableName}"
|
505
621
|
await self.execute(deleteQuery)
|
@@ -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=
|
20
|
-
wcp_library/sql/oracle.py,sha256=
|
21
|
-
wcp_library/sql/postgres.py,sha256=
|
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=I6Mw7QnXHu-aIOe8CiLcqgJ8wNzyjrTy3_bhfEV-2pI,18631
|
22
22
|
wcp_library/time.py,sha256=ktSzhK7SZnGPNXobFexnhFGQAcriLCJQKxnO0fed8fQ,1740
|
23
|
-
wcp_library-1.
|
24
|
-
wcp_library-1.
|
25
|
-
wcp_library-1.
|
23
|
+
wcp_library-1.6.1.dist-info/METADATA,sha256=POlu-hZub7JLGST9pp2bS4wv4YQGgi2PbAMT76kJXUE,1393
|
24
|
+
wcp_library-1.6.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
25
|
+
wcp_library-1.6.1.dist-info/RECORD,,
|
File without changes
|