Skip to content

Expose combined __annotations__ on composed functions (#496) - #634

Merged
eriknw merged 4 commits into
pytoolz:masterfrom
az51826295-sys:compose-annotations
Sep 17, 2026
Merged

eriknw merged 4 commits into
pytoolz:masterfrom
az51826295-sys:compose-annotations

Conversation

@az51826295-sys

Copy link
Copy Markdown
Contributor

Compose already synthesizes __signature__ (parameters of the first function applied, return annotation of the last), but it had no __annotations__, so typing.get_type_hints() and tools that read __annotations__ directly saw nothing on a composed callable.

This adds an instance property that builds the same view:

def f(x: int) -> str: ...
def g(y: str) -> float: ...
compose(g, f).__annotations__          # {'x': int, 'return': float}
typing.get_type_hints(compose(g, f))   # {'x': int, 'return': float}

Functions without annotations contribute nothing; callables with no __annotations__ at all (e.g. str, arbitrary objects) are handled.

Scope: this is a small runtime step toward the static typing discussed in #496 — the composed callable now reports Callable[[A], C] for compose(g, f) with f: A -> B, g: B -> C. It does not add stubs or annotate the library itself; happy to split or drop it if you'd rather approach #496 differently.

Tests: test_compose_annotations (combined view, unannotated pieces, get_type_hints, consistency with __signature__). Full suite incl. doctests passes locally (pytest --doctest-modules toolz/; the only failure is test_has_version, which needs an installed distribution and fails identically on master in my environment).

Authored with the help of an AI agent (Rookery Alpha), human-reviewed.

az51826295-sys and others added 3 commits August 22, 2026 14:13
Compose already synthesizes __signature__ from the first-applied
function's parameters and the last-applied function's return
annotation, but it had no __annotations__, so typing.get_type_hints()
and tools that read __annotations__ directly saw nothing on a composed
callable. Add an instance property that builds the same view:
parameter annotations from the first function applied, the return
annotation from the last. Functions without annotations contribute
nothing, as do callables that have no __annotations__ at all.

This is a small runtime step toward the static typing discussed in
pytoolz#496 (the composed callable now reports Callable[[A], C] for
compose(g, f) with f: A -> B, g: B -> C); it does not add stubs or
annotate the library itself.

Adds test_compose_annotations covering the combined view, unannotated
pieces, get_type_hints, and consistency with __signature__.

Co-Authored-By: Rookery Alpha (AI agent, human-reviewed)
Build the combined annotations from inspect.signature so partial, curry,
bound methods, classes, and nested compositions are handled and the result
always agrees with signature.  Expose them through a dict-subclass
descriptor so Compose itself keeps an empty dict annotations, which
typing.get_type_hints and inspect.get_annotations require before 3.14.

On Python 3.14+, add annotate so functools.wraps copies the
annotations and the FORWARDREF and STRING formats work: NameError from
eager signature properties (e.g. curry) is tolerated under those
formats, STRING output is stringified, and unsupported formats raise
NotImplementedError.
@codecov

codecov Bot commented Sep 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (80ddcb3) to head (e017166).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #634   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           13        13           
  Lines         1178      1226   +48     
=========================================
+ Hits          1178      1226   +48     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@eriknw
eriknw merged commit a1e25cb into pytoolz:master Sep 17, 2026
18 checks passed
@eriknw

eriknw commented Sep 17, 2026

Copy link
Copy Markdown
Member

Thanks @az51826295-sys. This is in. I made a few changes that you may want to review

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.

2 participants