Skip to content

Commit 86881af

Browse files
committed
Change default to UTC, fix linting
1 parent 2cc714c commit 86881af

File tree

6 files changed

+45
-27
lines changed

6 files changed

+45
-27
lines changed

src/pip/_internal/cli/cmdoptions.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -805,13 +805,16 @@ def _handle_exclude_newer_than(
805805
Process a value provided for the --exclude-newer-than option.
806806
807807
This is an optparse.Option callback for the --exclude-newer-than option.
808+
809+
Parses an ISO 8601 datetime string. If no timezone is specified in the string,
810+
UTC timezone is applied automatically for consistency with PyPI upload times.
808811
"""
809812
if value is None:
810813
return None
811814
exclude_newer_than = datetime.datetime.fromisoformat(value)
812-
# Assume local timezone if no offset is given in the ISO string.
815+
# Assume UTC timezone if no offset is given in the ISO string.
813816
if exclude_newer_than.tzinfo is None:
814-
exclude_newer_than = exclude_newer_than.astimezone()
817+
exclude_newer_than = exclude_newer_than.replace(tzinfo=datetime.timezone.utc)
815818
parser.values.exclude_newer_than = exclude_newer_than
816819

817820

@@ -823,7 +826,11 @@ def _handle_exclude_newer_than(
823826
action="callback",
824827
callback=_handle_exclude_newer_than,
825828
type="str",
826-
help="Exclude packages newer than given time. This should be an ISO 8601 string.",
829+
help=(
830+
"Exclude packages newer than given time. "
831+
"This should be an ISO 8601 string. "
832+
"If no timezone is specified, UTC is assumed."
833+
),
827834
)
828835

829836
no_build_isolation: Callable[..., Option] = partial(

src/pip/_internal/cli/req_command.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
PackageFinder machinery and all its vendored dependencies, etc.
66
"""
77

8+
from __future__ import annotations
9+
810
import datetime
911
import logging
1012
from functools import partial

src/pip/_internal/commands/index.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from __future__ import annotations
2+
13
import datetime
4+
import json
25
import logging
36
from collections.abc import Iterable
47
from optparse import Values

src/pip/_internal/commands/list.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ def handle_pip_version_check(self, options: Values) -> None:
145145
def _build_package_finder(
146146
self,
147147
options: Values,
148-
session: "PipSession",
149-
) -> "PackageFinder":
148+
session: PipSession,
149+
) -> PackageFinder:
150150
"""
151151
Create a package finder appropriate to this list command.
152152
"""

src/pip/_internal/index/package_finder.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Routines related to PyPI, indexes"""
2+
23
from __future__ import annotations
34

45
import datetime
@@ -132,8 +133,8 @@ def __init__(
132133
formats: frozenset[str],
133134
target_python: TargetPython,
134135
allow_yanked: bool,
135-
ignore_requires_python: Optional[bool] = None,
136-
exclude_newer_than: Optional[datetime.datetime] = None,
136+
ignore_requires_python: bool | None = None,
137+
exclude_newer_than: datetime.datetime | None = None,
137138
) -> None:
138139
"""
139140
:param project_name: The user supplied package name.
@@ -152,6 +153,8 @@ def __init__(
152153
PEP 503 "data-requires-python" values in HTML links. Defaults
153154
to False.
154155
:param exclude_newer_than: If set, only allow links prior to the given date.
156+
This should be a timezone-aware datetime. If a timezone-naive datetime
157+
is provided to the command line option, UTC is assumed.
155158
"""
156159
if ignore_requires_python is None:
157160
ignore_requires_python = False
@@ -181,8 +184,15 @@ def evaluate_link(self, link: Link) -> tuple[LinkType, str]:
181184
return (LinkType.yanked, f"yanked for reason: {reason}")
182185

183186
if link.upload_time is not None and self._exclude_newer_than is not None:
184-
if link.upload_time > self._exclude_newer_than:
185-
reason = f"Upload time {link.upload_time} after {self._exclude_newer_than}"
187+
upload_time = link.upload_time
188+
assert upload_time.tzinfo is not None
189+
exclude_cutoff = self._exclude_newer_than
190+
assert exclude_cutoff.tzinfo is not None
191+
192+
if upload_time > exclude_cutoff:
193+
reason = (
194+
f"Upload time {link.upload_time} after {self._exclude_newer_than}"
195+
)
186196
return (LinkType.upload_too_late, reason)
187197

188198
if link.egg_fragment:
@@ -599,10 +609,10 @@ def __init__(
599609
link_collector: LinkCollector,
600610
target_python: TargetPython,
601611
allow_yanked: bool,
602-
format_control: Optional[FormatControl] = None,
603-
candidate_prefs: Optional[CandidatePreferences] = None,
604-
ignore_requires_python: Optional[bool] = None,
605-
exclude_newer_than: Optional[datetime.datetime] = None,
612+
format_control: FormatControl | None = None,
613+
candidate_prefs: CandidatePreferences | None = None,
614+
ignore_requires_python: bool | None = None,
615+
exclude_newer_than: datetime.datetime | None = None,
606616
) -> None:
607617
"""
608618
This constructor is primarily meant to be used by the create() class
@@ -647,9 +657,9 @@ def create(
647657
cls,
648658
link_collector: LinkCollector,
649659
selection_prefs: SelectionPreferences,
650-
target_python: Optional[TargetPython] = None,
651-
exclude_newer_than: Optional[datetime.datetime] = None,
652-
) -> "PackageFinder":
660+
target_python: TargetPython | None = None,
661+
exclude_newer_than: datetime.datetime | None = None,
662+
) -> PackageFinder:
653663
"""Create a PackageFinder.
654664
655665
:param selection_prefs: The candidate selection preferences, as a

src/pip/_internal/models/link.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@
1010
import urllib.parse
1111
from collections.abc import Mapping
1212
from dataclasses import dataclass
13-
from typing import (
14-
TYPE_CHECKING,
15-
Any,
16-
NamedTuple,
17-
)
13+
from typing import TYPE_CHECKING, Any, NamedTuple
1814

1915
from pip._internal.utils.deprecation import deprecated
2016
from pip._internal.utils.filetypes import WHEEL_EXTENSION
@@ -216,11 +212,11 @@ class Link:
216212
def __init__(
217213
self,
218214
url: str,
219-
comes_from: Optional[Union[str, "IndexContent"]] = None,
220-
requires_python: Optional[str] = None,
221-
yanked_reason: Optional[str] = None,
222-
metadata_file_data: Optional[MetadataFile] = None,
223-
upload_time: Optional[datetime.datetime] = None,
215+
comes_from: str | IndexContent | None = None,
216+
requires_python: str | None = None,
217+
yanked_reason: str | None = None,
218+
metadata_file_data: MetadataFile | None = None,
219+
upload_time: datetime.datetime | None = None,
224220
cache_link_parsing: bool = True,
225221
hashes: Mapping[str, str] | None = None,
226222
) -> None:
@@ -306,7 +302,7 @@ def from_json(
306302
if metadata_info is None:
307303
metadata_info = file_data.get("dist-info-metadata")
308304

309-
upload_time: Optional[datetime.datetime]
305+
upload_time: datetime.datetime | None
310306
if upload_time_data := file_data.get("upload-time"):
311307
upload_time = datetime.datetime.fromisoformat(upload_time_data)
312308
else:

0 commit comments

Comments
 (0)