refactor(exceptions): split the module into a package by error family - #484
Merged
Conversation
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 000018c | Previous: db82d66 | Ratio |
|---|---|---|---|
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type |
3986394.276875674 iter/sec (stddev: 9.226428653958042e-9) |
6342740.37843326 iter/sec (stddev: 9.202513810841618e-9) |
1.59 |
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry |
3969438.814235255 iter/sec (stddev: 1.0170923951089194e-8) |
6301507.73655055 iter/sec (stddev: 5.837541794200572e-9) |
1.59 |
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve |
15335.835653209153 iter/sec (stddev: 0.00019861890781159983) |
18519.215140319986 iter/sec (stddev: 0.00023833044863198944) |
1.21 |
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached |
14052.353791778007 iter/sec (stddev: 0.000046039640243974174) |
16950.669911934823 iter/sec (stddev: 0.00003839170685752548) |
1.21 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] |
564.0805935287412 iter/sec (stddev: 0.00005339801078745559) |
750.5255911150985 iter/sec (stddev: 0.00010588905849466288) |
1.33 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] |
488.6960676980392 iter/sec (stddev: 0.00018610505438532583) |
716.130547342282 iter/sec (stddev: 0.000034490050698847745) |
1.47 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] |
425.49793683877886 iter/sec (stddev: 0.00015066221618945393) |
628.2716149468757 iter/sec (stddev: 0.000029724030420819064) |
1.48 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] |
1692.5667461591281 iter/sec (stddev: 0.00020462147689898427) |
2018.0238454413284 iter/sec (stddev: 0.0001466318768720067) |
1.19 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] |
1374.1013162693375 iter/sec (stddev: 0.00017962626680038114) |
1608.3153333810044 iter/sec (stddev: 0.00016296098788864177) |
1.17 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] |
983.8653462210252 iter/sec (stddev: 0.00022490062966491276) |
1140.4239451893473 iter/sec (stddev: 0.00016340204334424594) |
1.16 |
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container |
712430.7354796415 iter/sec (stddev: 5.5084630197276516e-8) |
900655.0058566307 iter/sec (stddev: 4.8654175268626705e-8) |
1.26 |
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope |
686181.1908423759 iter/sec (stddev: 4.487490746408243e-8) |
860547.5952628809 iter/sec (stddev: 3.913517920349686e-8) |
1.25 |
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch |
2462.0281997604607 iter/sec (stddev: 0.00001260914087129064) |
3131.2894785403664 iter/sec (stddev: 0.000014595809200219622) |
1.27 |
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control |
61695.77495413011 iter/sec (stddev: 0.000002020824258095879) |
88227.56125982522 iter/sec (stddev: 0.0000011915065519641762) |
1.43 |
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale |
49561.605591185194 iter/sec (stddev: 0.0000018570590682547498) |
59697.52510922353 iter/sec (stddev: 0.0000016626388028007914) |
1.20 |
benchmarks/test_guard_resolve.py::test_g1_transient_resolve |
2533390.4022222282 iter/sec (stddev: 2.996034548731107e-8) |
3340385.7226674776 iter/sec (stddev: 2.510624853208012e-8) |
1.32 |
benchmarks/test_guard_resolve.py::test_g2_cached_resolve |
4210107.786759864 iter/sec (stddev: 9.292705959482407e-9) |
6314036.165535865 iter/sec (stddev: 3.827483457802025e-9) |
1.50 |
benchmarks/test_guard_resolve.py::test_g3_deep_chain |
857197.129967429 iter/sec (stddev: 4.067180299596836e-8) |
1133085.4463420268 iter/sec (stddev: 2.61991776066509e-7) |
1.32 |
benchmarks/test_guard_resolve.py::test_g4_wide_resolve |
505915.83832159935 iter/sec (stddev: 4.137000268924078e-7) |
639676.599981068 iter/sec (stddev: 2.962348952419589e-7) |
1.26 |
benchmarks/test_guard_resolve.py::test_g5_cross_scope |
1992410.6091549888 iter/sec (stddev: 2.780737749451298e-8) |
2686527.267253543 iter/sec (stddev: 2.9619305062133404e-8) |
1.35 |
benchmarks/test_guard_resolve.py::test_g9_context_resolve |
1065353.0721271296 iter/sec (stddev: 1.515289661701316e-7) |
1481506.2281223983 iter/sec (stddev: 1.4213959768046547e-7) |
1.39 |
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve |
827460.8094854786 iter/sec (stddev: 3.647355959212343e-8) |
1177838.2663165168 iter/sec (stddev: 4.5617617069912537e-8) |
1.42 |
benchmarks/test_guard_resolve.py::test_g18_alias_hop |
2800481.35791702 iter/sec (stddev: 1.7394036013799495e-8) |
4079403.134366965 iter/sec (stddev: 2.1759382457417547e-8) |
1.46 |
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain |
22776.810219049665 iter/sec (stddev: 0.00021489151358105248) |
24499.653178795208 iter/sec (stddev: 0.00027135942114880316) |
1.08 |
benchmarks/test_guard_validate.py::test_g11_validate_wide |
15528.769027195749 iter/sec (stddev: 0.000023687384482807807) |
18475.910332123764 iter/sec (stddev: 0.00001925423841397092) |
1.19 |
This comment was automatically generated by workflow using github-action-benchmark.
Each family gets its own submodule over a shared `base` and `rendering`; `__init__` re-exports every public name, so `from modern_di import exceptions` and `from modern_di.exceptions import X` are unchanged. The class bodies are a verbatim move: all 37 top-level blocks keep byte-identical ASTs and the 34 public names are the same set. `__module__` now names the family submodule, so it reads that way in tracebacks. Closes #473
lesnik512
force-pushed
the
split-exceptions-package
branch
from
September 12, 2026 11:13
6069929 to
000018c
Compare
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 #473.
modern_di/exceptions.pyhad grown to 759 lines across 33 classes, mixing container, resolution and registration errors with the warnings and the chain renderers. Each family now has its own submodule over a sharedbaseandrendering.lifecycle.pywarnings.pyrendering.pybase.py__init__.pycontainer.pyresolution.pyregistration.pyBackward compatibility
from modern_di import exceptionsandfrom modern_di.exceptions import Xare unchanged. The class bodies are a verbatim move: all 37 top-level blocks keep byte-identical ASTs, and the 34 public names are the same set.The one user-visible consequence is
__module__:ProviderNotRegisteredError.__module__is nowmodern_di.exceptions.resolution, which shows up in tracebacks andpytest.raisesoutput. Nothing in this repo asserts on it, and thefilterwarningsstring indocs/migration/to-3.x.mdresolves through the re-export. A downstream snapshot test on traceback text would see a diff. Pinning__module__back would hide the family from the traceback, so it is left honest.Tests
No new tests, per the issue's "existing test coverage remains sufficient" — the suite is the same 540 passed at 100% line coverage as before the split, and the slug census is the structural gate it always was.
tests/test_error_rendering.pyis the one test file that had to change: it reached forexceptions._render_chainand two sibling private helpers, which now live inrendering.Known deviations from the issue
registration.pylands at 225 lines, over the under-200 in user story 3. Cutting it would either split theRegistrationErrorhierarchy across two files or force a family-to-family import; the family stays whole instead.lifecycle.pyis the weakest name in the set: it holds the three concretes that subclassModernDIErrordirectly (two close-time finalizer errors plusGroupInstantiationError). The alternative was foldingGroupInstantiationErrorintoregistration.py, which reads naturally but puts a non-RegistrationErrorthere.Verification
ruff,ty, 540 passed, 100% line coverage.