From c953a1074b2f2a7eab8387b4fc6b691d7c1a8429 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Tue, 28 Jul 2026 13:14:48 +0300 Subject: [PATCH] docs(migration): warn that suites asserting on closed break in 3.1 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. --- docs/migration/to-3.x.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/migration/to-3.x.md b/docs/migration/to-3.x.md index 8718a4a..fd74a69 100644 --- a/docs/migration/to-3.x.md +++ b/docs/migration/to-3.x.md @@ -264,6 +264,22 @@ part was wrong and has been corrected here: **validation is explicit-only as of `open()` (and `with`/`async with`, which call it) no longer runs `validate()` — it only clears `closed`, unconditionally. Nothing validates automatically: not construction, not `open()`, not `add_providers`, not `resolve()`. + +!!! warning "A test suite that asserts on `closed` will fail" + 3.1 is a relaxation for *callers*, but not for *tests that assert the lifecycle flag*. + Two 3.0-era assertions break, and both were found in the wild across the official + integrations: + + - `assert container.closed is True` on a freshly built container — it is `False` in + 3.1, because construction leaves it open. + - `with pytest.raises(ValidationFailedError): container.open()` — `open()` validates + nothing in 3.1, so it does not raise. + + Both are mechanical to fix, but the second needs care: if a test's *subject* is the + lifecycle transition ("this signal opens the root"), flipping the assertion makes it + pass without proving anything. Close the container first, so the transition stays + observable. If the subject is the validation-ordering rule, point it at + `container.validate()` — the rule still holds, it just binds a different call. `container.validate()` is the only thing that walks the graph, and `Container(validate=...)` is deprecated — passing `True` or `False` is ignored and emits `ValidateArgumentWarning` (a `DeprecationWarning`), removed in 4.0. So in the "After (3.0)" example above, the comment