From 9ca2c14cd8af9f7cadc957ecbba9de7a08256664 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 26 Aug 2024 13:51:54 +0300 Subject: [PATCH] feat: drop `cachetools` dependency in favor of simple local implementation --- .kokoro/requirements.txt | 4 ---- google/auth/_cache.py | 42 +++++++++++++++++++++++++++++++++++++ google/auth/jwt.py | 7 +++---- noxfile.py | 1 - setup.py | 1 - testing/constraints-3.7.txt | 1 - tests/test__cache.py | 22 +++++++++++++++++++ 7 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 google/auth/_cache.py create mode 100644 tests/test__cache.py diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 9622baf0b..264902dd5 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -16,10 +16,6 @@ backports-tarfile==1.2.0 \ --hash=sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34 \ --hash=sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991 # via jaraco-context -cachetools==5.3.3 \ - --hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \ - --hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105 - # via google-auth certifi==2024.7.4 \ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90 diff --git a/google/auth/_cache.py b/google/auth/_cache.py new file mode 100644 index 000000000..f03480230 --- /dev/null +++ b/google/auth/_cache.py @@ -0,0 +1,42 @@ +from collections import OrderedDict + + +class LRUCache(dict): + def __init__(self, maxsize): + super().__init__() + self._order = OrderedDict() + self.maxsize = maxsize + + def clear(self): + super().clear() + self._order.clear() + + def __getitem__(self, key): + value = super().__getitem__(key) + self._update(key) + return value + + def __setitem__(self, key, value): + maxsize = self.maxsize + if maxsize <= 0: + return + if key not in self: + while len(self) >= maxsize: + self.popitem() + super().__setitem__(key, value) + self._update(key) + + def __delitem__(self, key): + super().__delitem__(key) + del self._order[key] + + def popitem(self): + """Remove and return the least recently used key-value pair.""" + key, _ = self._order.popitem(last=False) + return key, super().pop(key) + + def _update(self, key): + try: + self._order.move_to_end(key) + except KeyError: + self._order[key] = None diff --git a/google/auth/jwt.py b/google/auth/jwt.py index 1ebd565d4..3225d9e2e 100644 --- a/google/auth/jwt.py +++ b/google/auth/jwt.py @@ -50,8 +50,7 @@ import json import urllib -import cachetools - +from google.auth import _cache from google.auth import _helpers from google.auth import _service_account_info from google.auth import crypt @@ -629,7 +628,7 @@ def __init__( token_lifetime (int): The amount of time in seconds for which the token is valid. Defaults to 1 hour. max_cache_size (int): The maximum number of JWT tokens to keep in - cache. Tokens are cached using :class:`cachetools.LRUCache`. + cache. Tokens are cached using :class:`google.auth._cache.LRUCache`. quota_project_id (Optional[str]): The project ID used for quota and billing. @@ -645,7 +644,7 @@ def __init__( additional_claims = {} self._additional_claims = additional_claims - self._cache = cachetools.LRUCache(maxsize=max_cache_size) + self._cache = _cache.LRUCache(maxsize=max_cache_size) @classmethod def _from_signer_and_info(cls, signer, info, **kwargs): diff --git a/noxfile.py b/noxfile.py index 07cef9bcc..e3c8951cb 100644 --- a/noxfile.py +++ b/noxfile.py @@ -73,7 +73,6 @@ def mypy(session): session.install("-e", ".") session.install( "mypy", - "types-cachetools", "types-certifi", "types-freezegun", "types-pyOpenSSL", diff --git a/setup.py b/setup.py index 4e4c0d47b..70ac90cd6 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,6 @@ DEPENDENCIES = ( - "cachetools>=2.0.0,<6.0", "pyasn1-modules>=0.2.1", # rsa==4.5 is the last version to support 2.7 # https://github.com/sybrenstuvel/python-rsa/issues/152#issuecomment-643470233 diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index 6c4dd2e8c..dec647cfd 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -5,7 +5,6 @@ # # e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", # Then this file should have foo==1.14.0 -cachetools==2.0.0 pyasn1-modules==0.2.1 setuptools==40.3.0 rsa==3.1.4 diff --git a/tests/test__cache.py b/tests/test__cache.py new file mode 100644 index 000000000..6ac9326fb --- /dev/null +++ b/tests/test__cache.py @@ -0,0 +1,22 @@ +from google.auth._cache import LRUCache + + +def test_lru_cache(): + lru_cache = LRUCache(2) + lru_cache["a"] = 1 + lru_cache["b"] = 2 + assert lru_cache["a"] == 1 + lru_cache["c"] = 3 + assert "b" not in lru_cache + assert lru_cache["a"] == 1 + assert lru_cache["c"] == 3 + lru_cache["d"] = 4 + assert "a" not in lru_cache + assert lru_cache["c"] == 3 + assert lru_cache["d"] == 4 + + +def test_zero_size_lru_cache(): + lru_cache = LRUCache(0) + lru_cache["a"] = 1 + assert "a" not in lru_cache