Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 17, 2025

📝 Changes Description

dspy.asyncify returned Callable[[Any, Any], Awaitable[Any]], incorrectly specifying exactly 2 positional arguments. Pyright raised reportCallIssue errors on valid calls:

module = MyModule()
async_module = dspy.asyncify(module)
result = await async_module(5)  # error: Expected 2 positional arguments

Type Signature Fix:

  • Added ParamSpec("P") and TypeVar("T") to preserve function signatures
  • For generic callables: Callable[P, T]Callable[P, Awaitable[T]] (preserves exact parameter specification)
  • For DSPy Modules: Callable[..., Awaitable[Any]] (uses Any since Module return types cannot be statically determined)
  • Added @overload decorators for better type inference based on input type
  • Typed *args: P.args, **kwargs: P.kwargs and return type T in inner async_program function

Benefits:

  • Type checkers now know the exact signature of asyncified functions
  • Parameter names, types, and defaults are all preserved for typed callables
  • Incorrect arguments are caught at type-check time, not runtime
  • Module overload correctly uses Any to indicate dynamically-typed returns

Test Coverage:

  • Added test_asyncify_with_dspy_module covering positional/keyword args
  • Validates both DSPy modules and plain functions

✅ Contributor Checklist

  • Pre-Commit checks are passing (locally and remotely)
  • Title of your PR / MR corresponds to the required format
  • Commit message follows required format {label}(dspy): {message}

⚠️ Warnings

None. Backward compatible - existing code continues to work unchanged.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug] dspy.asyncify triggers Pyright "reportCallIssue" type error</issue_title>
<issue_description>### What happened?

When using dspy.asyncify to convert a DSPy module into an async callable, Pyright raises a reportCallIssue type error even though the asyncified module runs correctly at runtime.
As a result, static type-checking fails locally and in CI pipelines, which breaks builds that enforce type-safety.

Expected behaviour:

Pyright should not raise a type error; the asyncified module should be recognized as a callable with the same argument signature as the original module.

Environment:

Python: 3.12
DSPy==3.0.3
Pyright==1.1.407
OS: Mac

Possible Cause:

dspy.asyncify wraps the module dynamically without preserving its original type annotations.
Pyright then infers an incomplete or incorrect callable signature, leading to the diagnostic.

Suggested Fix:

Update the type signature of dspy.asyncify to use typing.ParamSpec and typing.TypeVar.
This will allow the function to preserve the original module’s argument types and annotations and correctly re-type the return value as a coroutine (e.g., Awaitable[T]).

Current Workaround:

`from typing import Callable, Awaitable, Any, cast

dspy_module_async = cast("Callable[..., Awaitable[Any]]", dspy.asyncify(dspy_module))
`

Steps to reproduce

`import dspy

class MyModule(dspy.Module):
def forward(self, x):
return x * 2

optimized_module = MyModule()
optimized_module_async = dspy.asyncify(optimized_module)

Pyright error here:
error: Expected 2 positional arguments (reportCallIssue)

result = await optimized_module_async(5)
`

DSPy version

3.0.3</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Fix Pyright reportCallIssue type error in dspy.asyncify fix(dspy): asyncify type signature causing Pyright reportCallIssue Nov 17, 2025
Copilot AI requested a review from TomeHirata November 17, 2025 07:17
Copilot finished work on behalf of TomeHirata November 17, 2025 07:17

def asyncify(program: "Module") -> Callable[[Any, Any], Awaitable[Any]]:
@overload
def asyncify(program: "Module") -> Callable[..., Awaitable[Any]]: ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot can we use generic typing to keep the function signature?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes! Updated to use ParamSpec and TypeVar to preserve function signatures. Now when you pass a typed callable, the asyncified version maintains the exact parameter specification and return type: Callable[P, T]Callable[P, Awaitable[T]]. For DSPy Modules, it falls back to Callable[..., Awaitable[T]].

Changes in commit 4b759b3.

Copilot AI requested a review from TomeHirata November 17, 2025 07:42
Copilot finished work on behalf of TomeHirata November 17, 2025 07:42


@overload
def asyncify(program: "Module") -> Callable[..., Awaitable[T]]: ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot how can we know T in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! T was unbound in the Module overload. Since Module doesn't have a generic return type, we can't statically determine T. Fixed to use Any instead: Callable[..., Awaitable[Any]].

For typed callables, the signature is preserved: Callable[P, T]Callable[P, Awaitable[T]].
For Modules, we use Any since the return type varies by implementation.

Changes in commit be2bd89.

Copilot AI requested a review from TomeHirata November 17, 2025 08:28
Copilot finished work on behalf of TomeHirata November 17, 2025 08:28
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.

[Bug] dspy.asyncify triggers Pyright "reportCallIssue" type error

2 participants