Visitar URL original
[ty] Pass the generic context through the decorator by dhruvmanila · Pull Request #22544 · astral-sh/ruff · GitHub
Skip to content

[ty] Pass the generic context through the decorator - #22544

Merged
dhruvmanila merged 5 commits into
mainfrom
dhruv/paramspec-decorator
Jan 23, 2026
Merged

dhruvmanila merged 5 commits into
mainfrom
dhruv/paramspec-decorator

Conversation

@dhruvmanila

@dhruvmanila dhruvmanila commented Jan 13, 2026 •

Copy link
Copy Markdown
Member

Summary

fixes: astral-sh/ty#2336
fixes: astral-sh/ty#2382

This PR fixes a bug where the generic context was not being passed through the decorator via the ParamSpec type variable. For example:

from typing import Callable

def decorator[**P, R](f: Callable[P, R]) -> Callable[P, R]: ...

@decorator 
def foo[T](x: T): ...

foo(1)

This meant that after the decorator has been applied, the Callable corresponding to the ParamSpec type variable did not preserve the generic context from the decorated function, which lead to foo loosing the generic context.

Test Plan

Add new mdtest cases.

Typing conformance result

The false positive that's removed is correct.

The true positives that are removed isn't correct but it's unrelated to this PR (related to astral-sh/ty#623). The case is:

def accepts_callable(cb: t.Callable[P, R]) -> t.Callable[P, R]:
    return cb

class Class9:
    def __init__(self, x: list[T], y: list[T]) -> None: ...

r9 = accepts_callable(Class9)
r9([1], [""])  # E

Here, the r9 call has two arguments and the corresponding parameters have the same type variable. Pyright specializes using the first argument and errors on the second argument while ty currently union the constraints i.e., T: Unknown | int | str (Unknown because T is inside a list).

@dhruvmanila dhruvmanila added bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker labels Jan 13, 2026
@astral-sh-bot

astral-sh-bot Bot commented Jan 13, 2026 •

Copy link
Copy Markdown

Typing conformance results

The percentage of diagnostics emitted that were expected errors increased from 77.47% to 77.51%. The percentage of expected errors that received a diagnostic decreased from 60.67% to 60.49%.

Summary

Metric Old New Diff Outcome
True Positives 674 672 -2 ⏬ (❌)
False Positives 196 195 -1 ⏬ (✅)
False Negatives 437 439 +2 ⏫ (❌)
Total Diagnostics 870 867 -3 ⏬
Precision 77.47% 77.51% +0.04% ⏫ (✅)
Recall 60.67% 60.49% -0.18% ⏬ (❌)

False positives removed

Details
Location Name Message
constructors_callable.py:196:16 invalid-argument-type Argument is incorrect: Expected list[T@__init__], found list[Unknown | str]

True positives removed

Details
Location Name Message
constructors_callable.py:186:4 invalid-argument-type Argument is incorrect: Expected list[T@Class8], found list[Unknown | int]
constructors_callable.py:197:4 invalid-argument-type Argument is incorrect: Expected list[T@__init__], found list[Unknown | int]

@astral-sh-bot

astral-sh-bot Bot commented Jan 13, 2026 •

Copy link
Copy Markdown

mypy_primer results

Changes were detected when running on open source projects
anyio (https://github.com/agronholm/anyio)
- src/anyio/_backends/_asyncio.py:2542:13: error[invalid-argument-type] Argument to bound method `run` is incorrect: Expected `Coroutine[Any, Any, _T@run_coroutine_threadsafe]`, found `CoroutineType[Any, Any, T_Retval@run_async_from_thread]`
- Found 92 diagnostics
+ Found 91 diagnostics

async-utils (https://github.com/mikeshardmind/async-utils)
- src/async_utils/gen_transform.py:109:36: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `Queue[Y@_consumer]`, found `Queue[Y@_sync_to_async_gen]`
- src/async_utils/gen_transform.py:109:54: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `(**P@_consumer) -> Generator[Y@_consumer, None, None]`, found `(**P@_sync_to_async_gen) -> Generator[Y@_sync_to_async_gen, None, None]`
- src/async_utils/gen_transform.py:109:66: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `P@_consumer.args`, found `P@_sync_to_async_gen.args`
- src/async_utils/gen_transform.py:109:69: error[invalid-argument-type] Argument to function `to_thread` is incorrect: Expected `P@_consumer.kwargs`, found `P@_sync_to_async_gen.kwargs`
- Found 12 diagnostics
+ Found 8 diagnostics

asynq (https://github.com/quora/asynq)
- asynq/tests/test_tools.py:72:39: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@afilter]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:74:34: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@afilter]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:82:53: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@afilterfalse]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:90:53: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asift]`, found `list[Unknown | None | int]`
- asynq/tests/test_tools.py:95:45: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amap]`, found `list[Unknown | None]`
- asynq/tests/test_tools.py:96:44: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amap]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:98:58: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amap]`, found `list[Unknown | None | str]`
- asynq/tests/test_tools.py:103:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asorted]`, found `list[Unknown | None]`
- asynq/tests/test_tools.py:104:37: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asorted]`, found `list[Unknown | bool | None]`
- asynq/tests/test_tools.py:105:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@asorted]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:109:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `Literal[1]`
+ asynq/tests/test_tools.py:109:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[Unknown]`, found `Literal[1]`
- asynq/tests/test_tools.py:110:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | int | None]`
- asynq/tests/test_tools.py:111:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `GeneratorType[Literal[1] | None, None, None]`
- asynq/tests/test_tools.py:112:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:113:31: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | list[Unknown | int]]`
- asynq/tests/test_tools.py:115:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `Literal[1]`
+ asynq/tests/test_tools.py:115:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[Unknown]`, found `Literal[1]`
- asynq/tests/test_tools.py:126:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `Literal[1]`
+ asynq/tests/test_tools.py:126:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[Unknown]`, found `Literal[1]`
- asynq/tests/test_tools.py:127:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `list[Unknown | int | None]`
- asynq/tests/test_tools.py:128:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `GeneratorType[Literal[1] | None, None, None]`
- asynq/tests/test_tools.py:129:25: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:129:30: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amin, /) -> Any) | None`, found `list[Unknown | int]`
+ asynq/tests/test_tools.py:129:30: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((int, /) -> Any) | None`, found `list[Unknown | int]`
- asynq/tests/test_tools.py:130:25: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `list[Unknown | list[Unknown | int]]`
- asynq/tests/test_tools.py:132:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amin]`, found `Literal[1]`
+ asynq/tests/test_tools.py:132:23: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[Unknown]`, found `Literal[1]`
- asynq/tests/test_tools.py:132:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amin, /) -> Any) | None`, found `Literal[2]`
+ asynq/tests/test_tools.py:132:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((Unknown, /) -> Any) | None`, found `Literal[2]`
- asynq/tests/test_typing.py:41:43: error[invalid-argument-type] Argument to bound method `asyncio` is incorrect: Expected `_T@generic`, found `str`
- asynq/tests/test_typing.py:54:16: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((...) -> _T@async_call) | ((...) -> FutureBase[_T@async_call])`, found `def f(x: int) -> str`
- asynq/tests/test_typing.py:56:20: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((...) -> _T@async_call) | ((...) -> FutureBase[_T@async_call])`, found `def f(x: int) -> str`
- asynq/tests/test_typing.py:61:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `Literal[1]`
+ asynq/tests/test_typing.py:61:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[Sized]`, found `Literal[1]`
- asynq/tests/test_typing.py:61:32: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amax, /) -> Any) | None`, found `def len(obj: Sized, /) -> int`
- asynq/tests/test_typing.py:62:26: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `Iterable[_T@amax]`, found `list[Unknown | int]`
- asynq/tests/test_typing.py:62:34: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((_T@amax, /) -> Any) | None`, found `def len(obj: Sized, /) -> int`
+ asynq/tests/test_typing.py:62:34: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `((Unknown | int | Sized, /) -> Any) | None`, found `def len(obj: Sized, /) -> int`
- Found 217 diagnostics
+ Found 194 diagnostics

dulwich (https://github.com/dulwich/dulwich)
- dulwich/porcelain/__init__.py:652:16: error[invalid-return-type] Return type does not match returned value: expected `AbstractContextManager[T@open_repo | Repo, bool | None]`, found `_GeneratorContextManager[T@_noop_context_manager, None, None]`
+ dulwich/porcelain/__init__.py:652:16: error[invalid-return-type] Return type does not match returned value: expected `AbstractContextManager[T@open_repo | Repo, bool | None]`, found `_GeneratorContextManager[(str & BaseRepo) | (PathLike[str] & BaseRepo) | T@open_repo, None, None]`
- dulwich/porcelain/__init__.py:652:38: error[invalid-argument-type] Argument is incorrect: Expected `T@_noop_context_manager`, found `(str & BaseRepo) | (PathLike[str] & BaseRepo) | T@open_repo`
- dulwich/porcelain/__init__.py:706:16: error[invalid-return-type] Return type does not match returned value: expected `AbstractContextManager[T@open_repo_closing | Repo, bool | None]`, found `_GeneratorContextManager[T@_noop_context_manager, None, None]`
+ dulwich/porcelain/__init__.py:706:16: error[invalid-return-type] Return type does not match returned value: expected `AbstractContextManager[T@open_repo_closing | Repo, bool | None]`, found `_GeneratorContextManager[(str & BaseRepo) | (bytes & BaseRepo) | (PathLike[str] & BaseRepo) | T@open_repo_closing, None, None]`
- dulwich/porcelain/__init__.py:706:38: error[invalid-argument-type] Argument is incorrect: Expected `T@_noop_context_manager`, found `(str & BaseRepo) | (bytes & BaseRepo) | (PathLike[str] & BaseRepo) | T@open_repo_closing`
- Found 229 diagnostics
+ Found 227 diagnostics

tornado (https://github.com/tornadoweb/tornado)
- tornado/gen.py:239:39: error[invalid-argument-type] Argument to bound method `run` is incorrect: Expected `SupportsNext[_T@next]`, found `(Generator[Any, Any, _T@coroutine] & Generator[object, None, None]) | (_T@coroutine & Generator[object, None, None])`
- Found 327 diagnostics
+ Found 326 diagnostics

pydantic (https://github.com/pydantic/pydantic)
- pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | ((dict[str, int | float | str | ... omitted 3 union elements], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
+ pydantic/_internal/_core_metadata.py:87:54: error[invalid-assignment] Invalid assignment to key "pydantic_js_extra" with declared type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | ((dict[str, Divergent], type[Any], /) -> None)` on TypedDict `CoreMetadata`: value of type `dict[object, object]`
- pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:949:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:989:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:1032:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:1072:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:1115:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:1154:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`
+ pydantic/fields.py:1194:5: error[invalid-parameter-default] Default value of type `PydanticUndefinedType` is not assignable to annotated parameter type `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`
- pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, int | float | str | ... omitted 3 union elements] | ((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) | None`, found `Top[dict[Unknown, Unknown]] | (((dict[str, int | float | str | ... omitted 3 union elements], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`
+ pydantic/fields.py:1573:13: error[invalid-argument-type] Argument is incorrect: Expected `dict[str, Divergent] | ((dict[str, Divergent], /) -> None) | None`, found `Top[dict[Unknown, Unknown]] | (((dict[str, Divergent], /) -> None) & ~Top[dict[Unknown, Unknown]]) | None`

discord.py (https://github.com/Rapptz/discord.py)
- discord/ext/commands/core.py:683:35: error[invalid-argument-type] Argument is incorrect: Expected `Context[BotT@cog_command_error]`, found `Context[BotT@dispatch_error]`
- discord/ext/commands/core.py:1314:63: error[invalid-argument-type] Argument to function `maybe_coroutine` is incorrect: Expected `Context[BotT@cog_check]`, found `Context[BotT@can_run]`
- discord/ext/commands/hybrid.py:430:45: error[invalid-argument-type] Argument to function `maybe_coroutine` is incorrect: Expected `Interaction[ClientT@interaction_check]`, found `Interaction[Client]`
- Found 539 diagnostics
+ Found 536 diagnostics

trio (https://github.com/python-trio/trio)
- src/trio/_core/_tests/test_run.py:2444:27: error[invalid-argument-type] Argument is incorrect: Expected `T@async_yield`, found `object`
- src/trio/_core/_tests/test_run.py:2502:27: error[invalid-argument-type] Argument is incorrect: Expected `T@async_yield`, found `Literal[1]`
- src/trio/_core/_tests/test_run.py:2503:27: error[invalid-argument-type] Argument is incorrect: Expected `T@async_yield`, found `Literal[2]`
- src/trio/_tests/test_highlevel_open_unix_stream.py:28:25: error[invalid-argument-type] Argument is incorrect: Expected `CloseT@close_on_error`, found `CloseMe`
- src/trio/_tests/test_highlevel_open_unix_stream.py:33:29: error[invalid-argument-type] Argument is incorrect: Expected `CloseT@close_on_error`, found `CloseMe`
- Found 487 diagnostics
+ Found 482 diagnostics

mypy (https://github.com/python/mypy)
- mypy/subtypes.py:187:26: error[invalid-argument-type] Argument is incorrect: Expected `list[tuple[T@pop_on_exit, T@pop_on_exit]]`, found `list[tuple[Type, Type]]`
- mypy/subtypes.py:187:71: error[invalid-argument-type] Argument is incorrect: Expected `T@pop_on_exit`, found `Type`
- mypy/subtypes.py:187:77: error[invalid-argument-type] Argument is incorrect: Expected `T@pop_on_exit`, found `Type`
- mypy/subtypes.py:226:26: error[invalid-argument-type] Argument is incorrect: Expected `list[tuple[T@pop_on_exit, T@pop_on_exit]]`, found `list[tuple[Type, Type]]`
- mypy/subtypes.py:226:70: error[invalid-argument-type] Argument is incorrect: Expected `T@pop_on_exit`, found `Type`
- mypy/subtypes.py:226:76: error[invalid-argument-type] Argument is incorrect: Expected `T@pop_on_exit`, found `Type`
- mypy/subtypes.py:1212:22: error[invalid-argument-type] Argument is incorrect: Expected `list[tuple[T@pop_on_exit, T@pop_on_exit]]`, found `Unknown | list[tuple[Instance, Instance]]`
- mypy/subtypes.py:1212:32: error[invalid-argument-type] Argument is incorrect: Expected `T@pop_on_exit`, found `Instance`
- mypy/subtypes.py:1212:38: error[invalid-argument-type] Argument is incorrect: Expected `T@pop_on_exit`, found `Instance`
- Found 1742 diagnostics
+ Found 1733 diagnostics

pwndbg (https://github.com/pwndbg/pwndbg)
- pwndbg/dbg_mod/gdb/__init__.py:181:28: error[invalid-argument-type] Argument is incorrect: Expected `T@selection`, found `Unknown | Frame`
- pwndbg/dbg_mod/gdb/__init__.py:200:24: error[invalid-argument-type] Argument is incorrect: Expected `T@selection`, found `Unknown | Frame`
- pwndbg/dbg_mod/gdb/__init__.py:389:24: error[invalid-argument-type] Argument is incorrect: Expected `T@selection`, found `Unknown | InferiorThread`
- Found 2031 diagnostics
+ Found 2028 diagnostics

scikit-build-core (https://github.com/scikit-build/scikit-build-core)
- src/scikit_build_core/build/wheel.py:99:20: error[no-matching-overload] No overload of bound method `__init__` matches arguments
- Found 47 diagnostics
+ Found 46 diagnostics

prefect (https://github.com/PrefectHQ/prefect)
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:94:28: error[invalid-assignment] Object of type `dict[str, Any] | int | T@resolve_block_document_references | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:96:21: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_block_document_references`, found `dict[str, Any] | @Todo`
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:99:28: error[invalid-assignment] Object of type `int | T@resolve_variables | float | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/integrations/prefect-dbt/prefect_dbt/core/settings.py:99:63: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_variables`, found `dict[str, Any]`
- src/prefect/_internal/concurrency/calls.py:341:41: error[invalid-argument-type] Argument to bound method `run` is incorrect: Expected `Generator[Any, None, _T@create_task] | Coroutine[Any, Any, _T@create_task]`, found `CoroutineType[Any, Any, None]`
- src/prefect/_internal/concurrency/calls.py:355:41: error[invalid-argument-type] Argument to bound method `run` is incorrect: Expected `Coroutine[Any, Any, _T@run]`, found `CoroutineType[Any, Any, None]`
- src/prefect/automations.py:235:5: error[invalid-argument-type] Argument is incorrect: Expected `Overload[(cls, id: UUID, name: str | None = ...) -> Self@aread | Self@aread, (cls, id: None = None, name: str = ...) -> Self@aread | Self@aread]`, found `Overload[[Self](cls, id: UUID, name: str | None = ...) -> CoroutineType[Any, Any, Self], [Self](cls, id: None = None, name: str = ...) -> CoroutineType[Any, Any, Self]]`
+ src/prefect/automations.py:235:5: error[invalid-argument-type] Argument is incorrect: Expected `Overload[[Self](cls, id: UUID, name: str | None = ...) -> Self | Self@aread, [Self](cls, id: None = None, name: str = ...) -> Self@aread | Self]`, found `Overload[[Self](cls, id: UUID, name: str | None = ...) -> CoroutineType[Any, Any, Self], [Self](cls, id: None = None, name: str = ...) -> CoroutineType[Any, Any, Self]]`
- src/prefect/cli/deploy/_core.py:86:21: error[invalid-assignment] Object of type `dict[str, Any] | int | T@resolve_block_document_references | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/prefect/cli/deploy/_core.py:86:61: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_block_document_references`, found `dict[str, Any]`
- src/prefect/cli/deploy/_core.py:87:21: error[invalid-assignment] Object of type `int | T@resolve_variables | float | ... omitted 4 union elements` is not assignable to `dict[str, Any]`
- src/prefect/cli/deploy/_core.py:87:45: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_variables`, found `dict[str, Any]`
- src/prefect/deployments/steps/core.py:136:54: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_block_document_references`, found `dict[Any, Any]`
- src/prefect/deployments/steps/core.py:137:38: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_variables`, found `dict[str, Any] | int | T@resolve_block_document_references | ... omitted 4 union elements`
- src/prefect/task_engine.py:777:25: error[invalid-argument-type] Argument is incorrect: Expected `Task[P@update_for_task, R@update_for_task]`, found `Task[P@SyncTaskRunEngine, R@SyncTaskRunEngine] | Task[P@SyncTaskRunEngine, Coroutine[Any, Any, R@SyncTaskRunEngine]]`
- src/prefect/task_engine.py:1399:25: error[invalid-argument-type] Argument is incorrect: Expected `Task[P@update_for_task, R@update_for_task]`, found `Task[P@AsyncTaskRunEngine, R@AsyncTaskRunEngine] | Task[P@AsyncTaskRunEngine, Coroutine[Any, Any, R@AsyncTaskRunEngine]]`
- src/prefect/task_runners.py:398:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `(**_P@run) -> _T@run`, found `def run[_T](main: Coroutine[Any, Any, _T], *, debug: bool | None = None) -> _T`
- src/prefect/task_runners.py:399:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.args`, found `CoroutineType[Any, Any, Unknown | State[Any] | None]`
- src/prefect/task_runners.py:404:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `(**_P@run) -> _T@run`, found `def run_task_sync[**P, R](task: Task[P, R], task_run_id: UUID | None = None, task_run: TaskRun | None = None, parameters: dict[str, Any] | None = None, wait_for: PrefectFuture[Any] | Any | Iterable[PrefectFuture[Any] | Any] | None = None, return_type: Literal["state", "result"] = "result", dependencies: dict[str, set[RunInput]] | None = None, context: dict[str, Any] | None = None) -> R | State[Any] | None`
- src/prefect/task_runners.py:803:13: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `Task[P@_resolve_futures_and_submit, R@_resolve_futures_and_submit | CoroutineType[Any, Any, R@_resolve_futures_and_submit]]`, found `Task[P@submit, R@submit | CoroutineType[Any, Any, R@submit]]`
- src/prefect/task_worker.py:387:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `(**_P@run) -> _T@run`, found `def run_task_sync[**P, R](task: Task[P, R], task_run_id: UUID | None = None, task_run: TaskRun | None = None, parameters: dict[str, Any] | None = None, wait_for: PrefectFuture[Any] | Any | Iterable[PrefectFuture[Any] | Any] | None = None, return_type: Literal["state", "result"] = "result", dependencies: dict[str, set[RunInput]] | None = None, context: dict[str, Any] | None = None) -> R | State[Any] | None`
- src/prefect/task_worker.py:389:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.kwargs`, found `UUID`
- src/prefect/task_worker.py:390:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.kwargs`, found `TaskRun`
- src/prefect/task_worker.py:391:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.kwargs`, found `dict[Unknown, Unknown] | Any`
- src/prefect/task_worker.py:392:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.kwargs`, found `list[Unknown] | Any`
- src/prefect/task_worker.py:393:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.kwargs`, found `Literal["state"]`
- src/prefect/task_worker.py:394:17: error[invalid-argument-type] Argument to bound method `submit` is incorrect: Expected `_P@run.kwargs`, found `None | Any`
- src/prefect/task_worker.py:595:13: error[invalid-argument-type] Argument to function `create_call` is incorrect: Expected `Task[P@aserve, R@aserve]`, found `Task[P@serve, R@serve]`
- src/prefect/tasks.py:922:35: error[invalid-argument-type] Argument is incorrect: Expected `Task[P@update_for_task, R@update_for_task]`, found `Self@create_run`
- src/prefect/tasks.py:1027:35: error[invalid-argument-type] Argument is incorrect: Expected `Task[P@update_for_task, R@update_for_task]`, found `Self@create_local_run`
- src/prefect/tasks.py:1822:21: error[invalid-argument-type] Argument is incorrect: Expected `Task[P@aserve, R@aserve]`, found `Self@serve`
- src/prefect/utilities/templating.py:318:17: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_block_document_references`, found `object`
+ src/prefect/utilities/templating.py:318:17: error[invalid-argument-type] Argument is incorrect: Argument type `object` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/utilities/templating.py:320:13: error[invalid-assignment] Invalid subscript assignment with key of type `object` and value of type `dict[str, Any] | int | T@resolve_block_document_references | ... omitted 4 union elements` on object of type `dict[str, Any]`
+ src/prefect/utilities/templating.py:320:13: error[invalid-assignment] Invalid subscript assignment with key of type `object` and value of type `Unknown | dict[str, Any]` on object of type `dict[str, Any]`
- src/prefect/utilities/templating.py:323:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_block_document_references | dict[str, Any]`, found `list[Unknown | dict[str, Any] | int | ... omitted 5 union elements]`
+ src/prefect/utilities/templating.py:323:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_block_document_references | dict[str, Any]`, found `list[Unknown | dict[str, Any]]`
- src/prefect/utilities/templating.py:325:17: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_block_document_references`, found `object`
+ src/prefect/utilities/templating.py:325:17: error[invalid-argument-type] Argument is incorrect: Argument type `object` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/utilities/templating.py:437:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `dict[object, Unknown | int | T@resolve_variables | ... omitted 5 union elements]`
+ src/prefect/utilities/templating.py:437:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `dict[object, Unknown]`
- src/prefect/utilities/templating.py:438:42: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_variables`, found `object`
+ src/prefect/utilities/templating.py:438:42: error[invalid-argument-type] Argument is incorrect: Argument type `object` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/utilities/templating.py:442:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `list[Unknown | int | T@resolve_variables | ... omitted 5 union elements]`
+ src/prefect/utilities/templating.py:442:16: error[invalid-return-type] Return type does not match returned value: expected `T@resolve_variables`, found `list[Unknown]`
- src/prefect/utilities/templating.py:442:41: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_variables`, found `object`
+ src/prefect/utilities/templating.py:442:41: error[invalid-argument-type] Argument is incorrect: Argument type `object` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
+ src/prefect/workers/base.py:232:13: error[invalid-argument-type] Argument is incorrect: Argument type `str | dict[str, Any]` does not satisfy constraints (`str`, `int`, `int | float`, `bool`, `dict[Any, Any]`, `list[Any]`, `None`) of type variable `T`
- src/prefect/workers/base.py:232:13: error[invalid-argument-type] Argument is incorrect: Expected `T@resolve_variables`, found `dict[str, Any] | int | T@resolve_block_document_references | ... omitted 4 union elements`
- src/prefect/workers/base.py:234:20: error[invalid-argument-type] Argument expression after ** must be a mapping type: Found `int | T@resolve_variables | float | ... omitted 4 union elements`
- Found 5387 diagnostics
+ Found 5357 diagnostics

hydpy (https://github.com/hydpy-dev/hydpy)
- hydpy/core/hydpytools.py:2631:13: error[invalid-assignment] Object of type `tuple[_Node@topological_sort, ...]` is not assignable to attribute `_deviceorder` of type `tuple[Node | Element, ...] | None`
- hydpy/core/selectiontools.py:829:25: error[invalid-argument-type] Argument to bound method `add` is incorrect: Expected `_Node@ancestors`, found `Node | Element`
- hydpy/core/selectiontools.py:981:25: error[invalid-argument-type] Argument to bound method `add` is incorrect: Expected `_Node@descendants`, found `Node | Element`
- hydpy/core/threadingtools.py:247:66: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `_Node@dfs_successors | None`, found `Element`
- hydpy/core/threadingtools.py:259:70: error[invalid-argument-type] Argument to bound method `__call__` is incorrect: Expected `_Node@dfs_successors | None`, found `Node`
- Found 668 diagnostics
+ Found 663 diagnostics

zulip (https://github.com/zulip/zulip)
- zerver/data_import/slack.py:1794:13: error[invalid-argument-type] Argument to function `convert_slack_workspace_messages` is incorrect: Expected `(UploadFileRequest, /) -> None`, found `(ParallelRecordType@run_parallel_queue, /) -> None`
- zerver/lib/export.py:2288:9: error[invalid-argument-type] Argument is incorrect: Expected `(ParallelRecordType@run_parallel_queue, /) -> None`, found `def _save_s3_key_to_file(key_name: str) -> None`
- zerver/lib/export.py:2299:65: error[invalid-argument-type] Argument to function `iterate_attachments` is incorrect: Expected `(str, /) -> Any`, found `(ParallelRecordType@run_parallel_queue, /) -> None`
- zerver/lib/parallel.py:54:9: error[invalid-argument-type] Argument is incorrect: Expected `(ParallelRecordType@run_parallel_queue, /) -> None`, found `(ParallelRecordType@run_parallel, /) -> None`
- zerver/lib/parallel.py:63:20: error[invalid-argument-type] Argument is incorrect: Expected `ParallelRecordType@run_parallel_queue`, found `ParallelRecordType@run_parallel`
- zerver/tests/test_parallel.py:135:21: error[invalid-argument-type] Argument is incorrect: Expected `ParallelRecordType@run_parallel_queue`, found `Literal[100]`
- zerver/tests/test_parallel.py:143:21: error[invalid-argument-type] Argument is incorrect: Expected `ParallelRecordType@run_parallel_queue`, found `Literal[101]`
- zerver/tests/test_parallel.py:144:21: error[invalid-argument-type] Argument is incorrect: Expected `ParallelRecordType@run_parallel_queue`, found `Literal[102]`
- Found 3669 diagnostics
+ Found 3661 diagnostics

rotki (https://github.com/rotki/rotki)
- rotkehlchen/chain/decoding/tools.py:96:44: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
- rotkehlchen/chain/decoding/tools.py:99:13: error[invalid-argument-type] Argument to function `decode_transfer_direction` is incorrect: Expected `Sequence[A@BaseDecoderTools]`, found `Unknown | tuple[BTCAddress, ...] | tuple[ChecksumAddress, ...] | tuple[SubstrateAddress, ...] | tuple[SolanaAddress, ...]`
- rotkehlchen/chain/decoding/tools.py:100:62: warning[unused-ignore-comment] Unused blanket `type: ignore` directive
+ rotkehlchen/chain/decoding/tools.py:97:13: error[invalid-argument-type] Argument to function `decode_transfer_direction` is incorrect: Expected `BTCAddress | ChecksumAddress | SubstrateAddress | SolanaAddress`, found `A@BaseDecoderTools`
+ rotkehlchen/chain/decoding/tools.py:98:13: error[invalid-argument-type] Argument to function `decode_transfer_direction` is incorrect: Expected `BTCAddress | ChecksumAddress | SubstrateAddress | SolanaAddress | None`, found `A@BaseDecoderTools | None`
- Found 2050 diagnostics
+ Found 2049 diagnostics

core (https://github.com/home-assistant/core)
+ homeassistant/util/variance.py:47:12: error[invalid-return-type] Return type does not match returned value: expected `(**_P@ignore_variance) -> _R@ignore_variance`, found `_Wrapped[_P@ignore_variance, int | _R@ignore_variance | float | datetime, _P@ignore_variance, _R@ignore_variance | int | float | datetime]`
- Found 14464 diagnostics
+ Found 14465 diagnostics

No memory usage changes detected ✅

@dhruvmanila
dhruvmanila force-pushed the dhruv/paramspec-decorator branch from ec2861b to 495d4b7 Compare January 16, 2026 09:12
@astral-sh-bot

astral-sh-bot Bot commented Jan 22, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-argument-type 0 89 14
invalid-return-type 5 0 6
invalid-assignment 0 5 1
invalid-await 0 0 6
Total 5 94 27

Full report with detailed diff (timing results)

@dhruvmanila
dhruvmanila marked this pull request as ready for review January 22, 2026 09:41

@dcreager dcreager left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wonderful

@dhruvmanila
dhruvmanila merged commit cb4fec2 into main Jan 23, 2026
50 checks passed
@dhruvmanila
dhruvmanila deleted the dhruv/paramspec-decorator branch January 23, 2026 05:03
carljm added a commit that referenced this pull request Jan 30, 2026
* main: (62 commits)
  [`refurb`] Do not add `abc.ABC` if already present (`FURB180`) (#22234)
  [ty] Add a new `assert-type-unspellable-subtype` diagnostic (#22815)
  [ty] Avoid duplicate syntax errors for `await` outside functions (#22826)
  [ty] Fix unary operator false-positive for constrained TypeVars (#22783)
  [ty] Fix binary operator false-positive for constrained TypeVars (#22782)
  [ty] Fix false-positive `unsupported-operator` for "symmetric" TypeVars (#22756)
  [`pydocstyle`] Clarify which quote styles are allowed (`D300`) (#22825)
  [ty] Use distributed versions of AND and OR on constraint sets (#22614)
  [ty] Add support for dict literals and dict() calls as default values for parameters with TypedDict types (#22161)
  Document `-` stdin convention in CLI help text (#22817)
  [ty] Make `infer_subscript_expression_types` a method on `Type` (#22731)
  [ty] Simplify `OverloadLiteral::spans` and `OverloadLiteral::parameter_span` (#22823)
  [ty] Require both `*args` and `**kwargs` when calling a `ParamSpec` callable (#22820)
  [ty] Handle tagged errors in conformance (#22746)
  Add `--color` cli option to force colored output (#22806)
  Identify notebooks by LSP didOpen instead of `.ipynb` file extension (#22810)
  [ty] Fix docstring rendering for literal blocks after doctests (#22676)
  [ty] Update salsa to fix out-of-order query validation (#22498)
  [ty] Inline cycle initial and recovery functions (#22814)
  [ty] Pass the generic context through the decorator (#22544)
  ...
carljm added a commit that referenced this pull request Jun 8, 2026
## Summary

In #21876 we introduced a
special-cased workaround inference for `@asynccontextmanager`, since we
didn't at the time have the needed generics solver features to handle
it.

Today (thanks to #21551,
#21902,
#21902 and
#22544), we have all the necessary
pieces to handle this natively, and no longer need a special-cased
workaround.

And the workaround didn't correctly preserve the generic context of a
generic async context manager, so removing the workaround fixes generic
async context managers, too.

Closes astral-sh/ty#3692.

## Test plan

Added regression mdtest for the generic case. Existing tests pass.

Codex analysis confirms all removed ecosystem diagnostics were false
positives; removing them is a fix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug An issue describing something that isn't working, or a PR that fixes a bug ecosystem-analyzer ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Erroneous invalid-argument-type for generic contextmanager with ParamSpec decorator that uses paramspec breaks generics on decorated function

2 participants