Repository navigation
feat: reject provider subclasses at definition, name both duplicate providers, summarize finalizer errors, document the providers (#618) - #631
Merged
Conversation
…roviders, summarize finalizer errors, document the providers (#618)
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 63852d9 | Previous: 9fca05d | Ratio |
|---|---|---|---|
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type |
4594412.184010674 iter/sec (stddev: 1.9964050998746996e-8) |
3757940.2458935827 iter/sec (stddev: 1.9871470784386957e-8) |
0.82 |
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry |
4619484.727881559 iter/sec (stddev: 2.0789972197940685e-8) |
3772690.9914374542 iter/sec (stddev: 1.0168008591359035e-8) |
0.82 |
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve |
23769.971117835496 iter/sec (stddev: 0.00004143298893311027) |
22103.290349830208 iter/sec (stddev: 0.00004627586827240872) |
0.93 |
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached |
19196.277187909112 iter/sec (stddev: 0.0001266698100708045) |
17243.220046602797 iter/sec (stddev: 0.00012370532748143167) |
0.90 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] |
631.811480845798 iter/sec (stddev: 0.00008171350152958304) |
386.02246310233477 iter/sec (stddev: 0.00008801829546247881) |
0.61 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] |
609.805180590712 iter/sec (stddev: 0.00006021891277541407) |
424.92173710239894 iter/sec (stddev: 0.0001408626172301536) |
0.70 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] |
575.2256746545758 iter/sec (stddev: 0.00007367620559968257) |
389.9142863525594 iter/sec (stddev: 0.00012773187148944017) |
0.68 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] |
13670.817202675702 iter/sec (stddev: 0.000008618731910652419) |
12894.870484989313 iter/sec (stddev: 0.000014094940280855665) |
0.94 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] |
6433.65436016382 iter/sec (stddev: 0.00002399136611744103) |
6245.309512340506 iter/sec (stddev: 0.00005076579950550514) |
0.97 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] |
3269.999617405953 iter/sec (stddev: 0.00004648281020558787) |
3325.602416251845 iter/sec (stddev: 0.000045069836303194324) |
1.02 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[1] |
10537.838083518829 iter/sec (stddev: 0.000011248528052703273) |
8974.439226584482 iter/sec (stddev: 0.000010548015828080406) |
0.85 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[2] |
4371.7414132522645 iter/sec (stddev: 0.000022152727287610355) |
3863.139277112657 iter/sec (stddev: 0.00002147797550262497) |
0.88 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[4] |
1944.6191900853214 iter/sec (stddev: 0.00005502692811861615) |
1861.32230570072 iter/sec (stddev: 0.00004399656028164962) |
0.96 |
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[1] |
30453.158220655034 iter/sec (stddev: 0.0000047657974525078986) |
39717.21344135618 iter/sec (stddev: 0.000005937724465444655) |
1.30 |
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[2] |
12031.26444382543 iter/sec (stddev: 0.00001928212345602406) |
12926.652236162534 iter/sec (stddev: 0.000016035591671154977) |
1.07 |
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[4] |
5534.749764981986 iter/sec (stddev: 0.00004070953878807983) |
5633.227857391772 iter/sec (stddev: 0.000035472654583660356) |
1.02 |
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container |
1794560.3466207052 iter/sec (stddev: 5.498757978636024e-8) |
1599934.6586693635 iter/sec (stddev: 3.5092442851353725e-8) |
0.89 |
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope |
1945468.7066985124 iter/sec (stddev: 5.955511754930611e-8) |
1677839.6103617244 iter/sec (stddev: 2.0099612510064583e-8) |
0.86 |
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch |
3006.6190893370067 iter/sec (stddev: 0.00004960438085672508) |
2985.18003500368 iter/sec (stddev: 0.00001349872220770278) |
0.99 |
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control |
71378.2709451807 iter/sec (stddev: 0.0000013613548308297734) |
57811.65437798101 iter/sec (stddev: 0.0000023636264035798613) |
0.81 |
benchmarks/test_guard_lifecycle.py::test_g7b_request_cycle_sync |
408275.4660701501 iter/sec (stddev: 1.0429605637520283e-7) |
387336.70804320497 iter/sec (stddev: 1.1612783600768163e-7) |
0.95 |
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale |
62918.14291435815 iter/sec (stddev: 0.0000017306462897363167) |
56429.917854609484 iter/sec (stddev: 0.000001909351631550383) |
0.90 |
benchmarks/test_guard_lifecycle.py::test_g13b_teardown_at_scale_async_no_finalizers |
599.4359759215686 iter/sec (stddev: 0.001133913367716592) |
518.2335247250417 iter/sec (stddev: 0.001294428485352388) |
0.86 |
benchmarks/test_guard_resolve.py::test_g1_transient_resolve |
2669292.8949794346 iter/sec (stddev: 2.637196736785289e-8) |
2142403.7566680824 iter/sec (stddev: 2.84876267436551e-8) |
0.80 |
benchmarks/test_guard_resolve.py::test_g2_cached_resolve |
4849255.791989697 iter/sec (stddev: 1.970425746450663e-8) |
3391886.6816813163 iter/sec (stddev: 2.4182600235528645e-8) |
0.70 |
benchmarks/test_guard_resolve.py::test_g3_deep_chain |
891212.0807359907 iter/sec (stddev: 5.453211822120974e-8) |
683099.4434992333 iter/sec (stddev: 7.622996206571738e-8) |
0.77 |
benchmarks/test_guard_resolve.py::test_g4_wide_resolve |
511639.6877771057 iter/sec (stddev: 4.539774422504683e-7) |
425099.6428249923 iter/sec (stddev: 3.902063625365541e-7) |
0.83 |
benchmarks/test_guard_resolve.py::test_g5_cross_scope |
2367801.7789955237 iter/sec (stddev: 2.755111064861269e-8) |
1953645.5587753574 iter/sec (stddev: 4.0531940972630803e-8) |
0.83 |
benchmarks/test_guard_resolve.py::test_g9_context_resolve |
1748886.9427710746 iter/sec (stddev: 1.5587647694664483e-7) |
1360392.5385450525 iter/sec (stddev: 1.7458080708057942e-7) |
0.78 |
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve |
903808.6405718289 iter/sec (stddev: 4.148867316346122e-8) |
715184.2155420394 iter/sec (stddev: 8.360877431979395e-8) |
0.79 |
benchmarks/test_guard_resolve.py::test_g18_alias_hop |
4752568.906068427 iter/sec (stddev: 1.6808273071045618e-8) |
3396212.855866297 iter/sec (stddev: 3.6069980524154594e-8) |
0.71 |
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain |
36060.35609320815 iter/sec (stddev: 0.000019079801164790778) |
36792.48962257669 iter/sec (stddev: 0.000017542859660054885) |
1.02 |
benchmarks/test_guard_validate.py::test_g11_validate_wide |
21366.950669043326 iter/sec (stddev: 0.00002887897872424291) |
20992.70455232314 iter/sec (stddev: 0.00002802513785042281) |
0.98 |
This comment was automatically generated by workflow using github-action-benchmark.
This was referenced Oct 10, 2026
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.
Part of #618 (items 1, 2, 3, 4). Item 6 is #630; the rest was dropped (see the issue comments).
Summary
AbstractProvider.__init_subclass__raisesTypeErrorfor a subclass declared outside modern-di. Since refactor: dispatch the dependency graph by provider type, make the provider step a free function (#617) #629 the graph dispatches by exact type, so aFactorysubclass got no validation at all and then failed at its first resolve with a bare "no compiled resolver"TypeError.DuplicateProviderTypeErrornames both providers. New.first_providerand.second_provider, in registration order, and one line per provider in the message. The hint "pass dependencies via kwargs", which does not fix a duplicate, is gone:FinalizerErroris summarized likeValidationFailedError:Container.close_sync() found 2 finalizer error(s): ConnectionError (1), ValueError (1). Each user finalizer exception gets a note,raised by the finalizer of a cached Database, which shows in the traceback.Factory,Alias,Group,AbstractProvider,CacheSettings,Group.get_providersandGroup.get_named_providers, worded to matchdocs/providers/.Design decisions
TypeError, the type the docs already promised, rather than adding aModernDIErrorsubclass that would need its own troubleshooting page. The check looks at the subclass's module, so modern-di's own provider types still subclassAbstractProvider. No integration, template or chat-app subclasses a provider.DuplicateProviderTypeErroritself keeps working. Like the other errors that hold providers, they degrade to their repr under pickle protocols 0 and 1.exceptions/, which owns every message.Release notes
Two changes are visible to 4.0.0 users and belong in the next release notes:
FinalizerError's message text changed. Code that matched onErrors during sync cleanup: [...]must update.Test plan
FactoryandAbstractProvider), duplicate providers and message in both registration paths, finalizer notes on sync and async close, the newFinalizerErrortextjust lint-ci, full suite at 100% line and branch coverage,just test-raceDuplicateProviderTypeErrorwith providers