Skip to content

refactor(graph): move the validation walk into dependency_graph.collect_errors - #544

Merged
lesnik512 merged 1 commit into
mainfrom
refactor/536-collect-errors
Sep 27, 2026
Merged

lesnik512 merged 1 commit into
mainfrom
refactor/536-collect-errors

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Closes #536.

Container._walk_errors moves to dependency_graph.collect_errors(container), unchanged line for line apart from self becoming container. Container.validate calls it and keeps the memo check and the ValidationFailedError raise.

What it changes in container.py

  • The dependency_graph import drops from eight names to three: DependencyGraph and build_cycle_error stay for _handle_recursion_error, and collect_errors joins them.
  • The graph-event match leaves the class whose other jobs are lifecycle and the two resolve entry points.

Import direction

dependency_graph.py must not import Container at runtime, because container.py imports it. collect_errors takes the container as an argument and the annotation stays under TYPE_CHECKING, so nothing changes there.

Behaviour

None. validate() is boot-time only, _walk_errors was private with no caller outside validate, and the test that pinned the walk order (test_walk_errors_returns_flat_list_in_walk_order) is the same test renamed and calling collect_errors directly.

Checks

  • Full suite with coverage: 544 passed, 8 skipped, 100% line coverage.
  • ruff format, ruff check, eof-fixer clean. ty check reports only the pre-existing unused-ignore at tests/providers/test_factory.py:454.

…ct_errors

Container._walk_errors was the only consumer of the walk's event types
outside dependency_graph, and it pulled eight names from that module into
container.py. The walk now lives next to the events it matches on, and
Container.validate calls collect_errors(self). Closes #536.

@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: c10dbf3 Previous: a324645 Ratio
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type 3879663.6952339234 iter/sec (stddev: 9.140498264801621e-9) 3487208.6222819886 iter/sec (stddev: 1.6866072468572677e-8) 0.90
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry 3847085.580690999 iter/sec (stddev: 1.1779629421298373e-8) 3478393.713962888 iter/sec (stddev: 2.5288091962078263e-8) 0.90
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve 17913.529622302416 iter/sec (stddev: 0.000051318767321870626) 15495.645030450161 iter/sec (stddev: 0.00006109304292965719) 0.87
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached 15171.528759565816 iter/sec (stddev: 0.00013931550396566582) 13013.676096400704 iter/sec (stddev: 0.0001412755967184869) 0.86
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] 497.93733058288103 iter/sec (stddev: 0.000037040719290879074) 374.8261817484961 iter/sec (stddev: 0.00010874486815227522) 0.75
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] 468.266792211976 iter/sec (stddev: 0.00002936553583402235) 357.3724058607998 iter/sec (stddev: 0.00013858022845116602) 0.76
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] 422.28183447847476 iter/sec (stddev: 0.00011727004186672103) 329.0107566345924 iter/sec (stddev: 0.00014557533792018413) 0.78
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] 1676.052209864542 iter/sec (stddev: 0.0002237893539089371) 1478.1564324391036 iter/sec (stddev: 0.0002392316542320992) 0.88
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] 1467.6249099541644 iter/sec (stddev: 0.00017651812239734033) 1221.2978343280963 iter/sec (stddev: 0.00024729429484636353) 0.83
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] 1031.8627878395607 iter/sec (stddev: 0.0001997980541039297) 847.2282532354639 iter/sec (stddev: 0.00028247565834591025) 0.82
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[1] 1477.146730572983 iter/sec (stddev: 0.0013069305356307114) 1234.2242992958365 iter/sec (stddev: 0.0016211315341404478) 0.84
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[2] 1310.0193412344922 iter/sec (stddev: 0.00018906088961628999) 1060.0306954887758 iter/sec (stddev: 0.00032095727684094705) 0.81
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[4] 844.3436567057553 iter/sec (stddev: 0.0002168047021646993) 665.7575746998305 iter/sec (stddev: 0.00036024012466687617) 0.79
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container 813199.3145637609 iter/sec (stddev: 3.963318722000515e-8) 788970.5234656611 iter/sec (stddev: 9.484223391782856e-8) 0.97
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope 743387.6136384744 iter/sec (stddev: 1.4619854131155884e-7) 715171.5692083471 iter/sec (stddev: 4.815302438977803e-8) 0.96
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch 2479.01835873484 iter/sec (stddev: 0.0000487544148745425) 2429.264129387182 iter/sec (stddev: 0.000011202848205415609) 0.98
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control 58659.921860027585 iter/sec (stddev: 0.0000019196495823206577) 57191.07429995937 iter/sec (stddev: 0.0000021750260248608014) 0.97
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale 46438.194099809756 iter/sec (stddev: 0.00000289817401687082) 43540.05597346128 iter/sec (stddev: 0.0000021820092774815705) 0.94
benchmarks/test_guard_lifecycle.py::test_g13b_teardown_at_scale_async_no_finalizers 628.7375252444701 iter/sec (stddev: 0.00006339464634494698) 561.5006937878361 iter/sec (stddev: 0.00002505044399750245) 0.89
benchmarks/test_guard_resolve.py::test_g1_transient_resolve 2334132.190070908 iter/sec (stddev: 3.1197865872471324e-8) 2156077.9432966453 iter/sec (stddev: 2.899760252099538e-8) 0.92
benchmarks/test_guard_resolve.py::test_g2_cached_resolve 3745852.732319375 iter/sec (stddev: 9.134222425116083e-9) 3276618.4537722347 iter/sec (stddev: 2.0817515756959605e-8) 0.87
benchmarks/test_guard_resolve.py::test_g3_deep_chain 830848.5250339668 iter/sec (stddev: 4.435921291654024e-8) 711825.1128164383 iter/sec (stddev: 7.484690789204477e-8) 0.86
benchmarks/test_guard_resolve.py::test_g4_wide_resolve 484968.03975725145 iter/sec (stddev: 3.60685139406087e-7) 461696.48248650023 iter/sec (stddev: 3.759030085236763e-7) 0.95
benchmarks/test_guard_resolve.py::test_g5_cross_scope 2203324.916453447 iter/sec (stddev: 2.8700265922846043e-8) 1858217.968928989 iter/sec (stddev: 4.497840005869342e-8) 0.84
benchmarks/test_guard_resolve.py::test_g9_context_resolve 1190438.1744012316 iter/sec (stddev: 1.7533107171884601e-7) 1060758.2713874592 iter/sec (stddev: 2.0465904597179856e-7) 0.89
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve 824846.7259500753 iter/sec (stddev: 8.012042240617132e-8) 693384.1205018064 iter/sec (stddev: 7.278305868639698e-8) 0.84
benchmarks/test_guard_resolve.py::test_g18_alias_hop 2606071.134587685 iter/sec (stddev: 9.585619326111566e-9) 2042195.1833653012 iter/sec (stddev: 1.4270316268674222e-8) 0.78
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain 26788.723233401644 iter/sec (stddev: 0.00003092394557808863) 22617.677741632695 iter/sec (stddev: 0.000028080947620640477) 0.84
benchmarks/test_guard_validate.py::test_g11_validate_wide 15932.461319266726 iter/sec (stddev: 0.00002812467851069047) 13885.312777986277 iter/sec (stddev: 0.00002933321378046146) 0.87

This comment was automatically generated by workflow using github-action-benchmark.

@lesnik512
lesnik512 merged commit 0a78def into main Sep 27, 2026
10 checks passed
@lesnik512
lesnik512 deleted the refactor/536-collect-errors branch September 27, 2026 20:18
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.

Move the validation walk out of Container into dependency_graph

1 participant