Skip to content

docs(migration): warn that suites asserting on closed break in 3.1 - #385

Merged
lesnik512 merged 1 commit into
mainfrom
docs/migration-note-closed-assertions
Jul 28, 2026
Merged

docs(migration): warn that suites asserting on closed break in 3.1#385
lesnik512 merged 1 commit into
mainfrom
docs/migration-note-closed-assertions

Conversation

@lesnik512

Copy link
Copy Markdown
Member

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()/with call 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 main branches, for exactly two shapes:

  • assert container.closed is True on a freshly built container — False in 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_init opens the root — with containers now born open, assert closed is False passes 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 at container.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-ci and mkdocs build --strict clean. Docs-only.

🤖 Generated with Claude Code

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.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@lesnik512
lesnik512 merged commit d454289 into main Jul 28, 2026
9 checks passed
@lesnik512
lesnik512 deleted the docs/migration-note-closed-assertions branch July 28, 2026 10:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant