dycw-utilities 0.148.5__py3-none-any.whl → 0.175.31__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.
Potentially problematic release.
This version of dycw-utilities might be problematic. Click here for more details.
- dycw_utilities-0.175.31.dist-info/METADATA +34 -0
- dycw_utilities-0.175.31.dist-info/RECORD +103 -0
- dycw_utilities-0.175.31.dist-info/WHEEL +4 -0
- {dycw_utilities-0.148.5.dist-info → dycw_utilities-0.175.31.dist-info}/entry_points.txt +1 -0
- utilities/__init__.py +1 -1
- utilities/altair.py +10 -7
- utilities/asyncio.py +113 -64
- utilities/atomicwrites.py +1 -1
- utilities/atools.py +64 -4
- utilities/cachetools.py +9 -6
- utilities/click.py +144 -49
- utilities/concurrent.py +1 -1
- utilities/contextlib.py +4 -2
- utilities/contextvars.py +20 -1
- utilities/cryptography.py +3 -3
- utilities/dataclasses.py +15 -28
- utilities/docker.py +381 -0
- utilities/enum.py +2 -2
- utilities/errors.py +1 -1
- utilities/fastapi.py +8 -3
- utilities/fpdf2.py +2 -2
- utilities/functions.py +20 -297
- utilities/git.py +19 -0
- utilities/grp.py +28 -0
- utilities/hypothesis.py +361 -79
- utilities/importlib.py +17 -1
- utilities/inflect.py +1 -1
- utilities/iterables.py +12 -58
- utilities/jinja2.py +148 -0
- utilities/json.py +1 -1
- utilities/libcst.py +7 -7
- utilities/logging.py +74 -85
- utilities/math.py +8 -4
- utilities/more_itertools.py +4 -6
- utilities/operator.py +1 -1
- utilities/orjson.py +86 -34
- utilities/os.py +49 -2
- utilities/parse.py +2 -2
- utilities/pathlib.py +66 -34
- utilities/permissions.py +298 -0
- utilities/platform.py +4 -4
- utilities/polars.py +934 -420
- utilities/polars_ols.py +1 -1
- utilities/postgres.py +296 -174
- utilities/pottery.py +8 -73
- utilities/pqdm.py +3 -3
- utilities/pwd.py +28 -0
- utilities/pydantic.py +11 -0
- utilities/pydantic_settings.py +240 -0
- utilities/pydantic_settings_sops.py +76 -0
- utilities/pyinstrument.py +5 -5
- utilities/pytest.py +155 -46
- utilities/pytest_plugins/pytest_randomly.py +1 -1
- utilities/pytest_plugins/pytest_regressions.py +7 -3
- utilities/pytest_regressions.py +27 -8
- utilities/random.py +11 -6
- utilities/re.py +1 -1
- utilities/redis.py +101 -64
- utilities/sentinel.py +10 -0
- utilities/shelve.py +4 -1
- utilities/shutil.py +25 -0
- utilities/slack_sdk.py +8 -3
- utilities/sqlalchemy.py +422 -352
- utilities/sqlalchemy_polars.py +28 -52
- utilities/string.py +1 -1
- utilities/subprocess.py +1947 -0
- utilities/tempfile.py +95 -4
- utilities/testbook.py +50 -0
- utilities/text.py +165 -42
- utilities/timer.py +2 -2
- utilities/traceback.py +46 -36
- utilities/types.py +62 -23
- utilities/typing.py +479 -19
- utilities/uuid.py +42 -5
- utilities/version.py +27 -26
- utilities/whenever.py +661 -151
- utilities/zoneinfo.py +80 -22
- dycw_utilities-0.148.5.dist-info/METADATA +0 -41
- dycw_utilities-0.148.5.dist-info/RECORD +0 -95
- dycw_utilities-0.148.5.dist-info/WHEEL +0 -4
- dycw_utilities-0.148.5.dist-info/licenses/LICENSE +0 -21
- utilities/eventkit.py +0 -388
- utilities/period.py +0 -237
- utilities/typed_settings.py +0 -144
utilities/sqlalchemy_polars.py
CHANGED
|
@@ -4,7 +4,7 @@ import datetime as dt
|
|
|
4
4
|
import decimal
|
|
5
5
|
from contextlib import suppress
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
-
from typing import TYPE_CHECKING, Any,
|
|
7
|
+
from typing import TYPE_CHECKING, Any, cast, overload, override
|
|
8
8
|
from uuid import UUID
|
|
9
9
|
|
|
10
10
|
import polars as pl
|
|
@@ -35,7 +35,7 @@ from utilities.iterables import (
|
|
|
35
35
|
chunked,
|
|
36
36
|
one,
|
|
37
37
|
)
|
|
38
|
-
from utilities.polars import
|
|
38
|
+
from utilities.polars import zoned_date_time_dtype
|
|
39
39
|
from utilities.reprlib import get_repr
|
|
40
40
|
from utilities.sqlalchemy import (
|
|
41
41
|
CHUNK_SIZE_FRAC,
|
|
@@ -44,7 +44,6 @@ from utilities.sqlalchemy import (
|
|
|
44
44
|
get_chunk_size,
|
|
45
45
|
get_columns,
|
|
46
46
|
insert_items,
|
|
47
|
-
upsert_items,
|
|
48
47
|
)
|
|
49
48
|
from utilities.text import snake_case
|
|
50
49
|
from utilities.typing import is_subclass_gen
|
|
@@ -65,7 +64,7 @@ if TYPE_CHECKING:
|
|
|
65
64
|
from sqlalchemy.sql.base import ReadOnlyColumnCollection
|
|
66
65
|
from whenever import TimeDelta
|
|
67
66
|
|
|
68
|
-
from utilities.types import MaybeType, TimeZoneLike
|
|
67
|
+
from utilities.types import Delta, MaybeType, TimeZoneLike
|
|
69
68
|
|
|
70
69
|
|
|
71
70
|
async def insert_dataframe(
|
|
@@ -75,9 +74,9 @@ async def insert_dataframe(
|
|
|
75
74
|
/,
|
|
76
75
|
*,
|
|
77
76
|
snake: bool = False,
|
|
77
|
+
is_upsert: bool = False,
|
|
78
78
|
chunk_size_frac: float = CHUNK_SIZE_FRAC,
|
|
79
79
|
assume_tables_exist: bool = False,
|
|
80
|
-
upsert: Literal["selected", "all"] | None = None,
|
|
81
80
|
timeout_create: TimeDelta | None = None,
|
|
82
81
|
error_create: type[Exception] = TimeoutError,
|
|
83
82
|
timeout_insert: TimeDelta | None = None,
|
|
@@ -87,43 +86,25 @@ async def insert_dataframe(
|
|
|
87
86
|
mapping = _insert_dataframe_map_df_schema_to_table(
|
|
88
87
|
df.schema, table_or_orm, snake=snake
|
|
89
88
|
)
|
|
90
|
-
items = df.select(*mapping).rename(mapping).
|
|
89
|
+
items = df.select(*mapping).rename(mapping).rows(named=True)
|
|
91
90
|
if len(items) == 0:
|
|
92
|
-
if not df.is_empty():
|
|
93
|
-
raise InsertDataFrameError(df=df)
|
|
94
91
|
if not assume_tables_exist:
|
|
95
92
|
await ensure_tables_created(
|
|
96
93
|
engine, table_or_orm, timeout=timeout_create, error=error_create
|
|
97
94
|
)
|
|
98
95
|
return
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
case "selected" | "all" as selected_or_all: # skipif-ci-and-not-linux
|
|
113
|
-
await upsert_items(
|
|
114
|
-
engine,
|
|
115
|
-
(items, table_or_orm),
|
|
116
|
-
snake=snake,
|
|
117
|
-
chunk_size_frac=chunk_size_frac,
|
|
118
|
-
selected_or_all=selected_or_all,
|
|
119
|
-
assume_tables_exist=assume_tables_exist,
|
|
120
|
-
timeout_create=timeout_create,
|
|
121
|
-
error_create=error_create,
|
|
122
|
-
timeout_insert=timeout_insert,
|
|
123
|
-
error_insert=error_insert,
|
|
124
|
-
)
|
|
125
|
-
case _ as never:
|
|
126
|
-
assert_never(never)
|
|
96
|
+
await insert_items(
|
|
97
|
+
engine,
|
|
98
|
+
(items, table_or_orm),
|
|
99
|
+
snake=snake,
|
|
100
|
+
is_upsert=is_upsert,
|
|
101
|
+
chunk_size_frac=chunk_size_frac,
|
|
102
|
+
assume_tables_exist=assume_tables_exist,
|
|
103
|
+
timeout_create=timeout_create,
|
|
104
|
+
error_create=error_create,
|
|
105
|
+
timeout_insert=timeout_insert,
|
|
106
|
+
error_insert=error_insert,
|
|
107
|
+
)
|
|
127
108
|
|
|
128
109
|
|
|
129
110
|
def _insert_dataframe_map_df_schema_to_table(
|
|
@@ -207,15 +188,6 @@ def _insert_dataframe_check_df_and_db_types(
|
|
|
207
188
|
)
|
|
208
189
|
|
|
209
190
|
|
|
210
|
-
@dataclass(kw_only=True, slots=True)
|
|
211
|
-
class InsertDataFrameError(Exception):
|
|
212
|
-
df: DataFrame
|
|
213
|
-
|
|
214
|
-
@override
|
|
215
|
-
def __str__(self) -> str:
|
|
216
|
-
return f"Non-empty DataFrame must resolve to at least 1 item\n\n{self.df}"
|
|
217
|
-
|
|
218
|
-
|
|
219
191
|
@overload
|
|
220
192
|
async def select_to_dataframe(
|
|
221
193
|
sel: Select[Any],
|
|
@@ -228,7 +200,8 @@ async def select_to_dataframe(
|
|
|
228
200
|
in_clauses: tuple[Column[Any], Iterable[Any]] | None = None,
|
|
229
201
|
in_clauses_chunk_size: int | None = None,
|
|
230
202
|
chunk_size_frac: float = CHUNK_SIZE_FRAC,
|
|
231
|
-
timeout:
|
|
203
|
+
timeout: Delta | None = None,
|
|
204
|
+
error: MaybeType[BaseException] = TimeoutError,
|
|
232
205
|
**kwargs: Any,
|
|
233
206
|
) -> DataFrame: ...
|
|
234
207
|
@overload
|
|
@@ -243,7 +216,8 @@ async def select_to_dataframe(
|
|
|
243
216
|
in_clauses: None = None,
|
|
244
217
|
in_clauses_chunk_size: int | None = None,
|
|
245
218
|
chunk_size_frac: float = CHUNK_SIZE_FRAC,
|
|
246
|
-
timeout:
|
|
219
|
+
timeout: Delta | None = None,
|
|
220
|
+
error: MaybeType[BaseException] = TimeoutError,
|
|
247
221
|
**kwargs: Any,
|
|
248
222
|
) -> Iterable[DataFrame]: ...
|
|
249
223
|
@overload
|
|
@@ -258,7 +232,8 @@ async def select_to_dataframe(
|
|
|
258
232
|
in_clauses: tuple[Column[Any], Iterable[Any]],
|
|
259
233
|
in_clauses_chunk_size: int | None = None,
|
|
260
234
|
chunk_size_frac: float = CHUNK_SIZE_FRAC,
|
|
261
|
-
timeout:
|
|
235
|
+
timeout: Delta | None = None,
|
|
236
|
+
error: MaybeType[BaseException] = TimeoutError,
|
|
262
237
|
**kwargs: Any,
|
|
263
238
|
) -> AsyncIterable[DataFrame]: ...
|
|
264
239
|
@overload
|
|
@@ -273,7 +248,8 @@ async def select_to_dataframe(
|
|
|
273
248
|
in_clauses: tuple[Column[Any], Iterable[Any]] | None = None,
|
|
274
249
|
in_clauses_chunk_size: int | None = None,
|
|
275
250
|
chunk_size_frac: float = CHUNK_SIZE_FRAC,
|
|
276
|
-
timeout:
|
|
251
|
+
timeout: Delta | None = None,
|
|
252
|
+
error: MaybeType[BaseException] = TimeoutError,
|
|
277
253
|
**kwargs: Any,
|
|
278
254
|
) -> DataFrame | Iterable[DataFrame] | AsyncIterable[DataFrame]: ...
|
|
279
255
|
async def select_to_dataframe(
|
|
@@ -287,7 +263,7 @@ async def select_to_dataframe(
|
|
|
287
263
|
in_clauses: tuple[Column[Any], Iterable[Any]] | None = None,
|
|
288
264
|
in_clauses_chunk_size: int | None = None,
|
|
289
265
|
chunk_size_frac: float = CHUNK_SIZE_FRAC,
|
|
290
|
-
timeout:
|
|
266
|
+
timeout: Delta | None = None,
|
|
291
267
|
error: MaybeType[BaseException] = TimeoutError,
|
|
292
268
|
**kwargs: Any,
|
|
293
269
|
) -> DataFrame | Iterable[DataFrame] | AsyncIterable[DataFrame]:
|
|
@@ -390,7 +366,7 @@ def _select_to_dataframe_map_table_column_type_to_dtype(
|
|
|
390
366
|
return pl.Date
|
|
391
367
|
if is_subclass_gen(py_type, dt.datetime):
|
|
392
368
|
has_tz: bool = type_use.timezone
|
|
393
|
-
return
|
|
369
|
+
return zoned_date_time_dtype(time_zone=time_zone) if has_tz else Datetime()
|
|
394
370
|
if issubclass(py_type, dt.time):
|
|
395
371
|
return Time
|
|
396
372
|
if issubclass(py_type, dt.timedelta):
|
|
@@ -439,4 +415,4 @@ def _select_to_dataframe_yield_selects_with_in_clauses(
|
|
|
439
415
|
return (sel.where(in_col.in_(values)) for values in chunked(in_values, chunk_size))
|
|
440
416
|
|
|
441
417
|
|
|
442
|
-
__all__ = ["
|
|
418
|
+
__all__ = ["insert_dataframe", "select_to_dataframe"]
|
utilities/string.py
CHANGED
|
@@ -13,7 +13,7 @@ def substitute_environ(path_or_text: Path | str, /, **kwargs: Any) -> str:
|
|
|
13
13
|
return substitute_environ(path.read_text(), **kwargs)
|
|
14
14
|
case str() as text:
|
|
15
15
|
return Template(text).substitute(environ, **kwargs)
|
|
16
|
-
case
|
|
16
|
+
case never:
|
|
17
17
|
assert_never(never)
|
|
18
18
|
|
|
19
19
|
|