dycw-utilities 0.148.1__py3-none-any.whl → 0.148.3__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.148.1
3
+ Version: 0.148.3
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=iMEViWolW9oRg6PDmC46RTFOqP-O9BCaLj3gJai78wg,60
1
+ utilities/__init__.py,sha256=2R5RFhflbLqa8cgmmyLGluSJBh478f4vSqo-2D-gsrE,60
2
2
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
3
3
  utilities/asyncio.py,sha256=z0w3fb-U5Ml5YXVaFFPClizXaQmjDO6YgZg-V9QL0VQ,16021
4
4
  utilities/atomicwrites.py,sha256=xcOWenTBRS0oat3kg7Sqe51AohNThMQ2ixPL7QCG8hw,5795
@@ -48,7 +48,7 @@ utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
48
48
  utilities/platform.py,sha256=Ue9LSxYvg9yUXGKuz5aZoy_qkUEXde-v6B09exgSctU,2813
49
49
  utilities/polars.py,sha256=BgiDryAVOapi41ddfJqN0wYh_sDj8BNEYtPB36LaHdo,71824
50
50
  utilities/polars_ols.py,sha256=Uc9V5kvlWZ5cU93lKZ-cfAKdVFFw81tqwLW9PxtUvMs,5618
51
- utilities/postgres.py,sha256=dbQrUFOoV6huNeuYTnSpNhSNq-QhXkBfrJPMtoAGJtY,7877
51
+ utilities/postgres.py,sha256=3xuJ_EWWFjgKbN3QwBF21Oj_QWd5BIpt0x6_X1yIzb8,8995
52
52
  utilities/pottery.py,sha256=w2X80PXWwzdHdqSYJP6ESrPNNDP3xzpyuJn-fp-Vt3M,5969
53
53
  utilities/pqdm.py,sha256=BTsYPtbKQWwX-iXF4qCkfPG7DPxIB54J989n83bXrIo,3092
54
54
  utilities/psutil.py,sha256=KUlu4lrUw9Zg1V7ZGetpWpGb9DB8l_SSDWGbANFNCPU,2104
@@ -73,7 +73,7 @@ utilities/tempfile.py,sha256=VqmZJAhTJ1OaVywFzk5eqROV8iJbW9XQ_QYAV0bpdRo,1384
73
73
  utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
74
74
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
75
75
  utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
76
- utilities/traceback.py,sha256=-e1D3cMHJCMbggZVFeKVzyAzHCteEcoPc3-3eY0Dtj8,9187
76
+ utilities/traceback.py,sha256=zofhzIedpUHrzDNiRJDVzm_wuu_tlTQvVqK4quxVlgM,9151
77
77
  utilities/typed_settings.py,sha256=-mzQP5ZCIGWOhm7nPxlajWQhgtX657HVnRCfUYGKQKs,4433
78
78
  utilities/types.py,sha256=iDfk_Z96v7cIxPlgGYMap0fYmjgRUJ7uQzPPCQe1odY,18115
79
79
  utilities/typing.py,sha256=Z-_XDaWyT_6wIo3qfNK-hvRlzxP2Jxa9PgXzm5rDYRA,13790
@@ -88,8 +88,8 @@ utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
88
88
  utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
89
89
  utilities/pytest_plugins/pytest_randomly.py,sha256=NXzCcGKbpgYouz5yehKb4jmxmi2SexKKpgF4M65bi10,414
90
90
  utilities/pytest_plugins/pytest_regressions.py,sha256=Iwhfv_OJH7UCPZCfoh7ugZ2Xjqjil-BBBsOb8sDwiGI,1471
91
- dycw_utilities-0.148.1.dist-info/METADATA,sha256=loLMrx_55h6ZZhUdA2rWHGRDwCsc94yJto0LWyv8DE8,1697
92
- dycw_utilities-0.148.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- dycw_utilities-0.148.1.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
- dycw_utilities-0.148.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.148.1.dist-info/RECORD,,
91
+ dycw_utilities-0.148.3.dist-info/METADATA,sha256=RqJfw_DNqWHNMV3xk_mgGOX1xPumuzPT1EG9G58SkWM,1697
92
+ dycw_utilities-0.148.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ dycw_utilities-0.148.3.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
+ dycw_utilities-0.148.3.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.148.3.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.148.1"
3
+ __version__ = "0.148.3"
utilities/postgres.py CHANGED
@@ -5,17 +5,21 @@ from pathlib import Path
5
5
  from shutil import rmtree
6
6
  from typing import TYPE_CHECKING, Literal, assert_never, override
7
7
 
8
+ from sqlalchemy import Table
9
+ from sqlalchemy.orm import DeclarativeBase
10
+
8
11
  from utilities.asyncio import stream_command
9
12
  from utilities.iterables import always_iterable
10
13
  from utilities.logging import get_logger
11
14
  from utilities.os import temp_environ
12
- from utilities.sqlalchemy import TableOrORMInstOrClass, get_table_name
15
+ from utilities.sqlalchemy import get_table_name
13
16
  from utilities.timer import Timer
14
17
  from utilities.types import PathLike
15
18
 
16
19
  if TYPE_CHECKING:
17
20
  from sqlalchemy import URL
18
21
 
22
+ from utilities.sqlalchemy import TableOrORMInstOrClass
19
23
  from utilities.types import LoggerOrName, MaybeListStr, MaybeSequence, PathLike
20
24
 
21
25
 
@@ -31,7 +35,10 @@ async def pg_dump(
31
35
  format_: _PGDumpFormat = "plain",
32
36
  jobs: int | None = None,
33
37
  schemas: MaybeListStr | None = None,
34
- tables: MaybeSequence[TableOrORMInstOrClass] | None = None,
38
+ schemas_exc: MaybeListStr | None = None,
39
+ tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
40
+ tables_exc: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
41
+ inserts: bool = False,
35
42
  logger: LoggerOrName | None = None,
36
43
  dry_run: bool = False,
37
44
  ) -> None:
@@ -69,8 +76,16 @@ async def pg_dump(
69
76
  parts.append(f"--jobs={jobs}")
70
77
  if schemas is not None:
71
78
  parts.extend([f"--schema={s}" for s in always_iterable(schemas)])
79
+ if schemas_exc is not None:
80
+ parts.extend([f"--exclude-schema={s}" for s in always_iterable(schemas_exc)])
72
81
  if tables is not None:
73
- parts.extend([f"--table={get_table_name(t)}" for t in always_iterable(tables)])
82
+ parts.extend([f"--table={_get_table_name(t)}" for t in always_iterable(tables)])
83
+ if tables_exc is not None:
84
+ parts.extend([
85
+ f"--exclude-table={_get_table_name(t)}" for t in always_iterable(tables_exc)
86
+ ])
87
+ if inserts:
88
+ parts.append("--inserts")
74
89
  if url.username is not None:
75
90
  parts.append(f"--username={url.username}")
76
91
  cmd = " ".join(parts)
@@ -144,7 +159,8 @@ async def pg_restore(
144
159
  data_only: bool = False,
145
160
  jobs: int | None = None,
146
161
  schemas: MaybeListStr | None = None,
147
- tables: MaybeSequence[TableOrORMInstOrClass] | None = None,
162
+ schemas_exc: MaybeListStr | None = None,
163
+ tables: MaybeSequence[TableOrORMInstOrClass | str] | None = None,
148
164
  logger: LoggerOrName | None = None,
149
165
  dry_run: bool = False,
150
166
  ) -> None:
@@ -174,7 +190,6 @@ async def pg_restore(
174
190
  "--exit-on-error",
175
191
  "--no-owner",
176
192
  "--no-privileges",
177
- "--if-exists",
178
193
  # connection options
179
194
  f"--host={url.host}",
180
195
  f"--port={url.port}",
@@ -183,13 +198,15 @@ async def pg_restore(
183
198
  if data_only:
184
199
  parts.append("--data-only")
185
200
  else:
186
- parts.append("--clean")
201
+ parts.extend(["--clean", "--if-exists"])
187
202
  if jobs is not None:
188
203
  parts.append(f"--jobs={jobs}")
189
204
  if schemas is not None:
190
205
  parts.extend([f"--schema={s}" for s in always_iterable(schemas)])
206
+ if schemas_exc is not None:
207
+ parts.extend([f"--exclude-schema={s}" for s in always_iterable(schemas_exc)])
191
208
  if tables is not None:
192
- parts.extend([f"--table={get_table_name(t)}" for t in always_iterable(tables)])
209
+ parts.extend([f"--table={_get_table_name(t)}" for t in always_iterable(tables)])
193
210
  if url.username is not None:
194
211
  parts.append(f"--username={url.username}")
195
212
  parts.append(str(path))
@@ -249,4 +266,18 @@ class _PGRestorePortError(PGRestoreError):
249
266
  return f"Expected URL to contain a 'port'; got {self.url}"
250
267
 
251
268
 
269
+ ##
270
+
271
+
272
+ def _get_table_name(obj: TableOrORMInstOrClass | str, /) -> str:
273
+ """Get the table name from a Table or mapped class."""
274
+ match obj:
275
+ case Table() | DeclarativeBase() | type() as table_or_orm:
276
+ return get_table_name(table_or_orm)
277
+ case str() as name:
278
+ return name
279
+ case _ as never:
280
+ assert_never(never)
281
+
282
+
252
283
  __all__ = ["PGDumpError", "PGRestoreError", "pg_dump", "pg_restore"]
utilities/traceback.py CHANGED
@@ -6,10 +6,10 @@ from dataclasses import dataclass
6
6
  from functools import partial
7
7
  from getpass import getuser
8
8
  from itertools import repeat
9
- from logging import exception
10
9
  from os import getpid
11
10
  from pathlib import Path
12
11
  from socket import gethostname
12
+ from sys import stderr
13
13
  from traceback import TracebackException
14
14
  from typing import TYPE_CHECKING, override
15
15
 
@@ -287,8 +287,7 @@ def _make_except_hook_inner(
287
287
  try:
288
288
  send_to_slack(slack_url, f"```{slim}```")
289
289
  except SendToSlackError as error:
290
- msg = str(error)
291
- exception(msg) # noqa: LOG015
290
+ _ = stderr.write(f"{error}\n")
292
291
 
293
292
  if to_bool(bool_=pudb): # pragma: no cover
294
293
  from pudb import post_mortem