fix: raise on any nested container in approx(), not only same-type - #14934
Merged
Conversation
approx() rejects a nested container only when it is the same type as its
parent, so approx([[1]]) and approx({"k": {"k": 1}}) raise a clear
TypeError while approx([{"k": 1}]) and approx({"k": [1]}) are accepted.
The inner container is then compared exactly, so the values are unequal
however close they are and the tolerance is silently ignored.
Replace both isinstance(value, type(expected)) guards with a check for
any Collection other than str/bytes/bytearray, which compare exactly and
are already handled as leaves.
Closes pytest-dev#10210
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
onk3sh
pushed a commit
to onk3sh/onk3sh.github.io
that referenced
this pull request
Aug 25, 2026
Only contributions actually merged upstream are listed. Two qualify: pytest-dev/pytest#14934, which fixes approx() silently ignoring its tolerance for a container nested inside a different container type, and mightymoose/fortymm--#341, which rewrites the Devise mailer templates for an open-source table tennis league platform. Contributions that are open, superseded, or closed pending a linked issue are deliberately left off. Listing work that has not landed invites the reader to check, and what they find is weaker than the claim. The entries live in projects.ts alongside everything else, under a new `open-source` projectType, so they get a page under /post/ and appear in the /post/ listing without any parallel data path. Project gains an optional `link` field; [slug].astro uses it for the outbound link so each page points at its own merged PR instead of the GitHub profile. Existing entries have no `link` and fall back to the previous target, so nothing else changes. The homepage section sits below Writing and reuses the .grid-3 + .card pattern. No new nav item. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
onk3sh
added a commit
to onk3sh/onk3sh.github.io
that referenced
this pull request
Aug 26, 2026
Content and structure cleanup across the site. - Moved a project page to a descriptive slug and left a noindex redirect stub at the old URL so existing links keep resolving. - Dropped an outbound repository link that no longer pointed anywhere useful, along with the string interpolation that built it. - Corrected two legacy pages under post/ that Astro no longer builds. A rebuild never overwrites them, so edits under src/ never reach them. - Removed data/terminal-commands.json and src/data/now.ts. Neither was referenced by any source file or any built page, yet the JSON was still being published at /data/terminal-commands.json carrying a stale bio and a project that does not exist anywhere on the site. - The terminal's `lab` command advertised two demos that are not in /lab/. It points at the real ones now. - Standardized spelling: -ise/-isation to -ize/-ization. Two spellings of the same word had been in use for the same concept. - The About page had no <h1>, starting at <h2> while every other page had exactly one. Promoted the headline and moved the style hook with it, so the rendering is unchanged. Adds an Open Source section to the homepage, below Writing, reusing the existing .grid-3 + .card pattern. No new nav item. It lists only contributions that merged upstream: pytest-dev/pytest#14934, which fixes approx() silently ignoring its tolerance for a container nested inside a different container type, and mightymoose/fortymm--#341, which rewrites the Devise mailer templates for an open-source table tennis league platform. The entries live in projects.ts under a new `open-source` projectType, so each gets a page under /post/ and appears in the /post/ listing with no parallel data path. Project gains an optional `link` field, and [slug].astro uses it for the outbound link so each page points at its own merged PR. Existing entries have no `link` and fall back to the previous target. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10210
What is wrong
approx()refuses to descend into a nested container, and says so clearly — but only when that container happens to be the same type as the one holding it. Both guards test against the parent's type:src/_pytest/approx.py:263—ApproxMapping.__init__:if isinstance(value, type(expected)):src/_pytest/approx.py:361—ApproxSequenceLike.__init__:if isinstance(x, type(expected)):A dict inside a list, a list inside a dict, a tuple inside a list, a set inside a tuple — none of those match, so they slip past and are compared with
==as leaf values. That comparison is exact, so the tolerance is silently ignored:Passing
rel=explicitly produces a third behaviour — an error from a lower layer that does not mention nesting at all:Reported in #10210 in 2022 and still reproducing on
main.The change
Ask whether the value is a container at all, rather than whether it matches the parent's type:
str,bytesandbytearrayareCollections too, butapproxtreats them as leaves on purpose and compares them exactly —test_nonnumeric_okay_if_equalcovers that, and this PR extends it withbytescases so the exclusion is pinned by a test rather than by the implementation.Both existing error messages are untouched, so a nested dict in a list now reports "does not support nested data structures" (the sequence wording, from the container that actually holds it) and a list in a dict reports "does not support nested dictionaries".
#10215 attempted this in 2022 and was closed as stale during the 2026 sprint, with @Zac-HD noting "we'd be delighted to accept a fresh version of this patch". That patch only touched
ApproxSequenceLike, soapprox({"a": [1.0]})would still have been silently wrong; this one covers both sides.Behaviour change worth flagging
A numpy array nested inside a list or dict now raises instead of returning a result. That case was already broken —
[np.array([1.0])] == approx([np.array([1.0 + 1e-9])])returnedFalsebefore this PR — so this converts a silent wrong answer into a clear error, but it is a visible change for anyone relying on theFalse. A top-level array is unaffected:ApproxNumpyhandles it and does its own nesting.Tests
testing/python/approx.py:test_expected_value_type_errorwith every cross-kind combination — list-of-tuple, list-of-set, list-of-dict, tuple-of-dict, dict-of-list, dict-of-tuple, dict-of-settest_mixed_nested_containers_raise_instead_of_comparing_unequal, which pins the actual bug: values well inside the default tolerance used to compareFalseinstead of raisingtest_nonnumeric_okay_if_equalwithbytesleavesBefore the change 11 of these fail; after,
testing/python/approx.pyis 149 passed. Full suite:4483 passed, 51 skipped, 13 xfailed, 7 xpassed.ruff0.16.3 check and format clean,mypy2.3.1 clean on both touched files.Checklist
closes #10210in the PR description and the commit.changelog/10210.bugfix.rst.AUTHORSin alphabetical order.Co-authored-bytrailer.