wcp-library 1.5.7__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.
- wcp_library/sql/__init__.py +8 -8
- wcp_library/sql/oracle.py +166 -81
- wcp_library/sql/postgres.py +150 -48
- {wcp_library-1.5.7.dist-info → wcp_library-1.5.8.dist-info}/METADATA +1 -1
- {wcp_library-1.5.7.dist-info → wcp_library-1.5.8.dist-info}/RECORD +6 -6
- {wcp_library-1.5.7.dist-info → wcp_library-1.5.8.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
@@ -1,8 +1,11 @@
|
|
1
1
|
import logging
|
2
|
-
from
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
105
|
-
|
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.
|
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
|
-
|
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
|
-
|
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[
|
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
|
-
|
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
|
-
|
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
|
-
|
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 = "
|
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 = "
|
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 = "
|
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
|
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
|
-
|
326
|
-
|
327
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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[
|
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
|
-
|
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
|
-
|
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
|
-
|
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 = "
|
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 = "
|
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 = "
|
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 = "
|
606
|
+
deleteQuery = f"DELETE FROM {tableName}"
|
505
607
|
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=OH0p7sjQDyv1zqFfnvrsFh6R82LDh-fB5HW_FDfOMn8,18329
|
22
22
|
wcp_library/time.py,sha256=ktSzhK7SZnGPNXobFexnhFGQAcriLCJQKxnO0fed8fQ,1740
|
23
|
-
wcp_library-1.5.
|
24
|
-
wcp_library-1.5.
|
25
|
-
wcp_library-1.5.
|
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,,
|
File without changes
|