Repository navigation
Test failures with Python 3.15.0b1: test_bad_payload_exception[zlib] and test_loads_unsafe[zlib] #420
Copy link
Copy link
Open
Description
Hope you don't mind some early Python 3.15 testing reports.
$ uv venv -p 3.15
Using CPython 3.15.0b1 interpreter at: /usr/bin/python3.15
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
$ uv pip install -e . --group=tests
Resolved 9 packages in 2ms
Built itsdangerous @ file:///tmp/itsdangerous
Prepared 1 package in 164ms
░░░░░░░░░░░░░░░░░░░░ [0/9] Installing wheels... warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.
If the cache and target directories are on different filesystems, hardlinking may not be supported.
If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.
Installed 9 packages in 15ms
+ freezegun==1.5.5
+ iniconfig==2.3.0
+ itsdangerous==2.3.0.dev0 (from file:///tmp/itsdangerous)
+ packaging==26.2
+ pluggy==1.6.0
+ pygments==2.20.0
+ pytest==9.0.3
+ python-dateutil==2.9.0.post0
+ six==1.17.0
$ .venv/bin/pytest
========================================================= test session starts =========================================================
platform linux -- Python 3.15.0b1, pytest-9.0.3, pluggy-1.6.0
rootdir: /tmp/itsdangerous
configfile: pyproject.toml
testpaths: tests
collected 297 items
tests/test_itsdangerous/test_encoding.py ........ [ 2%]
tests/test_itsdangerous/test_serializer.py ......................................... [ 16%]
tests/test_itsdangerous/test_signer.py ................. [ 22%]
tests/test_itsdangerous/test_timed.py ......................................................................................... [ 52%]
............ [ 56%]
tests/test_itsdangerous/test_url_safe.py ...................................................................................... [ 85%]
.........................F.F................ [100%]
============================================================== FAILURES ===============================================================
_____________________________________ TestURLSafeTimedSerializer.test_bad_payload_exception[zlib] _____________________________________
self = <test_itsdangerous.test_url_safe.TestURLSafeTimedSerializer object at 0x7f30bde13650>
serializer = <itsdangerous.url_safe.URLSafeTimedSerializer object at 0x7f30bd735860>
value = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
def test_bad_payload_exception(self, serializer: Serializer, value: Any):
original = serializer.dumps(value)
payload = original.rsplit(coerce_str(original, "."), 1)[0] # type: ignore
bad = serializer.make_signer().sign(payload[:-1])
> with pytest.raises(BadPayload) as exc_info:
^^^^^^^^^^^^^^^^^^^^^^^^^
E Failed: DID NOT RAISE <class 'itsdangerous.exc.BadPayload'>
tests/test_itsdangerous/test_serializer.py:85: Failed
_________________________________________ TestURLSafeTimedSerializer.test_loads_unsafe[zlib] __________________________________________
self = <test_itsdangerous.test_url_safe.TestURLSafeTimedSerializer object at 0x7f30bde183d0>
serializer = <itsdangerous.url_safe.URLSafeTimedSerializer object at 0x7f30bd730af0>
value = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
def test_loads_unsafe(self, serializer: Serializer, value: Any):
signed = serializer.dumps(value)
assert serializer.loads_unsafe(signed) == (True, value)
bad_signed = signed[:-1]
assert serializer.loads_unsafe(bad_signed) == (False, value)
payload = signed.rsplit(coerce_str(signed, "."), 1)[0] # type: ignore
bad_payload = serializer.make_signer().sign(payload[:-1])[:-1]
> assert serializer.loads_unsafe(bad_payload) == (False, None)
E AssertionError: assert (False, 'aaaa...aaaaaaaaaaaa') == (False, None)
E
E At index 1 diff: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...
E
E ...Full output truncated (2 lines hidden), use '-vv' to show
tests/test_itsdangerous/test_serializer.py:99: AssertionError
======================================================= short test summary info =======================================================
FAILED tests/test_itsdangerous/test_url_safe.py::TestURLSafeTimedSerializer::test_bad_payload_exception[zlib] - Failed: DID NOT RAISE <class 'itsdangerous.exc.BadPayload'>
FAILED tests/test_itsdangerous/test_url_safe.py::TestURLSafeTimedSerializer::test_loads_unsafe[zlib] - AssertionError: assert (False, 'aaaa...aaaaaaaaaaaa') == (False, None)
==================================================== 2 failed, 295 passed in 0.85s ====================================================
Environment:
- Python version: 3.15.0b1
- ItsDangerous version: 672971d
Metadata
Metadata
Assignees
Labels
No labels
Activity
mgorny commentedon Jun 30, 2026
Additional data point: it seems to only happen with zlib-ng (2.3.3) is used as
libz.so. Curious enough, the issue doesn't occur with Python 3.14 while zlib-ng is also used.mgorny commentedon Jul 1, 2026
Okay, so the plot thickens. I've added some prints to debug this further…
On a vanilla zlib system I get:
On a zlib-ng system I get:
But the curious thing is, the results are the same for Python 3.14 and 3.15 — except for the fact that zlib-ng + 3.14 throws
BadPayloadas expected, so there's noserializer.loads(bad)there, while zlib-ng + 3.15 doesn't throw and gives you the payload.mgorny commentedon Jul 1, 2026
And I've just noticed #421. While I don't think the solution there is exactly correct, adding
padded=Trueto restore the old behavior does fix the test failures indeed. @davidism, did you close that PR because it's slop or some other reason? I don't know if I should open a PR addingpadded=Trueor if that's not the right solution here.davidism commentedon Jul 2, 2026
Yes, that was AI junk. I haven't looked into what the correct solution is. If you want to author a PR without AI generated code, I'm happy to review it.
require padding when decoding base64 on Python 3.15+
mgorny commentedon Jul 3, 2026
Filed #428. It's the conservative approach: making Python 3.15 behave like older Python versions.