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.

Files changed (84) hide show
  1. dycw_utilities-0.175.31.dist-info/METADATA +34 -0
  2. dycw_utilities-0.175.31.dist-info/RECORD +103 -0
  3. dycw_utilities-0.175.31.dist-info/WHEEL +4 -0
  4. {dycw_utilities-0.148.5.dist-info → dycw_utilities-0.175.31.dist-info}/entry_points.txt +1 -0
  5. utilities/__init__.py +1 -1
  6. utilities/altair.py +10 -7
  7. utilities/asyncio.py +113 -64
  8. utilities/atomicwrites.py +1 -1
  9. utilities/atools.py +64 -4
  10. utilities/cachetools.py +9 -6
  11. utilities/click.py +144 -49
  12. utilities/concurrent.py +1 -1
  13. utilities/contextlib.py +4 -2
  14. utilities/contextvars.py +20 -1
  15. utilities/cryptography.py +3 -3
  16. utilities/dataclasses.py +15 -28
  17. utilities/docker.py +381 -0
  18. utilities/enum.py +2 -2
  19. utilities/errors.py +1 -1
  20. utilities/fastapi.py +8 -3
  21. utilities/fpdf2.py +2 -2
  22. utilities/functions.py +20 -297
  23. utilities/git.py +19 -0
  24. utilities/grp.py +28 -0
  25. utilities/hypothesis.py +361 -79
  26. utilities/importlib.py +17 -1
  27. utilities/inflect.py +1 -1
  28. utilities/iterables.py +12 -58
  29. utilities/jinja2.py +148 -0
  30. utilities/json.py +1 -1
  31. utilities/libcst.py +7 -7
  32. utilities/logging.py +74 -85
  33. utilities/math.py +8 -4
  34. utilities/more_itertools.py +4 -6
  35. utilities/operator.py +1 -1
  36. utilities/orjson.py +86 -34
  37. utilities/os.py +49 -2
  38. utilities/parse.py +2 -2
  39. utilities/pathlib.py +66 -34
  40. utilities/permissions.py +298 -0
  41. utilities/platform.py +4 -4
  42. utilities/polars.py +934 -420
  43. utilities/polars_ols.py +1 -1
  44. utilities/postgres.py +296 -174
  45. utilities/pottery.py +8 -73
  46. utilities/pqdm.py +3 -3
  47. utilities/pwd.py +28 -0
  48. utilities/pydantic.py +11 -0
  49. utilities/pydantic_settings.py +240 -0
  50. utilities/pydantic_settings_sops.py +76 -0
  51. utilities/pyinstrument.py +5 -5
  52. utilities/pytest.py +155 -46
  53. utilities/pytest_plugins/pytest_randomly.py +1 -1
  54. utilities/pytest_plugins/pytest_regressions.py +7 -3
  55. utilities/pytest_regressions.py +27 -8
  56. utilities/random.py +11 -6
  57. utilities/re.py +1 -1
  58. utilities/redis.py +101 -64
  59. utilities/sentinel.py +10 -0
  60. utilities/shelve.py +4 -1
  61. utilities/shutil.py +25 -0
  62. utilities/slack_sdk.py +8 -3
  63. utilities/sqlalchemy.py +422 -352
  64. utilities/sqlalchemy_polars.py +28 -52
  65. utilities/string.py +1 -1
  66. utilities/subprocess.py +1947 -0
  67. utilities/tempfile.py +95 -4
  68. utilities/testbook.py +50 -0
  69. utilities/text.py +165 -42
  70. utilities/timer.py +2 -2
  71. utilities/traceback.py +46 -36
  72. utilities/types.py +62 -23
  73. utilities/typing.py +479 -19
  74. utilities/uuid.py +42 -5
  75. utilities/version.py +27 -26
  76. utilities/whenever.py +661 -151
  77. utilities/zoneinfo.py +80 -22
  78. dycw_utilities-0.148.5.dist-info/METADATA +0 -41
  79. dycw_utilities-0.148.5.dist-info/RECORD +0 -95
  80. dycw_utilities-0.148.5.dist-info/WHEEL +0 -4
  81. dycw_utilities-0.148.5.dist-info/licenses/LICENSE +0 -21
  82. utilities/eventkit.py +0 -388
  83. utilities/period.py +0 -237
  84. utilities/typed_settings.py +0 -144
@@ -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, Literal, assert_never, cast, overload, override
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 zoned_datetime
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).to_dicts()
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
- match upsert:
100
- case None:
101
- await insert_items(
102
- engine,
103
- (items, table_or_orm),
104
- snake=snake,
105
- chunk_size_frac=chunk_size_frac,
106
- assume_tables_exist=assume_tables_exist,
107
- timeout_create=timeout_create,
108
- error_create=error_create,
109
- timeout_insert=timeout_insert,
110
- error_insert=error_insert,
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: TimeDelta | None = None,
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: TimeDelta | None = None,
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: TimeDelta | None = None,
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: TimeDelta | None = None,
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: TimeDelta | None = None,
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 zoned_datetime(time_zone=time_zone) if has_tz else Datetime()
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__ = ["InsertDataFrameError", "insert_dataframe", "select_to_dataframe"]
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 _ as never:
16
+ case never:
17
17
  assert_never(never)
18
18
 
19
19