fix!: wire NamedTuple, __new__-only classes, NewType and type aliases (#571) - #591
Merged
Merged
Conversation
There was a problem hiding this comment.
Benchmark
Details
| Benchmark suite | Current: 3a59da2 | Previous: fd1e0f4 | Ratio |
|---|---|---|---|
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type |
4724052.727771523 iter/sec (stddev: 1.6672884772236973e-8) |
2785475.74950628 iter/sec (stddev: 1.4364414722432417e-8) |
0.59 |
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry |
4814937.167576123 iter/sec (stddev: 1.2427847137729109e-8) |
3177510.2434177175 iter/sec (stddev: 1.3790078078729603e-8) |
0.66 |
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve |
19913.619514589802 iter/sec (stddev: 0.000051805072200300686) |
20283.841161522876 iter/sec (stddev: 0.00005290189514080043) |
1.02 |
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached |
16215.438899778686 iter/sec (stddev: 0.00014750013451195716) |
16408.469239894028 iter/sec (stddev: 0.00011783911748240829) |
1.01 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] |
610.7083376522121 iter/sec (stddev: 0.00008396524384613371) |
334.71483392209666 iter/sec (stddev: 0.00005097644447706185) |
0.55 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] |
566.5134028845748 iter/sec (stddev: 0.00007030649248953457) |
321.9356643442428 iter/sec (stddev: 0.00007526403499159544) |
0.57 |
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] |
456.4306894048939 iter/sec (stddev: 0.00022797773425180885) |
299.1314862237464 iter/sec (stddev: 0.00015135528795282046) |
0.66 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] |
1924.7169731749043 iter/sec (stddev: 0.00016526011182520665) |
1909.8701404471688 iter/sec (stddev: 0.00016488825446358974) |
0.99 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] |
1584.3671130749701 iter/sec (stddev: 0.0001563089025173073) |
1283.774447504292 iter/sec (stddev: 0.00020133764649106264) |
0.81 |
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] |
1030.300582061424 iter/sec (stddev: 0.0001742468122274287) |
1019.194134918245 iter/sec (stddev: 0.0001933798585599239) |
0.99 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[1] |
2023.998892142404 iter/sec (stddev: 0.00014894724581217364) |
1851.8014417012332 iter/sec (stddev: 0.00021655536210606418) |
0.91 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[2] |
1164.3173636868946 iter/sec (stddev: 0.00141403205240231) |
1159.6223666571705 iter/sec (stddev: 0.0011509626487236457) |
1.00 |
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[4] |
899.4696367282685 iter/sec (stddev: 0.00018004215200217988) |
836.5240451725125 iter/sec (stddev: 0.00018625872855068212) |
0.93 |
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container |
1098996.9591819819 iter/sec (stddev: 4.142723037160206e-8) |
929162.4870813187 iter/sec (stddev: 4.500367366727941e-8) |
0.85 |
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope |
1004133.0114842409 iter/sec (stddev: 3.065130172890026e-8) |
839247.9155338999 iter/sec (stddev: 3.051896837754992e-8) |
0.84 |
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch |
2454.1119221555155 iter/sec (stddev: 0.000012116565935991959) |
2368.9196838669773 iter/sec (stddev: 0.000051192486509853176) |
0.97 |
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control |
68432.14444749721 iter/sec (stddev: 0.0000014469874666476483) |
57986.44256206956 iter/sec (stddev: 0.000002010699586755405) |
0.85 |
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale |
49072.74269448379 iter/sec (stddev: 0.000001743380894833483) |
42505.97817077367 iter/sec (stddev: 0.0000019620757051777622) |
0.87 |
benchmarks/test_guard_lifecycle.py::test_g13b_teardown_at_scale_async_no_finalizers |
624.1824424049817 iter/sec (stddev: 0.00003779352751747016) |
507.9171923025423 iter/sec (stddev: 0.000038635885906492634) |
0.81 |
benchmarks/test_guard_resolve.py::test_g1_transient_resolve |
2687444.5541494004 iter/sec (stddev: 3.4472906267940917e-8) |
1957502.809752955 iter/sec (stddev: 6.993608542046132e-8) |
0.73 |
benchmarks/test_guard_resolve.py::test_g2_cached_resolve |
4529713.380001874 iter/sec (stddev: 1.4453993529718734e-8) |
2768727.1931305034 iter/sec (stddev: 2.5771136906708655e-8) |
0.61 |
benchmarks/test_guard_resolve.py::test_g3_deep_chain |
945998.1228497069 iter/sec (stddev: 5.0084619117323515e-8) |
674111.0207255966 iter/sec (stddev: 5.616840649357383e-8) |
0.71 |
benchmarks/test_guard_resolve.py::test_g4_wide_resolve |
548668.0944790678 iter/sec (stddev: 4.690930481205634e-7) |
452150.1582536596 iter/sec (stddev: 4.7140486270837895e-7) |
0.82 |
benchmarks/test_guard_resolve.py::test_g5_cross_scope |
2508935.573913691 iter/sec (stddev: 2.464170040456481e-8) |
1857756.1621631144 iter/sec (stddev: 2.2144501895465633e-8) |
0.74 |
benchmarks/test_guard_resolve.py::test_g9_context_resolve |
1755474.204768919 iter/sec (stddev: 1.630212247387252e-7) |
1353873.3979482 iter/sec (stddev: 1.7011337438267227e-7) |
0.77 |
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve |
920333.7480310067 iter/sec (stddev: 1.0834852314583847e-7) |
682268.9057128795 iter/sec (stddev: 4.921611630457953e-8) |
0.74 |
benchmarks/test_guard_resolve.py::test_g18_alias_hop |
4542242.148113701 iter/sec (stddev: 2.894784200121989e-8) |
2878165.4711447074 iter/sec (stddev: 1.2323641519737934e-8) |
0.63 |
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain |
24248.49292894262 iter/sec (stddev: 0.00002150227371703452) |
25353.007458676224 iter/sec (stddev: 0.000024898450622046718) |
1.05 |
benchmarks/test_guard_validate.py::test_g11_validate_wide |
15202.868214048249 iter/sec (stddev: 0.00002619249812960554) |
15835.792042389787 iter/sec (stddev: 0.000027956843376048667) |
1.04 |
This comment was automatically generated by workflow using github-action-benchmark.
lesnik512
force-pushed
the
fix/types-parser-forms
branch
from
October 5, 2026 08:50
7efff66 to
3a59da2
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 #571.
Summary
__new__or__init__thatinspect.signaturereads (first Python-level one in the MRO).NamedTuplesubclasses and classes that define only__new__wire their parameters, including string forward references in aNamedTuple.NewTypeobjects and PEP 695type X = ...aliases are bound types of their own. A parameter annotated with one resolves from the provider whosebound_typeis that object, and a creator returning one gets it as its inferred bound type.Factory(creator)with a return annotation that is a union of several types (-> A | B) emits aUserWarning. The audit suspicion reproduced: the provider gotbound_type=Noneand was silently skipped at registration.get_origin(...) is Annotatedreplaces the__metadata__probe, the always-truehasattr(creator, "__init__")and the unreachableelif non_none_membersbranch are gone, and the narrating comments are removed.bound_typenotes indocs/providers/factories.md, and a migration entry.Design decisions
NewTypeis matched as the object itself.type DepAlias = Depwith only aDepprovider still fails, now withArgument dep of type DepAlias cannot be resolvedinstead of the "no usable type annotation" message. Following__value__/__supertype__would make aUserIdparameter silently receive anyint.skip_creator_parsingand unresolvable-hints cases do (UserWarning,stacklevel=2). It does not raise, because a provider resolved only throughresolve_provideris valid. An explicitbound_type(includingNone) silences it.localns. The__new__thatNamedTuplegenerates has a private globals dict, so forward references failed without it. For ordinary classes the dict is the method's own globals, so nothing changes.!: a creator returning aNewTypeor alias now registers under it, which can collide with an explicitbound_type=provider for the same object (DuplicateProviderTypeError). The migration entry covers it.Factory(...)construction on 3.14, best of 7 x 20k: class 21.0 to 20.7 us, kw-only dataclass 18.8 to 18.7 us, function 10.1 to 9.7 us.from_typenow callsget_originonce instead of up to three times, which pays for the new checks.Open questions
typing.TypeAliasType("_UserIdAlias", int), which builds the same object atypestatement creates, rather thanexec. That way the test module parses on 3.11 and the 100% line gate holds there (the cases are skipped below 3.12). A realtypestatement was checked by hand with the audit repro on 3.14.__call__still falls back to__init__hints, as before. Not in scope.Test plan
__new__-only class and its subclass, NewType and alias parameters, return annotations and unregistered-form messages, union-return warningjust lint,just lint-cijust test-ciat 100% on 3.14, plus full runs with coverage on 3.11 and 3.12 (100%)mkdocs build --strictr14_new.pyandr6_types.pybehave as expected