dycw-utilities 0.131.16__py3-none-any.whl → 0.131.18__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.
utilities/slack_sdk.py CHANGED
@@ -7,21 +7,21 @@ from typing import TYPE_CHECKING, Any, Self, override
7
7
 
8
8
  from slack_sdk.webhook.async_client import AsyncWebhookClient
9
9
 
10
- from utilities.asyncio import Looper, timeout_dur
11
- from utilities.datetime import MINUTE, SECOND, datetime_duration_to_float
10
+ from utilities.asyncio import Looper, timeout_td
12
11
  from utilities.functools import cache
13
- from utilities.math import safe_round
14
12
  from utilities.sentinel import Sentinel, sentinel
13
+ from utilities.whenever2 import MINUTE, SECOND
15
14
 
16
15
  if TYPE_CHECKING:
17
16
  from collections.abc import Callable
18
17
 
19
18
  from slack_sdk.webhook import WebhookResponse
19
+ from whenever import TimeDelta
20
20
 
21
- from utilities.types import Coroutine1, Duration
21
+ from utilities.types import Coroutine1
22
22
 
23
23
 
24
- _TIMEOUT: Duration = MINUTE
24
+ _TIMEOUT: TimeDelta = MINUTE
25
25
 
26
26
 
27
27
  ##
@@ -42,14 +42,14 @@ class SlackHandlerService(Handler, Looper[str]):
42
42
  url: str,
43
43
  auto_start: bool = False,
44
44
  empty_upon_exit: bool = True,
45
- freq: Duration = SECOND,
46
- backoff: Duration = SECOND,
45
+ freq: TimeDelta = SECOND,
46
+ backoff: TimeDelta = SECOND,
47
47
  logger: str | None = None,
48
- timeout: Duration | None = None,
48
+ timeout: TimeDelta | None = None,
49
49
  _debug: bool = False,
50
50
  level: int = NOTSET,
51
51
  sender: Callable[[str, str], Coroutine1[None]] = _send_adapter,
52
- send_timeout: Duration = SECOND,
52
+ send_timeout: TimeDelta = SECOND,
53
53
  ) -> None:
54
54
  Looper.__init__( # Looper first
55
55
  self,
@@ -81,7 +81,7 @@ class SlackHandlerService(Handler, Looper[str]):
81
81
  if self.empty():
82
82
  return
83
83
  text = "\n".join(self.get_all_nowait())
84
- async with timeout_dur(duration=self.send_timeout):
84
+ async with timeout_td(self.send_timeout):
85
85
  await self.sender(self.url, text)
86
86
 
87
87
  @override
@@ -90,10 +90,10 @@ class SlackHandlerService(Handler, Looper[str]):
90
90
  *,
91
91
  auto_start: bool | Sentinel = sentinel,
92
92
  empty_upon_exit: bool | Sentinel = sentinel,
93
- freq: Duration | Sentinel = sentinel,
94
- backoff: Duration | Sentinel = sentinel,
93
+ freq: TimeDelta | Sentinel = sentinel,
94
+ backoff: TimeDelta | Sentinel = sentinel,
95
95
  logger: str | None | Sentinel = sentinel,
96
- timeout: Duration | None | Sentinel = sentinel,
96
+ timeout: TimeDelta | None | Sentinel = sentinel,
97
97
  _debug: bool | Sentinel = sentinel,
98
98
  **kwargs: Any,
99
99
  ) -> Self:
@@ -115,11 +115,11 @@ class SlackHandlerService(Handler, Looper[str]):
115
115
 
116
116
 
117
117
  async def send_to_slack(
118
- url: str, text: str, /, *, timeout: Duration = _TIMEOUT
118
+ url: str, text: str, /, *, timeout: TimeDelta = _TIMEOUT
119
119
  ) -> None:
120
120
  """Send a message via Slack."""
121
121
  client = _get_client(url, timeout=timeout)
122
- async with timeout_dur(duration=timeout):
122
+ async with timeout_td(timeout):
123
123
  response = await client.send(text=text)
124
124
  if response.status_code != HTTPStatus.OK: # pragma: no cover
125
125
  raise SendToSlackError(text=text, response=response)
@@ -138,10 +138,9 @@ class SendToSlackError(Exception):
138
138
 
139
139
 
140
140
  @cache
141
- def _get_client(url: str, /, *, timeout: Duration = _TIMEOUT) -> AsyncWebhookClient:
141
+ def _get_client(url: str, /, *, timeout: TimeDelta = _TIMEOUT) -> AsyncWebhookClient:
142
142
  """Get the Slack client."""
143
- timeout_use = safe_round(datetime_duration_to_float(timeout))
144
- return AsyncWebhookClient(url, timeout=timeout_use)
143
+ return AsyncWebhookClient(url, timeout=round(timeout.in_seconds()))
145
144
 
146
145
 
147
146
  __all__ = ["SendToSlackError", "SlackHandlerService", "send_to_slack"]
utilities/sqlalchemy.py CHANGED
@@ -18,7 +18,16 @@ 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 Any, Literal, TypeGuard, TypeVar, assert_never, cast, override
21
+ from typing import (
22
+ TYPE_CHECKING,
23
+ Any,
24
+ Literal,
25
+ TypeGuard,
26
+ TypeVar,
27
+ assert_never,
28
+ cast,
29
+ override,
30
+ )
22
31
 
23
32
  from sqlalchemy import (
24
33
  URL,
@@ -57,9 +66,8 @@ from sqlalchemy.orm import (
57
66
  from sqlalchemy.orm.exc import UnmappedClassError
58
67
  from sqlalchemy.pool import NullPool, Pool
59
68
 
60
- from utilities.asyncio import Looper, timeout_dur
69
+ from utilities.asyncio import Looper, timeout_td
61
70
  from utilities.contextlib import suppress_super_object_attribute_error
62
- from utilities.datetime import SECOND
63
71
  from utilities.functions import (
64
72
  ensure_str,
65
73
  get_class_name,
@@ -82,13 +90,11 @@ from utilities.iterables import (
82
90
  )
83
91
  from utilities.reprlib import get_repr
84
92
  from utilities.text import snake_case
85
- from utilities.types import (
86
- Duration,
87
- MaybeIterable,
88
- MaybeType,
89
- StrMapping,
90
- TupleOrStrMapping,
91
- )
93
+ from utilities.types import MaybeIterable, MaybeType, StrMapping, TupleOrStrMapping
94
+ from utilities.whenever2 import SECOND
95
+
96
+ if TYPE_CHECKING:
97
+ from whenever import TimeDelta
92
98
 
93
99
  _T = TypeVar("_T")
94
100
  type _EngineOrConnectionOrAsync = Engine | Connection | AsyncEngine | AsyncConnection
@@ -105,7 +111,7 @@ async def check_engine(
105
111
  engine: AsyncEngine,
106
112
  /,
107
113
  *,
108
- timeout: Duration | None = None,
114
+ timeout: TimeDelta | None = None,
109
115
  error: type[Exception] = TimeoutError,
110
116
  num_tables: int | tuple[int, float] | None = None,
111
117
  ) -> None:
@@ -229,7 +235,7 @@ async def ensure_tables_created(
229
235
  engine: AsyncEngine,
230
236
  /,
231
237
  *tables_or_orms: TableOrORMInstOrClass,
232
- timeout: Duration | None = None,
238
+ timeout: TimeDelta | None = None,
233
239
  error: type[Exception] = TimeoutError,
234
240
  ) -> None:
235
241
  """Ensure a table/set of tables is/are created."""
@@ -258,7 +264,7 @@ async def ensure_tables_created(
258
264
  async def ensure_tables_dropped(
259
265
  engine: AsyncEngine,
260
266
  *tables_or_orms: TableOrORMInstOrClass,
261
- timeout: Duration | None = None,
267
+ timeout: TimeDelta | None = None,
262
268
  error: type[Exception] = TimeoutError,
263
269
  ) -> None:
264
270
  """Ensure a table/set of tables is/are dropped."""
@@ -384,9 +390,9 @@ async def insert_items(
384
390
  snake: bool = False,
385
391
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
386
392
  assume_tables_exist: bool = False,
387
- timeout_create: Duration | None = None,
393
+ timeout_create: TimeDelta | None = None,
388
394
  error_create: type[Exception] = TimeoutError,
389
- timeout_insert: Duration | None = None,
395
+ timeout_insert: TimeDelta | None = None,
390
396
  error_insert: type[Exception] = TimeoutError,
391
397
  ) -> None:
392
398
  """Insert a set of items into a database.
@@ -485,9 +491,9 @@ async def migrate_data(
485
491
  table_or_orm_to: TableOrORMInstOrClass | None = None,
486
492
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
487
493
  assume_tables_exist: bool = False,
488
- timeout_create: Duration | None = None,
494
+ timeout_create: TimeDelta | None = None,
489
495
  error_create: type[Exception] = TimeoutError,
490
- timeout_insert: Duration | None = None,
496
+ timeout_insert: TimeDelta | None = None,
491
497
  error_insert: type[Exception] = TimeoutError,
492
498
  ) -> None:
493
499
  """Migrate the contents of a table from one database to another."""
@@ -615,8 +621,8 @@ class UpsertService(Looper[_InsertItem]):
615
621
  """Service to upsert items to a database."""
616
622
 
617
623
  # base
618
- freq: Duration = field(default=SECOND, repr=False)
619
- backoff: Duration = field(default=SECOND, repr=False)
624
+ freq: TimeDelta = field(default=SECOND, repr=False)
625
+ backoff: TimeDelta = field(default=SECOND, repr=False)
620
626
  empty_upon_exit: bool = field(default=True, repr=False)
621
627
  # self
622
628
  engine: AsyncEngine
@@ -624,9 +630,9 @@ class UpsertService(Looper[_InsertItem]):
624
630
  selected_or_all: _SelectedOrAll = "selected"
625
631
  chunk_size_frac: float = CHUNK_SIZE_FRAC
626
632
  assume_tables_exist: bool = False
627
- timeout_create: Duration | None = None
633
+ timeout_create: TimeDelta | None = None
628
634
  error_create: type[Exception] = TimeoutError
629
- timeout_insert: Duration | None = None
635
+ timeout_insert: TimeDelta | None = None
630
636
  error_insert: type[Exception] = TimeoutError
631
637
 
632
638
  @override
@@ -651,11 +657,11 @@ class UpsertServiceMixin:
651
657
  """Mix-in for the upsert service."""
652
658
 
653
659
  # base - looper
654
- upsert_service_freq: Duration = field(default=SECOND, repr=False)
655
- upsert_service_backoff: Duration = field(default=SECOND, repr=False)
660
+ upsert_service_freq: TimeDelta = field(default=SECOND, repr=False)
661
+ upsert_service_backoff: TimeDelta = field(default=SECOND, repr=False)
656
662
  upsert_service_empty_upon_exit: bool = field(default=False, repr=False)
657
663
  upsert_service_logger: str | None = field(default=None, repr=False)
658
- upsert_service_timeout: Duration | None = field(default=None, repr=False)
664
+ upsert_service_timeout: TimeDelta | None = field(default=None, repr=False)
659
665
  upsert_service_debug: bool = field(default=False, repr=False)
660
666
  # base - upsert service
661
667
  upsert_service_database: AsyncEngine
@@ -663,9 +669,9 @@ class UpsertServiceMixin:
663
669
  upsert_service_selected_or_all: _SelectedOrAll = "selected"
664
670
  upsert_service_chunk_size_frac: float = CHUNK_SIZE_FRAC
665
671
  upsert_service_assume_tables_exist: bool = False
666
- upsert_service_timeout_create: Duration | None = None
672
+ upsert_service_timeout_create: TimeDelta | None = None
667
673
  upsert_service_error_create: type[Exception] = TimeoutError
668
- upsert_service_timeout_insert: Duration | None = None
674
+ upsert_service_timeout_insert: TimeDelta | None = None
669
675
  upsert_service_error_insert: type[Exception] = TimeoutError
670
676
  # self
671
677
  _upsert_service: UpsertService = field(init=False, repr=False)
@@ -713,9 +719,9 @@ async def upsert_items(
713
719
  selected_or_all: _SelectedOrAll = "selected",
714
720
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
715
721
  assume_tables_exist: bool = False,
716
- timeout_create: Duration | None = None,
722
+ timeout_create: TimeDelta | None = None,
717
723
  error_create: type[Exception] = TimeoutError,
718
- timeout_insert: Duration | None = None,
724
+ timeout_insert: TimeDelta | None = None,
719
725
  error_insert: type[Exception] = TimeoutError,
720
726
  ) -> None:
721
727
  """Upsert a set of items into a database.
@@ -835,11 +841,11 @@ async def yield_connection(
835
841
  engine: AsyncEngine,
836
842
  /,
837
843
  *,
838
- timeout: Duration | None = None,
844
+ timeout: TimeDelta | None = None,
839
845
  error: MaybeType[BaseException] = TimeoutError,
840
846
  ) -> AsyncIterator[AsyncConnection]:
841
847
  """Yield an async connection."""
842
- async with timeout_dur(duration=timeout, error=error), engine.begin() as conn:
848
+ async with timeout_td(timeout, error=error), engine.begin() as conn:
843
849
  yield conn
844
850
 
845
851
 
@@ -26,7 +26,7 @@ from polars import (
26
26
  from sqlalchemy import Column, Select, select
27
27
  from sqlalchemy.exc import DuplicateColumnError
28
28
 
29
- from utilities.asyncio import timeout_dur
29
+ from utilities.asyncio import timeout_td
30
30
  from utilities.functions import identity
31
31
  from utilities.iterables import (
32
32
  CheckDuplicatesError,
@@ -63,11 +63,8 @@ if TYPE_CHECKING:
63
63
  from sqlalchemy.ext.asyncio import AsyncEngine
64
64
  from sqlalchemy.sql import ColumnCollection
65
65
  from sqlalchemy.sql.base import ReadOnlyColumnCollection
66
- from tenacity.retry import RetryBaseT
67
- from tenacity.stop import StopBaseT
68
- from tenacity.wait import WaitBaseT
66
+ from whenever import TimeDelta
69
67
 
70
- import utilities.types
71
68
  from utilities.types import MaybeType, TimeZoneLike
72
69
 
73
70
 
@@ -81,9 +78,9 @@ async def insert_dataframe(
81
78
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
82
79
  assume_tables_exist: bool = False,
83
80
  upsert: Literal["selected", "all"] | None = None,
84
- timeout_create: utilities.types.Duration | None = None,
81
+ timeout_create: TimeDelta | None = None,
85
82
  error_create: type[Exception] = TimeoutError,
86
- timeout_insert: utilities.types.Duration | None = None,
83
+ timeout_insert: TimeDelta | None = None,
87
84
  error_insert: type[Exception] = TimeoutError,
88
85
  ) -> None:
89
86
  """Insert/upsert a DataFrame into a database."""
@@ -231,10 +228,7 @@ async def select_to_dataframe(
231
228
  in_clauses: tuple[Column[Any], Iterable[Any]] | None = None,
232
229
  in_clauses_chunk_size: int | None = None,
233
230
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
234
- stop: StopBaseT | None = None,
235
- wait: WaitBaseT | None = None,
236
- retry: RetryBaseT | None = None,
237
- timeout: utilities.types.Duration | None = None,
231
+ timeout: TimeDelta | None = None,
238
232
  **kwargs: Any,
239
233
  ) -> DataFrame: ...
240
234
  @overload
@@ -249,10 +243,7 @@ async def select_to_dataframe(
249
243
  in_clauses: None = None,
250
244
  in_clauses_chunk_size: int | None = None,
251
245
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
252
- stop: StopBaseT | None = None,
253
- wait: WaitBaseT | None = None,
254
- retry: RetryBaseT | None = None,
255
- timeout: utilities.types.Duration | None = None,
246
+ timeout: TimeDelta | None = None,
256
247
  **kwargs: Any,
257
248
  ) -> Iterable[DataFrame]: ...
258
249
  @overload
@@ -267,10 +258,7 @@ async def select_to_dataframe(
267
258
  in_clauses: tuple[Column[Any], Iterable[Any]],
268
259
  in_clauses_chunk_size: int | None = None,
269
260
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
270
- stop: StopBaseT | None = None,
271
- wait: WaitBaseT | None = None,
272
- retry: RetryBaseT | None = None,
273
- timeout: utilities.types.Duration | None = None,
261
+ timeout: TimeDelta | None = None,
274
262
  **kwargs: Any,
275
263
  ) -> AsyncIterable[DataFrame]: ...
276
264
  @overload
@@ -285,10 +273,7 @@ async def select_to_dataframe(
285
273
  in_clauses: tuple[Column[Any], Iterable[Any]] | None = None,
286
274
  in_clauses_chunk_size: int | None = None,
287
275
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
288
- stop: StopBaseT | None = None,
289
- wait: WaitBaseT | None = None,
290
- retry: RetryBaseT | None = None,
291
- timeout: utilities.types.Duration | None = None,
276
+ timeout: TimeDelta | None = None,
292
277
  **kwargs: Any,
293
278
  ) -> DataFrame | Iterable[DataFrame] | AsyncIterable[DataFrame]: ...
294
279
  async def select_to_dataframe(
@@ -302,7 +287,7 @@ async def select_to_dataframe(
302
287
  in_clauses: tuple[Column[Any], Iterable[Any]] | None = None,
303
288
  in_clauses_chunk_size: int | None = None,
304
289
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
305
- timeout: utilities.types.Duration | None = None,
290
+ timeout: TimeDelta | None = None,
306
291
  error: MaybeType[BaseException] = TimeoutError,
307
292
  **kwargs: Any,
308
293
  ) -> DataFrame | Iterable[DataFrame] | AsyncIterable[DataFrame]:
@@ -311,7 +296,7 @@ async def select_to_dataframe(
311
296
  sel = _select_to_dataframe_apply_snake(sel)
312
297
  schema = _select_to_dataframe_map_select_to_df_schema(sel, time_zone=time_zone)
313
298
  if in_clauses is None:
314
- async with timeout_dur(duration=timeout, error=error):
299
+ async with timeout_td(timeout, error=error):
315
300
  return read_database(
316
301
  sel,
317
302
  cast("Any", engine),
@@ -328,7 +313,7 @@ async def select_to_dataframe(
328
313
  chunk_size_frac=chunk_size_frac,
329
314
  )
330
315
  if batch_size is None:
331
- async with timeout_dur(duration=timeout, error=error):
316
+ async with timeout_td(timeout, error=error):
332
317
  dfs = [
333
318
  await select_to_dataframe(
334
319
  sel,
@@ -349,7 +334,7 @@ async def select_to_dataframe(
349
334
  return DataFrame(schema=schema)
350
335
 
351
336
  async def yield_dfs() -> AsyncIterator[DataFrame]:
352
- async with timeout_dur(duration=timeout, error=error):
337
+ async with timeout_td(timeout, error=error):
353
338
  for sel_i in sels:
354
339
  for df in await select_to_dataframe(
355
340
  sel_i,
utilities/whenever.py CHANGED
@@ -1,27 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import datetime as dt
4
- import re
5
4
  from contextlib import suppress
6
5
  from dataclasses import dataclass
7
6
  from typing import TYPE_CHECKING, override
8
7
 
9
- from whenever import (
10
- Date,
11
- DateTimeDelta,
12
- PlainDateTime,
13
- Time,
14
- TimeZoneNotFoundError,
15
- ZonedDateTime,
16
- )
8
+ from whenever import DateTimeDelta, TimeZoneNotFoundError, ZonedDateTime
17
9
 
18
10
  from utilities.datetime import (
19
11
  _MICROSECONDS_PER_DAY,
20
12
  _MICROSECONDS_PER_SECOND,
21
13
  ZERO_TIME,
22
- check_date_not_datetime,
23
14
  datetime_duration_to_microseconds,
24
- parse_two_digit_year,
25
15
  )
26
16
  from utilities.math import ParseNumberError, parse_number
27
17
  from utilities.re import (
@@ -35,7 +25,6 @@ from utilities.zoneinfo import UTC, ensure_time_zone, get_time_zone_name
35
25
  if TYPE_CHECKING:
36
26
  from utilities.types import Duration
37
27
 
38
-
39
28
  MAX_SERIALIZABLE_TIMEDELTA = dt.timedelta(days=3652060, microseconds=-1)
40
29
  MIN_SERIALIZABLE_TIMEDELTA = -MAX_SERIALIZABLE_TIMEDELTA
41
30
 
@@ -84,56 +73,6 @@ class _CheckValidZonedDateTimeUnequalError(CheckValidZonedDateTimeError):
84
73
  ##
85
74
 
86
75
 
87
- _PARSE_DATE_YYMMDD_REGEX = re.compile(r"^(\d{2})(\d{2})(\d{2})$")
88
-
89
-
90
- def parse_date(date: str, /) -> dt.date:
91
- """Parse a string into a date."""
92
- try:
93
- w_date = Date.parse_common_iso(date)
94
- except ValueError:
95
- try:
96
- ((year2, month, day),) = _PARSE_DATE_YYMMDD_REGEX.findall(date)
97
- except ValueError:
98
- raise ParseDateError(date=date) from None
99
- year = parse_two_digit_year(year2)
100
- return dt.date(year=int(year), month=int(month), day=int(day))
101
- return w_date.py_date()
102
-
103
-
104
- @dataclass(kw_only=True, slots=True)
105
- class ParseDateError(Exception):
106
- date: str
107
-
108
- @override
109
- def __str__(self) -> str:
110
- return f"Unable to parse date; got {self.date!r}"
111
-
112
-
113
- ##
114
-
115
-
116
- def parse_datetime(datetime: str, /) -> dt.datetime:
117
- """Parse a string into a datetime."""
118
- with suppress(ParsePlainDateTimeError):
119
- return parse_plain_datetime(datetime)
120
- with suppress(ParseZonedDateTimeError):
121
- return parse_zoned_datetime(datetime)
122
- raise ParseDateTimeError(datetime=datetime) from None
123
-
124
-
125
- @dataclass(kw_only=True, slots=True)
126
- class ParseDateTimeError(Exception):
127
- datetime: str
128
-
129
- @override
130
- def __str__(self) -> str:
131
- return f"Unable to parse datetime; got {self.datetime!r}"
132
-
133
-
134
- ##
135
-
136
-
137
76
  def parse_duration(duration: str, /) -> Duration:
138
77
  """Parse a string into a Duration."""
139
78
  with suppress(ParseNumberError):
@@ -156,48 +95,6 @@ class ParseDurationError(Exception):
156
95
  ##
157
96
 
158
97
 
159
- def parse_plain_datetime(datetime: str, /) -> dt.datetime:
160
- """Parse a string into a plain datetime."""
161
- try:
162
- ldt = PlainDateTime.parse_common_iso(datetime)
163
- except ValueError:
164
- raise ParsePlainDateTimeError(datetime=datetime) from None
165
- return ldt.py_datetime()
166
-
167
-
168
- @dataclass(kw_only=True, slots=True)
169
- class ParsePlainDateTimeError(Exception):
170
- datetime: str
171
-
172
- @override
173
- def __str__(self) -> str:
174
- return f"Unable to parse plain datetime; got {self.datetime!r}"
175
-
176
-
177
- ##
178
-
179
-
180
- def parse_time(time: str, /) -> dt.time:
181
- """Parse a string into a time."""
182
- try:
183
- w_time = Time.parse_common_iso(time)
184
- except ValueError:
185
- raise ParseTimeError(time=time) from None
186
- return w_time.py_time()
187
-
188
-
189
- @dataclass(kw_only=True, slots=True)
190
- class ParseTimeError(Exception):
191
- time: str
192
-
193
- @override
194
- def __str__(self) -> str:
195
- return f"Unable to parse time; got {self.time!r}"
196
-
197
-
198
- ##
199
-
200
-
201
98
  def parse_timedelta(timedelta: str, /) -> dt.timedelta:
202
99
  """Parse a string into a timedelta."""
203
100
  with suppress(ExtractGroupError):
@@ -245,47 +142,6 @@ class _ParseTimedeltaNanosecondError(ParseTimedeltaError):
245
142
  ##
246
143
 
247
144
 
248
- def parse_zoned_datetime(datetime: str, /) -> dt.datetime:
249
- """Parse a string into a zoned datetime."""
250
- try:
251
- zdt = ZonedDateTime.parse_common_iso(datetime)
252
- except ValueError:
253
- raise ParseZonedDateTimeError(datetime=datetime) from None
254
- return zdt.py_datetime()
255
-
256
-
257
- @dataclass(kw_only=True, slots=True)
258
- class ParseZonedDateTimeError(Exception):
259
- datetime: str
260
-
261
- @override
262
- def __str__(self) -> str:
263
- return f"Unable to parse zoned datetime; got {self.datetime!r}"
264
-
265
-
266
- ##
267
-
268
-
269
- def serialize_date(date: dt.date, /) -> str:
270
- """Serialize a date."""
271
- check_date_not_datetime(date)
272
- return Date.from_py_date(date).format_common_iso()
273
-
274
-
275
- ##
276
-
277
-
278
- def serialize_datetime(datetime: dt.datetime, /) -> str:
279
- """Serialize a datetime."""
280
- try:
281
- return serialize_plain_datetime(datetime)
282
- except SerializePlainDateTimeError:
283
- return serialize_zoned_datetime(datetime)
284
-
285
-
286
- ##
287
-
288
-
289
145
  def serialize_duration(duration: Duration, /) -> str:
290
146
  """Serialize a duration."""
291
147
  if isinstance(duration, int | float):
@@ -308,35 +164,6 @@ class SerializeDurationError(Exception):
308
164
  ##
309
165
 
310
166
 
311
- def serialize_plain_datetime(datetime: dt.datetime, /) -> str:
312
- """Serialize a plain datetime."""
313
- try:
314
- pdt = PlainDateTime.from_py_datetime(datetime)
315
- except ValueError:
316
- raise SerializePlainDateTimeError(datetime=datetime) from None
317
- return pdt.format_common_iso()
318
-
319
-
320
- @dataclass(kw_only=True, slots=True)
321
- class SerializePlainDateTimeError(Exception):
322
- datetime: dt.datetime
323
-
324
- @override
325
- def __str__(self) -> str:
326
- return f"Unable to serialize plain datetime; got {self.datetime}"
327
-
328
-
329
- ##
330
-
331
-
332
- def serialize_time(time: dt.time, /) -> str:
333
- """Serialize a time."""
334
- return Time.from_py_time(time).format_common_iso()
335
-
336
-
337
- ##
338
-
339
-
340
167
  def serialize_timedelta(timedelta: dt.timedelta, /) -> str:
341
168
  """Serialize a timedelta."""
342
169
  try:
@@ -358,31 +185,6 @@ class SerializeTimeDeltaError(Exception):
358
185
  ##
359
186
 
360
187
 
361
- def serialize_zoned_datetime(datetime: dt.datetime, /) -> str:
362
- """Serialize a zoned datetime."""
363
- if datetime.tzinfo is dt.UTC:
364
- return serialize_zoned_datetime( # skipif-ci-and-windows
365
- datetime.replace(tzinfo=UTC)
366
- )
367
- try:
368
- zdt = ZonedDateTime.from_py_datetime(datetime)
369
- except ValueError:
370
- raise SerializeZonedDateTimeError(datetime=datetime) from None
371
- return zdt.format_common_iso()
372
-
373
-
374
- @dataclass(kw_only=True, slots=True)
375
- class SerializeZonedDateTimeError(Exception):
376
- datetime: dt.datetime
377
-
378
- @override
379
- def __str__(self) -> str:
380
- return f"Unable to serialize zoned datetime; got {self.datetime}"
381
-
382
-
383
- ##
384
-
385
-
386
188
  def _to_datetime_delta(timedelta: dt.timedelta, /) -> DateTimeDelta:
387
189
  """Serialize a timedelta."""
388
190
  total_microseconds = datetime_duration_to_microseconds(timedelta)
@@ -415,30 +217,14 @@ __all__ = [
415
217
  "MAX_SERIALIZABLE_TIMEDELTA",
416
218
  "MIN_SERIALIZABLE_TIMEDELTA",
417
219
  "CheckValidZonedDateTimeError",
418
- "ParseDateError",
419
- "ParseDateTimeError",
420
220
  "ParseDurationError",
421
- "ParsePlainDateTimeError",
422
- "ParseTimeError",
423
221
  "ParseTimedeltaError",
424
- "ParseZonedDateTimeError",
425
222
  "SerializeDurationError",
426
- "SerializePlainDateTimeError",
427
223
  "SerializeTimeDeltaError",
428
- "SerializeZonedDateTimeError",
429
224
  "check_valid_zoned_datetime",
430
- "parse_date",
431
- "parse_datetime",
225
+ "check_valid_zoned_datetime",
432
226
  "parse_duration",
433
- "parse_plain_datetime",
434
- "parse_time",
435
227
  "parse_timedelta",
436
- "parse_zoned_datetime",
437
- "serialize_date",
438
- "serialize_datetime",
439
228
  "serialize_duration",
440
- "serialize_plain_datetime",
441
- "serialize_time",
442
229
  "serialize_timedelta",
443
- "serialize_zoned_datetime",
444
230
  ]