From f61250303515e04c8bfc5306d91686cc0d661ee9 Mon Sep 17 00:00:00 2001 From: Paul Ganssle <1377457+pganssle@users.noreply.github.com> Date: Thu, 31 Aug 2023 04:28:31 -0400 Subject: [PATCH] Remove uses of `utcnow` in non-vendored code (#12006) * Remove reference to utcnow This cleans up some of the datetime handling in the self check. Note that this changes the format of the state file, since the datetime now uses ``.isoformat()`` instead of ``.strftime``. Reading an outdated state file will still work on Python 3.11+, but not on earlier versions. * Use aware datetime object in x509.CertificateBuilder --- news/12005.bugfix.rst | 1 + src/pip/_internal/self_outdated_check.py | 15 ++++++--------- tests/lib/certs.py | 6 +++--- tests/unit/test_self_check_outdated.py | 11 ++++++++--- 4 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 news/12005.bugfix.rst diff --git a/news/12005.bugfix.rst b/news/12005.bugfix.rst new file mode 100644 index 000000000..98a3e5112 --- /dev/null +++ b/news/12005.bugfix.rst @@ -0,0 +1 @@ +Removed uses of ``datetime.datetime.utcnow`` from non-vendored code. diff --git a/src/pip/_internal/self_outdated_check.py b/src/pip/_internal/self_outdated_check.py index 41cc42c56..eefbc498b 100644 --- a/src/pip/_internal/self_outdated_check.py +++ b/src/pip/_internal/self_outdated_check.py @@ -28,8 +28,7 @@ from pip._internal.utils.entrypoints import ( from pip._internal.utils.filesystem import adjacent_tmp_file, check_path_owner, replace from pip._internal.utils.misc import ensure_dir -_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" - +_WEEK = datetime.timedelta(days=7) logger = logging.getLogger(__name__) @@ -73,12 +72,10 @@ class SelfCheckState: if "pypi_version" not in self._state: return None - seven_days_in_seconds = 7 * 24 * 60 * 60 - # Determine if we need to refresh the state - last_check = datetime.datetime.strptime(self._state["last_check"], _DATE_FMT) - seconds_since_last_check = (current_time - last_check).total_seconds() - if seconds_since_last_check > seven_days_in_seconds: + last_check = datetime.datetime.fromisoformat(self._state["last_check"]) + time_since_last_check = current_time - last_check + if time_since_last_check > _WEEK: return None return self._state["pypi_version"] @@ -100,7 +97,7 @@ class SelfCheckState: # Include the key so it's easy to tell which pip wrote the # file. "key": self.key, - "last_check": current_time.strftime(_DATE_FMT), + "last_check": current_time.isoformat(), "pypi_version": pypi_version, } @@ -229,7 +226,7 @@ def pip_self_version_check(session: PipSession, options: optparse.Values) -> Non try: upgrade_prompt = _self_version_check_logic( state=SelfCheckState(cache_dir=options.cache_dir), - current_time=datetime.datetime.utcnow(), + current_time=datetime.datetime.now(datetime.timezone.utc), local_version=installed_dist.version, get_remote_version=functools.partial( _get_current_remote_pip_version, session, options diff --git a/tests/lib/certs.py b/tests/lib/certs.py index 54b484ac0..9e6542d2d 100644 --- a/tests/lib/certs.py +++ b/tests/lib/certs.py @@ -1,4 +1,4 @@ -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Tuple from cryptography import x509 @@ -23,8 +23,8 @@ def make_tls_cert(hostname: str) -> Tuple[x509.Certificate, rsa.RSAPrivateKey]: .issuer_name(issuer) .public_key(key.public_key()) .serial_number(x509.random_serial_number()) - .not_valid_before(datetime.utcnow()) - .not_valid_after(datetime.utcnow() + timedelta(days=10)) + .not_valid_before(datetime.now(timezone.utc)) + .not_valid_after(datetime.now(timezone.utc) + timedelta(days=10)) .add_extension( x509.SubjectAlternativeName([x509.DNSName(hostname)]), critical=False, diff --git a/tests/unit/test_self_check_outdated.py b/tests/unit/test_self_check_outdated.py index c025ff302..011df08ae 100644 --- a/tests/unit/test_self_check_outdated.py +++ b/tests/unit/test_self_check_outdated.py @@ -49,7 +49,9 @@ def test_pip_self_version_check_calls_underlying_implementation( mocked_state.assert_called_once_with(cache_dir=str(tmpdir)) mocked_function.assert_called_once_with( state=mocked_state(cache_dir=str(tmpdir)), - current_time=datetime.datetime(1970, 1, 2, 11, 0, 0), + current_time=datetime.datetime( + 1970, 1, 2, 11, 0, 0, tzinfo=datetime.timezone.utc + ), local_version=ANY, get_remote_version=ANY, ) @@ -167,7 +169,10 @@ class TestSelfCheckState: # WHEN state = self_outdated_check.SelfCheckState(cache_dir=str(cache_dir)) - state.set("1.0.0", datetime.datetime(2000, 1, 1, 0, 0, 0)) + state.set( + "1.0.0", + datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc), + ) # THEN assert state._statefile_path == os.fspath(expected_path) @@ -175,6 +180,6 @@ class TestSelfCheckState: contents = expected_path.read_text() assert json.loads(contents) == { "key": sys.prefix, - "last_check": "2000-01-01T00:00:00Z", + "last_check": "2000-01-01T00:00:00+00:00", "pypi_version": "1.0.0", }