From 76cbba45b9c98832f2d3e2e6caf46e36b1090491 Mon Sep 17 00:00:00 2001 From: Vineeth Sai Date: Sat, 13 Jun 2026 02:53:10 -0700 Subject: [PATCH] Make RequestsCookieJar.popitem() work RequestsCookieJar subclasses both CookieJar and MutableMapping. Its __iter__ comes from CookieJar and yields Cookie objects rather than names, so the popitem() inherited from MutableMapping did `self[next(iter(self))]`, i.e. looked a cookie up by a Cookie object, and always raised KeyError even when the jar was non-empty. Override popitem() to remove and return a (name, value) pair using the jar's dict-like view, and raise KeyError only when the jar is empty, matching the documented behavior. --- src/requests/cookies.py | 14 ++++++++++++++ tests/test_requests.py | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/requests/cookies.py b/src/requests/cookies.py index 24dd9a7829..b6987ab5ba 100644 --- a/src/requests/cookies.py +++ b/src/requests/cookies.py @@ -299,6 +299,20 @@ def items(self) -> list[tuple[str, str | None]]: # type: ignore[override] """ return list(self.iteritems()) + def popitem(self) -> tuple[str, str | None]: + """Dict-like popitem() that removes and returns a (name, value) pair, + or raises KeyError if the jar is empty. + + The inherited ``MutableMapping.popitem`` does not work here because + ``__iter__`` yields ``Cookie`` objects rather than names. + """ + try: + name, value = next(self.iteritems()) + except StopIteration: + raise KeyError("popitem(): cookie jar is empty") from None + del self[name] + return name, value + def list_domains(self) -> list[str]: """Utility method to list all the domains in the jar.""" domains: list[str] = [] diff --git a/tests/test_requests.py b/tests/test_requests.py index 8bcb81d8b1..794be0f63c 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -1313,6 +1313,24 @@ def test_cookie_parameters(self): assert cookie.domain == domain assert cookie._rest["HttpOnly"] == rest["HttpOnly"] + def test_cookie_popitem(self): + jar = requests.cookies.RequestsCookieJar() + jar.set("some_cookie", "some_value") + jar.set("some_cookie1", "some_value1") + + items = dict(jar.items()) + + name, value = jar.popitem() + assert (name, value) in items.items() + assert name not in jar + assert len(jar) == 1 + + jar.popitem() + assert len(jar) == 0 + + with pytest.raises(KeyError): + jar.popitem() + def test_cookie_as_dict_keeps_len(self): key = "some_cookie" value = "some_value"