Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/requests/cookies.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,23 @@ 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:
cookie = next(iter(self))
except StopIteration:
raise KeyError("popitem(): cookie jar is empty") from None
# Remove the exact cookie the iterator selected. Deleting by name alone
# (``del self[name]``) would drop every cookie sharing that name across
# other domains/paths, not just the one returned here.
self.clear(cookie.domain, cookie.path, cookie.name)
return cookie.name, cookie.value

def list_domains(self) -> list[str]:
"""Utility method to list all the domains in the jar."""
domains: list[str] = []
Expand Down
34 changes: 34 additions & 0 deletions tests/test_requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,40 @@ 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_popitem_removes_only_the_selected_cookie(self):
# Two cookies share a name but live on different domains. popitem() must
# remove exactly the one it returns, not every cookie with that name.
jar = requests.cookies.RequestsCookieJar()
jar.set("dup", "value-a", domain="a.example.com", path="/")
jar.set("dup", "value-b", domain="b.example.com", path="/")
assert len(jar) == 2

name, value = jar.popitem()
assert name == "dup"
assert len(jar) == 1

remaining = next(iter(jar))
assert remaining.name == "dup"
assert {value, remaining.value} == {"value-a", "value-b"}

def test_cookie_as_dict_keeps_len(self):
key = "some_cookie"
value = "some_value"
Expand Down