Skip to content

Relax future() and future_safe() argument types from Coroutine to Awaitable - #2480

Merged
sobolevn merged 1 commit into
dry-python:masterfrom
syzayd:issue-2404
Aug 4, 2026
Merged

Relax future() and future_safe() argument types from Coroutine to Awaitable#2480
sobolevn merged 1 commit into
dry-python:masterfrom
syzayd:issue-2404

Conversation

@syzayd

@syzayd syzayd commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

I have made things!

Checklist

  • I have double checked that there are no unrelated changes in this pull request (old patches, accidental config files, etc)
  • I have created at least one test case for the changes I have made
  • I have updated the documentation for the changes I have made
  • I have added my changes to the CHANGELOG.md

Related issues

Closes #2404

What changed

future() and future_safe() typed their wrapped function argument as returning Coroutine, which is stricter than needed. A callable typed as Callable[..., Awaitable[T]] (for example an async def that awaits and returns some other awaitable, rather than one whose own return is annotated Coroutine) failed type checking even though the decorators only ever await the result at runtime.

This widens the parameter type on both decorators (and the internal _future_safe_factory helper) to Awaitable, and removes the now unused _SecondType TypeVar that only existed to parameterize Coroutine.

Test plan

  • Added a typesafety case to test_future_decorator.yml and test_future_safe_decorator.yml covering a Callable[[int], Awaitable[int]] argument that is not itself typed as Coroutine.
  • pytest typesafety/test_future (53 passed)
  • pytest tests -k future (133 passed)
  • mypy returns (no issues)
  • ruff check returns/future.py typesafety/test_future (all checks passed)

Both decorators typed their wrapped function argument as returning
Coroutine, which rejects any callable typed as returning a plain
Awaitable (e.g. an async def that awaits and returns another
awaitable, rather than being annotated as returning a Coroutine
itself), even though the runtime behavior only relies on awaiting
the result. Widen the parameter type to Awaitable and drop the now
unused _SecondType TypeVar.

Fixes dry-python#2404
@codspeed-hq

codspeed-hq Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 22 untouched benchmarks


Comparing syzayd:issue-2404 (e373e9e) with master (21fc742)

Open in CodSpeed

@sobolevn
sobolevn merged commit 911a863 into dry-python:master Aug 4, 2026
24 checks passed
@codecov

codecov Bot commented Aug 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (82ef3ef) to head (e373e9e).
⚠️ Report is 579 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##            master     #2480    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files           80        81     +1     
  Lines         2485      2564    +79     
  Branches       437        44   -393     
==========================================
+ Hits          2485      2564    +79     

☔ 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

future() and future_safe() overly restrictive type signatures

2 participants