dycw-utilities 0.149.11__py3-none-any.whl → 0.150.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.149.11
3
+ Version: 0.150.1
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=ODa44fHOmk12CX4kZdMwXIvOfgua6psr4jhzHKVTZf0,61
1
+ utilities/__init__.py,sha256=-ff8DCsQu3pztocOWVj0HdCbLUhyIgoNX_Q2gilrFmI,60
2
2
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
3
3
  utilities/asyncio.py,sha256=2m2a2C-Qgc6OHTTHL332-t66A7xDITt_SORT7a1DJWo,16792
4
4
  utilities/atomicwrites.py,sha256=xcOWenTBRS0oat3kg7Sqe51AohNThMQ2ixPL7QCG8hw,5795
@@ -66,7 +66,7 @@ utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
66
66
  utilities/shelve.py,sha256=4OzjQI6kGuUbJciqf535rwnao-_IBv66gsT6tRGiUt0,759
67
67
  utilities/slack_sdk.py,sha256=ppFBvKgfg5IRWiIoKPtpTyzBtBF4XmwEvU3I5wLJikM,2140
68
68
  utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
69
- utilities/sqlalchemy.py,sha256=q2aYUDAC3SE88Lt6XaKa3CLzT_ePaWvQu_OuRk19x9g,35520
69
+ utilities/sqlalchemy.py,sha256=5TPqPvJUCuxIeiMD7IKTptYg11UXNy7ThGw81reCIRU,37290
70
70
  utilities/sqlalchemy_polars.py,sha256=18AoEbeNJUKF3-5hroNy9J5LQwS_QJAXbMfKc9sChtk,14250
71
71
  utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
72
72
  utilities/string.py,sha256=MB0X6UPTUc06JdAdj-PctZ238IXeCjE5dAJibNw6ZrU,587
@@ -89,8 +89,8 @@ utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
89
89
  utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
90
90
  utilities/pytest_plugins/pytest_randomly.py,sha256=NXzCcGKbpgYouz5yehKb4jmxmi2SexKKpgF4M65bi10,414
91
91
  utilities/pytest_plugins/pytest_regressions.py,sha256=Iwhfv_OJH7UCPZCfoh7ugZ2Xjqjil-BBBsOb8sDwiGI,1471
92
- dycw_utilities-0.149.11.dist-info/METADATA,sha256=wXNAZioNfRMvkYH6pANvwG5RbGy1D-9z7hSwmANMABA,1698
93
- dycw_utilities-0.149.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- dycw_utilities-0.149.11.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
95
- dycw_utilities-0.149.11.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
96
- dycw_utilities-0.149.11.dist-info/RECORD,,
92
+ dycw_utilities-0.150.1.dist-info/METADATA,sha256=VjJ5-xcBd6dgd7vO_L77EpWzPfx021Ic9JkmEV8KoVI,1697
93
+ dycw_utilities-0.150.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ dycw_utilities-0.150.1.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
95
+ dycw_utilities-0.150.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
96
+ dycw_utilities-0.150.1.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.149.11"
3
+ __version__ = "0.150.1"
utilities/sqlalchemy.py CHANGED
@@ -18,8 +18,19 @@ from itertools import chain
18
18
  from math import floor
19
19
  from operator import ge, le
20
20
  from re import search
21
- from typing import TYPE_CHECKING, Any, Literal, TypeGuard, assert_never, cast, override
21
+ from typing import (
22
+ TYPE_CHECKING,
23
+ Any,
24
+ Literal,
25
+ TypeGuard,
26
+ assert_never,
27
+ cast,
28
+ overload,
29
+ override,
30
+ )
22
31
 
32
+ import sqlalchemy
33
+ import sqlalchemy.ext.asyncio
23
34
  from sqlalchemy import (
24
35
  URL,
25
36
  Column,
@@ -42,12 +53,17 @@ from sqlalchemy.dialects.postgresql import Insert as postgresql_Insert
42
53
  from sqlalchemy.dialects.postgresql import dialect as postgresql_dialect
43
54
  from sqlalchemy.dialects.postgresql import insert as postgresql_insert
44
55
  from sqlalchemy.dialects.postgresql.asyncpg import PGDialect_asyncpg
56
+ from sqlalchemy.dialects.postgresql.psycopg import PGDialect_psycopg
45
57
  from sqlalchemy.dialects.sqlite import Insert as sqlite_Insert
46
58
  from sqlalchemy.dialects.sqlite import dialect as sqlite_dialect
47
59
  from sqlalchemy.dialects.sqlite import insert as sqlite_insert
48
- from sqlalchemy.exc import ArgumentError, DatabaseError
60
+ from sqlalchemy.exc import (
61
+ ArgumentError,
62
+ DatabaseError,
63
+ OperationalError,
64
+ ProgrammingError,
65
+ )
49
66
  from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine
50
- from sqlalchemy.ext.asyncio import create_async_engine as _create_async_engine
51
67
  from sqlalchemy.orm import (
52
68
  DeclarativeBase,
53
69
  InstrumentedAttribute,
@@ -99,6 +115,18 @@ CHUNK_SIZE_FRAC = 0.8
99
115
  ##
100
116
 
101
117
 
118
+ def check_connect(engine: Engine, /) -> bool:
119
+ """Check if an engine can connect."""
120
+ try:
121
+ with engine.connect() as conn:
122
+ return bool(conn.execute(text("SELECT 1")).scalar_one())
123
+ except (OperationalError, ProgrammingError):
124
+ return False
125
+
126
+
127
+ ##
128
+
129
+
102
130
  async def check_engine(
103
131
  engine: AsyncEngine,
104
132
  /,
@@ -187,7 +215,8 @@ def _columnwise_minmax(*columns: Any, op: Callable[[Any, Any], Any]) -> Any:
187
215
  ##
188
216
 
189
217
 
190
- def create_async_engine(
218
+ @overload
219
+ def create_engine(
191
220
  drivername: str,
192
221
  /,
193
222
  *,
@@ -198,7 +227,49 @@ def create_async_engine(
198
227
  database: str | None = None,
199
228
  query: StrMapping | None = None,
200
229
  poolclass: type[Pool] | None = NullPool,
201
- ) -> AsyncEngine:
230
+ async_: Literal[True],
231
+ ) -> AsyncEngine: ...
232
+ @overload
233
+ def create_engine(
234
+ drivername: str,
235
+ /,
236
+ *,
237
+ username: str | None = None,
238
+ password: str | None = None,
239
+ host: str | None = None,
240
+ port: int | None = None,
241
+ database: str | None = None,
242
+ query: StrMapping | None = None,
243
+ poolclass: type[Pool] | None = NullPool,
244
+ async_: Literal[False] = False,
245
+ ) -> Engine: ...
246
+ @overload
247
+ def create_engine(
248
+ drivername: str,
249
+ /,
250
+ *,
251
+ username: str | None = None,
252
+ password: str | None = None,
253
+ host: str | None = None,
254
+ port: int | None = None,
255
+ database: str | None = None,
256
+ query: StrMapping | None = None,
257
+ poolclass: type[Pool] | None = NullPool,
258
+ async_: bool = False,
259
+ ) -> Engine | AsyncEngine: ...
260
+ def create_engine(
261
+ drivername: str,
262
+ /,
263
+ *,
264
+ username: str | None = None,
265
+ password: str | None = None,
266
+ host: str | None = None,
267
+ port: int | None = None,
268
+ database: str | None = None,
269
+ query: StrMapping | None = None,
270
+ poolclass: type[Pool] | None = NullPool,
271
+ async_: bool = False,
272
+ ) -> Engine | AsyncEngine:
202
273
  """Create a SQLAlchemy engine."""
203
274
  if query is None:
204
275
  kwargs = {}
@@ -217,7 +288,13 @@ def create_async_engine(
217
288
  database=database,
218
289
  **kwargs,
219
290
  )
220
- return _create_async_engine(url, poolclass=poolclass)
291
+ match async_:
292
+ case False:
293
+ return sqlalchemy.create_engine(url, poolclass=poolclass)
294
+ case True:
295
+ return sqlalchemy.ext.asyncio.create_async_engine(url, poolclass=poolclass)
296
+ case _ as never:
297
+ assert_never(never)
221
298
 
222
299
 
223
300
  ##
@@ -825,7 +902,7 @@ def _get_dialect(engine_or_conn: EngineOrConnectionOrAsync, /) -> Dialect:
825
902
  if isinstance(dialect, oracle_dialect): # pragma: no cover
826
903
  return "oracle"
827
904
  if isinstance( # skipif-ci-and-not-linux
828
- dialect, postgresql_dialect | PGDialect_asyncpg
905
+ dialect, (postgresql_dialect, PGDialect_asyncpg, PGDialect_psycopg)
829
906
  ):
830
907
  return "postgresql"
831
908
  if isinstance(dialect, sqlite_dialect):
@@ -1107,10 +1184,11 @@ __all__ = [
1107
1184
  "InsertItemsError",
1108
1185
  "TablenameMixin",
1109
1186
  "UpsertItemsError",
1187
+ "check_connect",
1110
1188
  "check_engine",
1111
1189
  "columnwise_max",
1112
1190
  "columnwise_min",
1113
- "create_async_engine",
1191
+ "create_engine",
1114
1192
  "ensure_tables_created",
1115
1193
  "ensure_tables_dropped",
1116
1194
  "enum_name",