Repository navigation
docs: rework the errors catalog and the scope, container and lifecycle troubleshooting pages - #664
Merged
Merged
Conversation
…e troubleshooting pages
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 94eb244 | Previous: 395e8fb | Ratio |
|---|---|---|---|
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type |
5791007.966065862 iter/sec (stddev: 1.8643690258731708e-8) |
6139935.138982263 iter/sec (stddev: 1.8605923146541302e-8) |
1.06 |
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry |
5904501.42064673 iter/sec (stddev: 1.7013081044220067e-8) |
6205832.315667191 iter/sec (stddev: 1.3805592208773412e-8) |
1.05 |
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve |
26963.305164746904 iter/sec (stddev: 0.00003579260576571272) |
32024.886577255867 iter/sec (stddev: 0.000030238944431934) |
1.19 |
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached |
21950.16802884705 iter/sec (stddev: 0.00013897720713502474) |
24960.133332489408 iter/sec (stddev: 0.00011886986138363566) |
1.14 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] |
749.3157421922463 iter/sec (stddev: 0.00007192406478698934) |
775.0388204206938 iter/sec (stddev: 0.00004473754687217169) |
1.03 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] |
695.4277934590127 iter/sec (stddev: 0.0001044457032864375) |
764.2436132277375 iter/sec (stddev: 0.0001144571715558005) |
1.10 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] |
629.4568306994992 iter/sec (stddev: 0.00009424951577115076) |
680.0345534095648 iter/sec (stddev: 0.0000803400475442327) |
1.08 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] |
10446.409917088471 iter/sec (stddev: 0.000011783454554986201) |
10419.935559673875 iter/sec (stddev: 0.00001230746171334532) |
1.00 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] |
7872.2248685374625 iter/sec (stddev: 0.000015077355303843093) |
5634.100392630293 iter/sec (stddev: 0.00003435893765767916) |
0.72 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] |
2971.418666696458 iter/sec (stddev: 0.00006208300262172865) |
2968.9836953557647 iter/sec (stddev: 0.000061919224501018) |
1.00 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[1] |
12289.087259800075 iter/sec (stddev: 0.000018729178871096452) |
12389.480670083722 iter/sec (stddev: 0.000019500905757513246) |
1.01 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[2] |
5077.343598138035 iter/sec (stddev: 0.000014520016425001374) |
4843.535831204409 iter/sec (stddev: 0.00003981695650002605) |
0.95 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[4] |
1838.032682550074 iter/sec (stddev: 0.0001668885758254382) |
1868.0290700812566 iter/sec (stddev: 0.00007765838735564648) |
1.02 |
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[1] |
18871.218089798083 iter/sec (stddev: 0.00000439590192695075) |
24896.9783783031 iter/sec (stddev: 0.000017881784016521047) |
1.32 |
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[2] |
12781.43113684052 iter/sec (stddev: 0.0000075203522892032244) |
11645.85197075752 iter/sec (stddev: 0.000015482573556939863) |
0.91 |
benchmarks/test_guard_concurrency.py::test_g15c_worker_pool_floor_control[4] |
5095.359872308934 iter/sec (stddev: 0.00004830947915217749) |
5052.235696391264 iter/sec (stddev: 0.000048475453192008314) |
0.99 |
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container |
2424069.3603774505 iter/sec (stddev: 2.733076405774691e-8) |
2335541.2567186337 iter/sec (stddev: 3.860763352243666e-8) |
0.96 |
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope |
2465853.173488663 iter/sec (stddev: 4.603663361447113e-8) |
2505907.6773532387 iter/sec (stddev: 3.905850495221895e-8) |
1.02 |
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch |
3634.938704985746 iter/sec (stddev: 0.000014816109673592282) |
3317.2697581338502 iter/sec (stddev: 0.000052891745120707064) |
0.91 |
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control |
87589.81205554071 iter/sec (stddev: 0.0000012952220151239049) |
83100.58991551855 iter/sec (stddev: 0.0000014527703096612033) |
0.95 |
benchmarks/test_guard_lifecycle.py::test_g7b_request_cycle_sync |
542774.6891790937 iter/sec (stddev: 7.268976616449304e-8) |
468518.9908558271 iter/sec (stddev: 8.515899938405845e-8) |
0.86 |
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale |
77107.5785474624 iter/sec (stddev: 0.0000014563390785576194) |
78785.45603292529 iter/sec (stddev: 0.0000017671089125152717) |
1.02 |
benchmarks/test_guard_lifecycle.py::test_g13b_teardown_at_scale_async_no_finalizers |
699.017103213025 iter/sec (stddev: 0.0011576839780805014) |
586.9668417253587 iter/sec (stddev: 0.0013708543619692236) |
0.84 |
benchmarks/test_guard_resolve.py::test_g1_transient_resolve |
3107493.884649706 iter/sec (stddev: 2.3370309230035162e-8) |
3091773.339921797 iter/sec (stddev: 3.1905368666696455e-8) |
0.99 |
benchmarks/test_guard_resolve.py::test_g2_cached_resolve |
5500852.632156926 iter/sec (stddev: 1.532794690592437e-8) |
5585002.481125255 iter/sec (stddev: 1.7326975696337195e-8) |
1.02 |
benchmarks/test_guard_resolve.py::test_g3_deep_chain |
1027810.4700035306 iter/sec (stddev: 5.5623204055786324e-8) |
1053634.7223852123 iter/sec (stddev: 4.376268176758002e-8) |
1.03 |
benchmarks/test_guard_resolve.py::test_g4_wide_resolve |
546661.1209718777 iter/sec (stddev: 3.7076261829182327e-7) |
602475.4027370019 iter/sec (stddev: 3.669391702377282e-7) |
1.10 |
benchmarks/test_guard_resolve.py::test_g5_cross_scope |
2638970.495376011 iter/sec (stddev: 4.40573711860842e-8) |
2722743.1964451196 iter/sec (stddev: 2.2608711961763022e-8) |
1.03 |
benchmarks/test_guard_resolve.py::test_g9_context_resolve |
2028689.6272748925 iter/sec (stddev: 1.5075277710791751e-7) |
2095884.4060996436 iter/sec (stddev: 1.4539795764318154e-7) |
1.03 |
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve |
1026564.143709598 iter/sec (stddev: 4.653118499678925e-8) |
1056924.0255533508 iter/sec (stddev: 4.539064934432262e-8) |
1.03 |
benchmarks/test_guard_resolve.py::test_g18_alias_hop |
5375044.827865133 iter/sec (stddev: 1.4534574274358616e-8) |
5564689.374851157 iter/sec (stddev: 1.595292015837515e-8) |
1.04 |
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain |
42495.4224286077 iter/sec (stddev: 0.00001626905220012278) |
23951.926949647954 iter/sec (stddev: 0.000031960404140896095) |
0.56 |
benchmarks/test_guard_validate.py::test_g11_validate_wide |
25412.20330255422 iter/sec (stddev: 0.000023258162801566658) |
21724.253571453744 iter/sec (stddev: 0.00003130808206721572) |
0.85 |
This comment was automatically generated by workflow using github-action-benchmark.
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.
Reworks
docs/providers/errors-and-exceptions.mdand twelve troubleshooting pages: InvalidChildScopeError, MaxScopeReachedError, ScopeNotInitializedError, ScopeSkippedError, InvalidScopeTypeError, ContainerClosedError, ValidationFailedError, scope-chain (InvalidScopeDependencyError), ScopeEnumMismatchError, FinalizerError, AsyncFinalizerInSyncCloseError and ChildContainerRegistrationError. I checked every behavioural claim by running a script against this checkout. Every quoted error block was regenerated from a smallmyapp/providers.pymodule, so themodule:linelocations match what a real run prints.What was wrong
Container(...)raises it. Onlybuild_child_container(scope=...)does (container.py; a root atScope.REQUESTbuilds fine).resolve()andresolve_provider()always draw it, even for a direct resolve. The page also said "see the scope dependency rule below", and nothing below it said that.code.co_firstlinenoof the class or function), not at theFactory(...)line.validate()and from a resolve. Only the tree lines match. The headline and thecaused byline differ.See:line. docs: quote errors the way Python prints them on troubleshooting pages #648 converted the other pages to that form.ShallowandDeepwithout locations. Real output always has one.ValidationFailedError'sstr()is one line. It is two: the summary, then theSee:line. Its security note saidCreatorCallErrorembeds the wrapped exception's text, as if creator exceptions were wrapped. Only argument-bindingTypeErrors are wrapped, and exceptions from a creator body propagate unchanged.<!-- raises -->block put the Works code after the raising line. Sybil stops at the first raise, so the Works code never ran. Each pair is now two blocks, and every Works block runs.What was added
.allowed_scopesand "Possible scopes are" list only the parent's own enum, so aSTEPparent shows[]even though a higher-valued member of another enum is accepted.scope=. Using one fullIntEnumin place ofScopelets every level derive its scope, but then every provider needs that enum's members. AScope.APPprovider raisesScopeSkippedErrorin anAppScope.APPcontainer.APPeven when you resolve from aREQUESTchild, and building the deeper container does not fix it.int,str, plainEnum,IntFlag), and converting a config value withScope(3)orScope["REQUEST"].FinalizerError.except*re-raises the remainder as aFinalizerError.close_sync()reporting it again, a reopen returning the kept instance, and a link tolifecycle.md#async-finalizers-and-close_sync.add_providersis not coordinated with concurrent resolves). This replaces the advice against walkingparent_container, which gave no reason.Structure
textfence, the attributes), Cause, Fix, See also. The two "Escape hatches" sections and scope-chain's "How to detect" section were folded into Fix.# InvalidScopeDependencyError, asdocs/agents/docs-style.mdrequires. The file name and slug did not change.dependency_pathparagraph, pickling, and a rewritten security note. Cause and fix text now lives only on the troubleshooting pages. The dropped details already exist elsewhere: the threading caveat incircular-dependency.md, the post-add_providersvalidate advice inlifecycle.md#validation, and the closed-container rules incontainer-closed-error.md.Anchors kept
scope-chain.md#when-the-dependency-is-reached-through-an-alias, linked fromproviders/alias.md.tests/test_docs_slug_census.pyand by theSee:URLs.## Hierarchy,## Pickling and copyingand## Security noteheadings on errors-and-exceptions.md. Nothing links to an anchor there, but they stay anyway.Checks
just test-docs -q -p no:cacheprovider --no-cov: 167 passed, 21 skipped (the skips are pages outside this batch). All 85 examples in the batch pages pass.tests/test_docs_slug_census.py: 3 passed.just docs-build: no WARNING lines. Anchor validation is on.just lint-ci: passes.lychee --offlineoverdocsandREADME.md: 0 errors.Library bugs found (not fixed here)
InvalidChildScopeError lists no allowed scopes even when another enum's higher member would be accepted.
_scope_algebra.deeper_memberslooks only attype(parent_scope), whilebuild_child_containeraccepts anyIntEnumwith a higher value.The ScopeSkippedError message contradicts itself across enums. A
Scope.APPprovider resolved in a root built atAppScope.APP(a custom enum withAPP = 1) printsNo APP-scope container exists in this chain, which starts at APP. Build the root container at scope APP.The message uses.nameonly, so the two scopes look the same. The page now explains this case.An Alias's repr reports
scope=APPwhen its source is REQUEST-scoped, so.dependency_providerlooks wrong on anInvalidScopeDependencyErrorreached through an alias:This only affects the repr. The pages do not show it.
Out-of-batch changes needed
mkdocs.ymlnav "Scope chain violation",docs/providers/alias.md:115"[Troubleshooting: Scope chain]" anddocs/recipes/good-and-bad-practices.md:36"[Scope chain violation]" should becomeInvalidScopeDependencyErrorto match the new H1.docs/troubleshooting/creator-call-error.mdshould pick up a fact this PR cut from the catalog: aResolutionErrorraised bycontainer.resolve()inside a creator body gains the creator's step in itsdependency_path.docs/troubleshooting/context-not-set.mdcould linkmigration/to-4.x.md#a-missing-context-value-for-a-required-parameter-raises-contextvaluenotseterror, which the catalog no longer links. The catalog also no longer linksmigration/to-3.x.md.docs/providers/lifecycle.mdshould be checked against the new FinalizerError and AsyncFinalizerInSyncCloseError facts: a failed finalizer is not retried, and a reopen returns the kept async instance.docs/troubleshooting/unsupported-creator-parameter-error.mdstill has an "Escape hatches" section.