Skip to content

refactor(factory): name the parsed creator and the cache coercion - #545

Merged
lesnik512 merged 2 commits into
mainfrom
refactor/537-parsed-creator
Sep 27, 2026
Merged

lesnik512 merged 2 commits into
mainfrom
refactor/537-parsed-creator

Conversation

@lesnik512

@lesnik512 lesnik512 commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

Closes #537.

Two names for two things Factory.__init__ carried by position or by ladder.

ParsedCreator

parse_creator returns a frozen, slotted dataclass with return_type, params and has_positional_only_gap. The docstring paragraph that explained the third tuple element now sits on the class. Factory.__init__ reads the fields by name, and the skip_creator_parsing branch builds an empty ParsedCreator so the assignments after the branch are one path instead of two sets of locals. The tests stop unpacking _ret, params, _gap.

parse_creator is not exported from modern_di, so its return type is not public API.

CacheSettings.coerce

@staticmethod
def coerce(cache: "bool | CacheSettings[types.T] | None") -> "CacheSettings[types.T] | None":
    if cache is True:
        return CacheSettings()
    return cache or None

A staticmethod over the invariant types.T rather than a classmethod over the class's covariant T_co: ty 0.0.84 rejects a covariant variable in a parameter position, which the first CI run caught.

Replaces the three-branch ladder and its two comments at the top of Factory.__init__. Two new tests pin the mapping (True to defaults, False and None to None, an instance returned as itself).

Behaviour

None at resolve time. One extra object per Factory at construction, which is import time for a Group body.

Checks

  • Full suite with coverage: 548 passed, 8 skipped, 100% line coverage.
  • ruff format, ruff check, eof-fixer and ty check clean with the locked tool versions.

parse_creator returns a ParsedCreator dataclass instead of a 3-tuple, so
Factory and the tests read return_type, params and has_positional_only_gap
by name. CacheSettings.coerce replaces the three-branch ladder that turned
the cache argument into settings or None. Closes #537.

@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: abc6954 Previous: 0a78def Ratio
benchmarks/test_guard_by_type.py::test_g16_resolve_by_type 3471998.7122578854 iter/sec (stddev: 1.7036046574653683e-8) 4968591.5454160115 iter/sec (stddev: 8.41396506374104e-9) 1.43
benchmarks/test_guard_by_type.py::test_g17_resolve_by_type_large_registry 3487433.608401099 iter/sec (stddev: 1.1046607004951574e-8) 4996027.408800345 iter/sec (stddev: 1.4695694448414382e-8) 1.43
benchmarks/test_guard_cold.py::test_g8_cold_first_resolve 14624.276884190329 iter/sec (stddev: 0.000053495968236821545) 22539.3628633738 iter/sec (stddev: 0.00004662239001453159) 1.54
benchmarks/test_guard_cold.py::test_g8b_cold_first_resolve_cached 12739.26178959642 iter/sec (stddev: 0.00012195389633674608) 19191.6790496122 iter/sec (stddev: 0.0001426656267049193) 1.51
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[1] 374.1639969967372 iter/sec (stddev: 0.00004720803635724062) 630.6994413228471 iter/sec (stddev: 0.000033762402906412355) 1.69
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[2] 354.37649069828245 iter/sec (stddev: 0.000040725568567036396) 588.7689052241964 iter/sec (stddev: 0.0001210559570636086) 1.66
benchmarks/test_guard_concurrency.py::test_g14_concurrent_cached_hit[4] 329.0192872749762 iter/sec (stddev: 0.00004688377151189849) 537.4440834218 iter/sec (stddev: 0.000023129769302699955) 1.63
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[1] 1615.6028242953948 iter/sec (stddev: 0.00019030577561535814) 2310.1930027653325 iter/sec (stddev: 0.00013228844954993188) 1.43
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[2] 1278.324365602773 iter/sec (stddev: 0.00020869889101231932) 1813.3266361134993 iter/sec (stddev: 0.00015685191293119628) 1.42
benchmarks/test_guard_concurrency.py::test_g15_concurrent_first_resolve[4] 934.2591280741457 iter/sec (stddev: 0.00021793865330889902) 1259.7266512835552 iter/sec (stddev: 0.00019618441960171664) 1.35
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[1] 1359.737131992806 iter/sec (stddev: 0.0011082844760762311) 1659.5303634170655 iter/sec (stddev: 0.0016704704107851974) 1.22
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[2] 1169.5847953512155 iter/sec (stddev: 0.0002133960236955586) 1606.1059651690402 iter/sec (stddev: 0.00018955869305135043) 1.37
benchmarks/test_guard_concurrency.py::test_g15b_concurrent_first_resolve_sibling_children[4] 744.5961723917271 iter/sec (stddev: 0.00023294672175019573) 1061.1266799026703 iter/sec (stddev: 0.00018060320885434483) 1.43
benchmarks/test_guard_lifecycle.py::test_g6_build_child_container 616922.6605220381 iter/sec (stddev: 3.715201003928183e-7) 1126700.927576428 iter/sec (stddev: 4.1378652249439554e-8) 1.83
benchmarks/test_guard_lifecycle.py::test_g6b_build_child_container_auto_scope 734411.3929540286 iter/sec (stddev: 6.08801952519743e-8) 1036355.9899417069 iter/sec (stddev: 4.3060571714441033e-8) 1.41
benchmarks/test_guard_lifecycle.py::test_g7_request_lifecycle_batch 2361.049484052426 iter/sec (stddev: 0.00004888846724468825) 3271.4591629564534 iter/sec (stddev: 0.000009229771135313224) 1.39
benchmarks/test_guard_lifecycle.py::test_g7c_event_loop_floor_control 57596.78863108535 iter/sec (stddev: 0.0000023023190759449053) 73054.24112724997 iter/sec (stddev: 0.0000013365268275422494) 1.27
benchmarks/test_guard_lifecycle.py::test_g13_teardown_at_scale 44583.38100972135 iter/sec (stddev: 0.0000021225133640635065) 61634.29912022505 iter/sec (stddev: 0.0000021808385227602092) 1.38
benchmarks/test_guard_lifecycle.py::test_g13b_teardown_at_scale_async_no_finalizers 563.4749020753834 iter/sec (stddev: 0.00003065388973762685) 802.014201917468 iter/sec (stddev: 0.0001425391488858678) 1.42
benchmarks/test_guard_resolve.py::test_g1_transient_resolve 2052739.074909094 iter/sec (stddev: 3.523406532503467e-8) 3008481.284814736 iter/sec (stddev: 2.920374869649033e-8) 1.47
benchmarks/test_guard_resolve.py::test_g2_cached_resolve 3369558.5588639006 iter/sec (stddev: 1.4341991136431386e-8) 4786923.732775733 iter/sec (stddev: 1.5389072634008654e-8) 1.42
benchmarks/test_guard_resolve.py::test_g3_deep_chain 715514.4570475413 iter/sec (stddev: 4.65692090648329e-8) 1056026.9557198184 iter/sec (stddev: 3.7584032949087816e-8) 1.48
benchmarks/test_guard_resolve.py::test_g4_wide_resolve 472012.68071708444 iter/sec (stddev: 3.123355397671735e-7) 626482.7279945917 iter/sec (stddev: 3.1358607686122413e-7) 1.33
benchmarks/test_guard_resolve.py::test_g5_cross_scope 1858708.0752233567 iter/sec (stddev: 3.069798280846045e-8) 2759412.545912089 iter/sec (stddev: 3.202354432896829e-8) 1.48
benchmarks/test_guard_resolve.py::test_g9_context_resolve 1053365.6084545543 iter/sec (stddev: 1.4624605878624907e-7) 1489595.639952772 iter/sec (stddev: 1.6483873603149457e-7) 1.41
benchmarks/test_guard_resolve.py::test_g12_override_active_resolve 719698.0233514238 iter/sec (stddev: 6.074731741991982e-8) 1057983.080100332 iter/sec (stddev: 4.047735683117108e-8) 1.47
benchmarks/test_guard_resolve.py::test_g18_alias_hop 2117560.612541916 iter/sec (stddev: 1.320455111131115e-8) 3365320.7066519074 iter/sec (stddev: 1.6545091511550612e-8) 1.59
benchmarks/test_guard_validate.py::test_g10_validate_deep_chain 23025.9282617151 iter/sec (stddev: 0.00002276332321588352) 33726.56294767888 iter/sec (stddev: 0.000020314821428495196) 1.46
benchmarks/test_guard_validate.py::test_g11_validate_wide 14026.163732545592 iter/sec (stddev: 0.000027786077301247497) 20075.791466350274 iter/sec (stddev: 0.000020561362561656457) 1.43

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

…pe variable

ty 0.0.84 rejects the covariant class variable in a parameter position.
@lesnik512
lesnik512 merged commit 2fa9349 into main Sep 27, 2026
10 checks passed
@lesnik512
lesnik512 deleted the refactor/537-parsed-creator branch September 27, 2026 20:23
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.

Factory construction: name the parsed-creator result and the cache coercion

1 participant