docs(migration): warn that suites asserting on closed break in 3.1 - #385
Merged
Conversation
3.1 is a relaxation for callers but not for tests that assert the lifecycle flag. Three official integrations - arq, celery and flask - were red against 3.1.1 on main for exactly two shapes: asserting a freshly built container is closed, and expecting open() to raise ValidationFailedError. Notes the trap that flipping the assertion can hide: where a test's subject is the lifecycle transition itself, it must close the container first or the assertion passes without proving anything.
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: c953a10 | Previous: 937d3fe | Ratio |
|---|---|---|---|
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type |
2124942.352205299 iter/sec (stddev: 1.9047255815500907e-7) |
2493510.9484914956 iter/sec (stddev: 1.5740033239517621e-7) |
1.17 |
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry |
2481020.413479061 iter/sec (stddev: 5.896949125451357e-8) |
3319784.9929585014 iter/sec (stddev: 4.400008843896513e-8) |
1.34 |
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve |
27908.34227180695 iter/sec (stddev: 0.000017181359961750386) |
30303.39268149637 iter/sec (stddev: 0.000024252553210697023) |
1.09 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] |
407.3929401386626 iter/sec (stddev: 0.00005096774541764643) |
576.180312188467 iter/sec (stddev: 0.00013123493723667202) |
1.41 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] |
388.4307853617585 iter/sec (stddev: 0.000035843119151145346) |
542.8577225672404 iter/sec (stddev: 0.00012370452251536345) |
1.40 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] |
351.40404805162 iter/sec (stddev: 0.0001055273420638492) |
489.7685391989075 iter/sec (stddev: 0.00009321145800633289) |
1.39 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] |
2384.2277137742703 iter/sec (stddev: 0.000029247297469794863) |
2891.964101751045 iter/sec (stddev: 0.000026342202976310143) |
1.21 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] |
1671.346646194141 iter/sec (stddev: 0.0003446871257894658) |
1981.3754014562955 iter/sec (stddev: 0.0004238031793177577) |
1.19 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] |
1162.1194610769105 iter/sec (stddev: 0.00008920816168787231) |
1362.3710460473576 iter/sec (stddev: 0.00006392747324820343) |
1.17 |
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container |
646031.0627970659 iter/sec (stddev: 5.075795839540936e-7) |
875992.4286487021 iter/sec (stddev: 3.519122519479823e-7) |
1.36 |
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope |
610805.4229707989 iter/sec (stddev: 4.279575835712783e-7) |
854596.867377346 iter/sec (stddev: 2.5246215835802713e-7) |
1.40 |
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch |
2104.6990888314876 iter/sec (stddev: 0.000054171222133724053) |
2656.41909512412 iter/sec (stddev: 0.000017102485689559324) |
1.26 |
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control |
61713.409225668336 iter/sec (stddev: 0.0000013857116758177663) |
90422.75294057408 iter/sec (stddev: 0.0000011576717305400116) |
1.47 |
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale |
43588.862218757306 iter/sec (stddev: 0.000001682886867261457) |
55617.09968528953 iter/sec (stddev: 0.0000013886890562583377) |
1.28 |
benchmarks/test_guard_resolve.py::test_g1_transient_resolve |
1269118.4283284408 iter/sec (stddev: 3.8497651703443085e-7) |
1878201.6615606395 iter/sec (stddev: 2.5761231764465055e-7) |
1.48 |
benchmarks/test_guard_resolve.py::test_g2_cached_resolve |
3178690.578070765 iter/sec (stddev: 4.891632359968183e-8) |
4493371.807885467 iter/sec (stddev: 3.0230502513483404e-8) |
1.41 |
benchmarks/test_guard_resolve.py::test_g3_deep_chain |
506116.9501049569 iter/sec (stddev: 8.392756653821641e-7) |
737779.937965571 iter/sec (stddev: 3.5247245465464004e-7) |
1.46 |
benchmarks/test_guard_resolve.py::test_g4_wide_resolve |
319913.9886573075 iter/sec (stddev: 6.905065470500096e-7) |
430691.90189708886 iter/sec (stddev: 3.8600465223101784e-7) |
1.35 |
benchmarks/test_guard_resolve.py::test_g5_cross_scope |
1184664.2795411644 iter/sec (stddev: 3.476392111681786e-7) |
1533020.2638274496 iter/sec (stddev: 2.8944638419274865e-7) |
1.29 |
benchmarks/test_guard_resolve.py::test_g9_context_resolve |
596337.122475179 iter/sec (stddev: 5.603347039047435e-7) |
744479.3330129668 iter/sec (stddev: 3.6590343964778644e-7) |
1.25 |
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve |
397306.96802732 iter/sec (stddev: 4.2744432827531493e-7) |
601593.9363375851 iter/sec (stddev: 2.7236558114434024e-7) |
1.51 |
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain |
31923.238487313647 iter/sec (stddev: 0.000002294991025370369) |
32389.953970852996 iter/sec (stddev: 0.0000023827751735272966) |
1.01 |
benchmarks/test_guard_validate.py::test_g11_validate_wide |
18591.60752154861 iter/sec (stddev: 0.0000029762961399647496) |
20791.88701676549 iter/sec (stddev: 0.000002968512709059663) |
1.12 |
This comment was automatically generated by workflow using github-action-benchmark.
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.
The 3.1 note in this guide says the mandatory-open requirement is "relaxed, not reversed", and the release notes say integrations need no code change. That is true of runtime code and of every
open()/withcall site — I verified those. It is not true of test suites that assert on the lifecycle flag, and that gap was found the hard way.Three official integrations were red against 3.1.1 on their own
mainbranches, for exactly two shapes:assert container.closed is Trueon a freshly built container —Falsein 3.1, since construction leaves it open. (arq ×2, celery ×1)with pytest.raises(ValidationFailedError): container.open()—open()validates nothing in 3.1, so it does not raise. (flask ×1)This adds the caveat where someone hitting the failure will look, rather than amending the published release notes after the fact.
It also records the non-obvious part, which cost real thought while fixing those three: flipping the assertion can silently gut the test. celery's failing test existed to prove
worker_initopens the root — with containers now born open,assert closed is Falsepasses whether or not the signal does anything. That one needed the container closed first to keep the transition observable. Where the subject is the validation-ordering rule instead, the fix is to point it atcontainer.validate(), since the rule still holds and only the call it binds to changed.Fixes for all three integrations are open alongside this: arq#8, celery#9, flask#8.
just lint-ciandmkdocs build --strictclean. Docs-only.🤖 Generated with Claude Code