Skip to content

tests: add Hypothesis property tests for URL roundtrip invariants#1686

Draft
aiolibsbot wants to merge 4 commits into
aio-libs:masterfrom
aiolibsbot:koan/url-hypothesis-roundtrip-tests
Draft

tests: add Hypothesis property tests for URL roundtrip invariants#1686
aiolibsbot wants to merge 4 commits into
aio-libs:masterfrom
aiolibsbot:koan/url-hypothesis-roundtrip-tests

Conversation

@aiolibsbot
Copy link
Copy Markdown
Contributor

@aiolibsbot aiolibsbot commented May 16, 2026

What do these changes do?

Add a new test module tests/test_url_roundtrip.py with
Hypothesis-driven property tests that pin down yarl.URL
normalization invariants:

  • URL(str(URL(s))) == URL(s) — parsing the textual form of a URL
    yields an equal object (idempotency of str -> URL).
  • Components passed to URL.build(...) are recovered after a
    str() -> URL() roundtrip when they only use characters
    yarl never re-encodes.
  • Normalization reaches a fixed point in at most one application —
    str(URL(str(URL(s)))) == str(URL(s)).
  • Equal URLs hash equal (Python __eq__/__hash__ contract).

Alphabets are restricted to RFC 3986 unreserved characters,
schemes whose default ports get stripped are filtered out, and .
is excluded from path strategies (yarl normalizes . segments per
RFC 3986 §5.2.4, which is intentional and not a roundtrip property).
The tests were stress-checked across eight Hypothesis seeds.

Are there changes in behavior for the user?

No. Tests-only addition — no production code is touched.

Related issue number

Related to #1482 (webknjaz suggested adding Hypothesis coverage for
quoting roundtrip behavior). This PR focuses on the broader
URL parse/build roundtrip surface and lays the foundation for
extending into quoter-level invariants later.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • Add a new news fragment into the CHANGES/ folder
    • name: 1686.contrib.rst
    • category: contrib

🤖 Generated with Claude Code


Quality Report

Changes: 6 files changed, 181 insertions(+), 342 deletions(-)

Code scan: clean

Tests: failed (FAILED)

Branch hygiene: clean

Generated by Kōan post-mission quality pipeline

Lock in the current normalization behavior of yarl.URL by asserting
idempotency invariants over restricted alphabets (RFC 3986 unreserved
characters):

* str(URL(s)) reparses to an equal URL
* URL.build(...) components survive a str()/URL() roundtrip
* yarl normalization reaches a fixed point in one application
* equal URLs hash equal

Alphabets are intentionally restricted to characters yarl never
re-encodes, so any future failure here is almost certainly a
regression rather than a property false-positive.
@psf-chronographer psf-chronographer Bot added the bot:chronographer:provided There is a change note present in this PR label May 16, 2026
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 16, 2026

Merging this PR will not alter performance

✅ 99 untouched benchmarks


Comparing aiolibsbot:koan/url-hypothesis-roundtrip-tests (e29154d) with master (067301d)

Open in CodSpeed

@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.80%. Comparing base (3867a90) to head (e29154d).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1686   +/-   ##
=======================================
  Coverage   99.80%   99.80%           
=======================================
  Files          21       22    +1     
  Lines        4128     4197   +69     
  Branches      241      242    +1     
=======================================
+ Hits         4120     4189   +69     
  Misses          5        5           
  Partials        3        3           
Flag Coverage Δ
CI-GHA 99.73% <100.00%> (+<0.01%) ⬆️
OS-Linux 99.71% <100.00%> (+<0.01%) ⬆️
OS-Windows 98.45% <100.00%> (+0.02%) ⬆️
OS-macOS 98.59% <100.00%> (+0.02%) ⬆️
Py-3.10.11 98.42% <100.00%> (+0.02%) ⬆️
Py-3.10.20 99.64% <100.00%> (+<0.01%) ⬆️
Py-3.11.15 99.64% <100.00%> (+<0.01%) ⬆️
Py-3.11.9 98.42% <100.00%> (+0.02%) ⬆️
Py-3.12.10 98.42% <100.00%> (+0.02%) ⬆️
Py-3.12.13 99.64% <100.00%> (+<0.01%) ⬆️
Py-3.13.13 99.69% <100.00%> (+<0.01%) ⬆️
Py-3.13.13t 99.69% <100.00%> (+<0.01%) ⬆️
Py-3.14.4 98.57% <100.00%> (+0.02%) ⬆️
Py-3.14.5 99.66% <100.00%> (+<0.01%) ⬆️
Py-3.14.5t 99.68% <100.00%> (+<0.01%) ⬆️
Py-pypy3.11.15-7.3.22 99.30% <100.00%> (+0.01%) ⬆️
VM-macos-latest 98.59% <100.00%> (+0.02%) ⬆️
VM-ubuntu-latest 99.71% <100.00%> (+<0.01%) ⬆️
VM-windows-latest 98.45% <100.00%> (+0.02%) ⬆️
pytest 99.73% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The yarl mypy config sets `disallow_any_decorated = True`, which
flags every Hypothesis `@given`-decorated function because their
type signatures still surface ``Any`` after decoration. The existing
``test_quoting.py`` works around this by tagging each decorated test
with ``# type: ignore[misc]`` — apply the same marker on the new
roundtrip tests so the lint job goes green.

The non-Hypothesis ``test_str_url_roundtrip_concrete_examples`` (only
``pytest.mark.parametrize``) does not trigger the rule and stays
unannotated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant