Skip to content

Commit 26ae729

Browse files
authored
more pendulum consolidation (#16922)
1 parent 471a8c2 commit 26ae729

File tree

8 files changed

+98
-56
lines changed

8 files changed

+98
-56
lines changed

src/prefect/_internal/compatibility/deprecated.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
import warnings
1616
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
1717

18-
import pendulum
1918
from pydantic import BaseModel
2019
from typing_extensions import ParamSpec, TypeAlias, TypeVar
2120

21+
from prefect.types._datetime import DateTime, from_format
2222
from prefect.utilities.callables import get_call_parameters
2323
from prefect.utilities.importtools import (
2424
AliasedModuleDefinition,
@@ -60,18 +60,18 @@ def generate_deprecation_message(
6060
if not start_date and not end_date:
6161
raise ValueError(
6262
"A start date is required if an end date is not provided. Suggested start"
63-
f" date is {pendulum.now('UTC').format(DEPRECATED_DATEFMT)!r}"
63+
f" date is {DateTime.now('UTC').format(DEPRECATED_DATEFMT)!r}"
6464
)
6565

6666
if not end_date:
6767
if TYPE_CHECKING:
6868
assert start_date is not None
69-
parsed_start_date = pendulum.from_format(start_date, DEPRECATED_DATEFMT)
69+
parsed_start_date = from_format(start_date, DEPRECATED_DATEFMT)
7070
parsed_end_date = parsed_start_date.add(months=6)
7171
end_date = parsed_end_date.format(DEPRECATED_DATEFMT)
7272
else:
7373
# Validate format
74-
pendulum.from_format(end_date, DEPRECATED_DATEFMT)
74+
from_format(end_date, DEPRECATED_DATEFMT)
7575

7676
if when:
7777
when = " when " + when

src/prefect/cli/deployment.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
from typing import TYPE_CHECKING, Any, Optional, TypedDict
1414
from uuid import UUID
1515

16-
import pendulum
17-
import pendulum.tz
1816
import typer
1917
import yaml
2018
from rich.console import Console
@@ -42,6 +40,12 @@
4240
)
4341
from prefect.flow_runs import wait_for_flow_run
4442
from prefect.states import Scheduled
43+
from prefect.types._datetime import (
44+
DateTime,
45+
format_diff,
46+
local_timezone,
47+
parse_datetime,
48+
)
4549
from prefect.utilities import urls
4650
from prefect.utilities.collections import listrepr
4751

@@ -344,7 +348,7 @@ async def create_schedule(
344348
if interval is not None:
345349
if interval_anchor:
346350
try:
347-
pendulum.parse(interval_anchor)
351+
parse_datetime(interval_anchor)
348352
except ValueError:
349353
return exit_with_error("The anchor date must be a valid date string.")
350354

@@ -552,7 +556,7 @@ async def list_schedules(deployment_name: str):
552556

553557
def sort_by_created_key(schedule: DeploymentSchedule): # type: ignore
554558
assert schedule.created is not None, "All schedules should have a created time."
555-
return pendulum.now("utc") - schedule.created
559+
return DateTime.now("utc") - schedule.created
556560

557561
def schedule_details(schedule: DeploymentSchedule) -> str:
558562
if isinstance(schedule.schedule, IntervalSchedule):
@@ -643,7 +647,7 @@ def sort_by_name_keys(d: DeploymentResponse):
643647

644648
def sort_by_created_key(d: DeploymentResponse):
645649
assert d.created is not None, "All deployments should have a created time."
646-
return pendulum.now("utc") - d.created
650+
return DateTime.now("utc") - d.created
647651

648652
table = Table(
649653
title="Deployments",
@@ -751,7 +755,7 @@ async def run(
751755
"""
752756
import dateparser
753757

754-
now = pendulum.now("UTC")
758+
now = DateTime.now("UTC")
755759

756760
multi_params: dict[str, Any] = {}
757761
if multiparams:
@@ -802,7 +806,7 @@ async def run(
802806
warnings.filterwarnings("ignore", module="dateparser")
803807

804808
try:
805-
start_time_parsed = dateparser.parse(
809+
start_time_parsed = dateparser.parse( # type: ignore[reportUnknownMemberType]
806810
start_time_raw,
807811
settings={
808812
"TO_TIMEZONE": "UTC",
@@ -820,10 +824,8 @@ async def run(
820824
if start_time_parsed is None:
821825
exit_with_error(f"Unable to parse scheduled start time {start_time_raw!r}.")
822826

823-
scheduled_start_time = pendulum.instance(start_time_parsed)
824-
human_dt_diff = (
825-
" (" + pendulum.format_diff(scheduled_start_time.diff(now)) + ")"
826-
)
827+
scheduled_start_time = DateTime.instance(start_time_parsed)
828+
human_dt_diff = " (" + format_diff(scheduled_start_time.diff(now)) + ")"
827829

828830
async with get_client() as client:
829831
deployment = await get_deployment(client, name, deployment_id)
@@ -871,7 +873,7 @@ async def run(
871873
raise
872874

873875
run_url = urls.url_for(flow_run) or "<no dashboard available>"
874-
datetime_local_tz = scheduled_start_time.in_tz(pendulum.tz.local_timezone())
876+
datetime_local_tz = scheduled_start_time.in_tz(local_timezone())
875877
scheduled_display = datetime_local_tz.to_datetime_string()
876878
tz_name = datetime_local_tz.tzname()
877879
if tz_name:

src/prefect/cli/work_pool.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import json
66
import textwrap
77

8-
import pendulum
98
import typer
109
from rich.pretty import Pretty
1110
from rich.table import Table
@@ -20,12 +19,14 @@
2019
from prefect.client.collections import get_collections_metadata_client
2120
from prefect.client.orchestration import get_client
2221
from prefect.client.schemas.actions import WorkPoolCreate, WorkPoolUpdate
22+
from prefect.client.schemas.objects import FlowRun, WorkPool
2323
from prefect.exceptions import ObjectAlreadyExists, ObjectNotFound
2424
from prefect.infrastructure.provisioners import (
2525
_provisioners,
2626
get_infrastructure_provisioner_for_work_pool_type,
2727
)
2828
from prefect.settings import update_current_profile
29+
from prefect.types._datetime import DateTime, PendulumDuration
2930
from prefect.utilities import urls
3031
from prefect.workers.utilities import (
3132
get_available_work_pool_types,
@@ -278,8 +279,9 @@ async def ls(
278279
async with get_client() as client:
279280
pools = await client.read_work_pools()
280281

281-
def sort_by_created_key(q):
282-
return pendulum.now("utc") - q.created
282+
def sort_by_created_key(q: WorkPool) -> PendulumDuration:
283+
assert q.created is not None
284+
return DateTime.now("utc") - q.created
283285

284286
for pool in sorted(pools, key=sort_by_created_key):
285287
row = [
@@ -649,18 +651,19 @@ async def preview(
649651
table.add_column("Name", style="green", no_wrap=True)
650652
table.add_column("Deployment ID", style="blue", no_wrap=True)
651653

652-
pendulum.now("utc").add(hours=hours or 1)
654+
DateTime.now("utc").add(hours=hours or 1)
653655

654-
now = pendulum.now("utc")
656+
now = DateTime.now("utc")
655657

656-
def sort_by_created_key(r):
658+
def sort_by_created_key(r: FlowRun) -> PendulumDuration:
659+
assert r.created is not None
657660
return now - r.created
658661

659662
for run in sorted(runs, key=sort_by_created_key):
660663
table.add_row(
661664
(
662665
f"{run.expected_start_time} [red](**)"
663-
if run.expected_start_time < now
666+
if run.expected_start_time and run.expected_start_time < now
664667
else f"{run.expected_start_time}"
665668
),
666669
str(run.id),

src/prefect/locking/filesystem.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing_extensions import TypedDict
1010

1111
from prefect.logging.loggers import get_logger
12+
from prefect.types._datetime import DateTime, PendulumDuration
1213

1314
from .protocol import LockManager
1415

@@ -116,7 +117,7 @@ def acquire_lock(
116117
)
117118
return self.acquire_lock(key, holder, acquire_timeout, hold_timeout)
118119
expiration = (
119-
pendulum.now("utc") + pendulum.duration(seconds=hold_timeout)
120+
DateTime.now("utc") + PendulumDuration(seconds=hold_timeout)
120121
if hold_timeout is not None
121122
else None
122123
)
@@ -165,7 +166,7 @@ async def aacquire_lock(
165166
)
166167
return self.acquire_lock(key, holder, acquire_timeout, hold_timeout)
167168
expiration = (
168-
pendulum.now("utc") + pendulum.duration(seconds=hold_timeout)
169+
DateTime.now("utc") + PendulumDuration(seconds=hold_timeout)
169170
if hold_timeout is not None
170171
else None
171172
)
@@ -207,7 +208,7 @@ def is_locked(self, key: str, use_cache: bool = False) -> bool:
207208
if (expiration := lock_info.get("expiration")) is None:
208209
return True
209210

210-
expired = expiration < pendulum.now("utc")
211+
expired = expiration < DateTime.now("utc")
211212
if expired:
212213
Path(lock_info["path"]).unlink()
213214
self._locks.pop(key, None)

src/prefect/runner/runner.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ def fast_flow():
6464

6565
import anyio
6666
import anyio.abc
67-
import pendulum
6867
from cachetools import LRUCache
6968
from typing_extensions import Self
7069

@@ -105,6 +104,7 @@ def fast_flow():
105104
Pending,
106105
exception_to_failed_state,
107106
)
107+
from prefect.types._datetime import DateTime
108108
from prefect.types.entrypoint import EntrypointType
109109
from prefect.utilities.asyncutils import (
110110
asyncnullcontext,
@@ -797,7 +797,7 @@ async def _get_and_submit_flow_runs(self):
797797
if self.stopping:
798798
return
799799
runs_response = await self._get_scheduled_flow_runs()
800-
self.last_polled: pendulum.DateTime = pendulum.now("UTC")
800+
self.last_polled: DateTime = DateTime.now("UTC")
801801
return await self._submit_scheduled_flow_runs(flow_run_response=runs_response)
802802

803803
async def _check_for_cancelled_flow_runs(
@@ -1063,7 +1063,7 @@ async def _get_scheduled_flow_runs(
10631063
"""
10641064
Retrieve scheduled flow runs for this runner.
10651065
"""
1066-
scheduled_before = pendulum.now("utc").add(seconds=int(self._prefetch_seconds))
1066+
scheduled_before = DateTime.now("utc").add(seconds=int(self._prefetch_seconds))
10671067
self._logger.debug(
10681068
f"Querying for flow runs scheduled before {scheduled_before}"
10691069
)

src/prefect/runner/server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import uuid
22
from typing import TYPE_CHECKING, Any, Callable, Coroutine, Hashable, Optional, Tuple
33

4-
import pendulum
54
import uvicorn
65
from fastapi import APIRouter, FastAPI, HTTPException, status
76
from fastapi.responses import JSONResponse
@@ -22,6 +21,7 @@
2221
PREFECT_RUNNER_SERVER_MISSED_POLLS_TOLERANCE,
2322
PREFECT_RUNNER_SERVER_PORT,
2423
)
24+
from prefect.types._datetime import DateTime
2525
from prefect.utilities.asyncutils import run_coro_as_sync
2626
from prefect.utilities.importtools import load_script_as_module
2727

@@ -54,7 +54,7 @@ def perform_health_check(
5454
)
5555

5656
def _health_check():
57-
now = pendulum.now("utc")
57+
now = DateTime.now("utc")
5858
poll_delay = (now - runner.last_polled).total_seconds()
5959

6060
if poll_delay > delay_threshold:

src/prefect/types/_datetime.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from __future__ import annotations
22

3+
from typing import Any
4+
35
import pendulum
6+
import pendulum.tz
47
from pendulum.date import Date as PendulumDate
58
from pendulum.datetime import DateTime as PendulumDateTime
69
from pendulum.duration import Duration as PendulumDuration
710
from pendulum.time import Time as PendulumTime
11+
from pendulum.tz.timezone import FixedTimezone, Timezone
812
from pydantic_extra_types.pendulum_dt import Date as PydanticDate
913
from pydantic_extra_types.pendulum_dt import DateTime as PydanticDateTime
1014
from typing_extensions import TypeAlias
@@ -15,5 +19,28 @@
1519

1620
def parse_datetime(
1721
value: str,
22+
**options: Any,
1823
) -> PendulumDateTime | PendulumDate | PendulumTime | PendulumDuration:
19-
return pendulum.parse(value)
24+
return pendulum.parse(value, **options)
25+
26+
27+
def format_diff(
28+
diff: PendulumDuration,
29+
is_now: bool = True,
30+
absolute: bool = False,
31+
locale: str | None = None,
32+
) -> str:
33+
return pendulum.format_diff(diff, is_now, absolute, locale)
34+
35+
36+
def local_timezone() -> Timezone | FixedTimezone:
37+
return pendulum.tz.local_timezone()
38+
39+
40+
def from_format(
41+
value: str,
42+
fmt: str,
43+
tz: str | Timezone = pendulum.tz.UTC,
44+
locale: str | None = None,
45+
) -> DateTime:
46+
return DateTime.instance(pendulum.from_format(value, fmt, tz, locale))

0 commit comments

Comments
 (0)