python / python/mypy

Fully-fledged support for mocked objects

Open
#9,776 8 comments 15 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
Python
Stars
20.6k
Forks
3.3k
PR merge metrics
PR metrics pending

Description

Feature

I'd like to propose that fully-fledged support for mocked objects be added so that type checks work with spec'd mocks.

import mock
import typing


class Foo:
    def bar(self, a: int) -> str:
        return str(a)


# I want to pass a spec'd mock here (mock.create_autospec(spec=Foo)).
def test_something(foo: Foo):
    # I'd like to find a way for this to be accepted by mypy.
    # error: "Callable[[int], str]" has no attribute "return_value"
    foo.bar.return_value = "42"


# This can be resolved arduously by writing a custom protocol for each mock.
class BarMockProtocol(typing.Protocol):
    return_value: str

    def __call__(self, a: int) -> str:
        pass

    # def assert_called():
    #     ...
    # And so on...


class FooMockProtocol(typing.Protocol):
    bar: BarMockProtocol


def test_something_else(foo: FooMockProtocol):
    # Error as expected.
    # error: Incompatible types in assignment (expression has type "int", variable has type "str")
    foo.bar.return_value = 42

    # No error as expected.
    foo.bar.return_value = "42"


# This is what I'd suggest
def test_something_else_yet(foo: mock.Mock[Foo]):
    # Error
    foo.bar.return_value = 42
    # No error
    foo.bar.return_value = "42"


# Usage sample
foo_mock = mock.create_autospec(spec=Foo)
test_something_else_yet(foo_mock)

Pitch

Currently, it's difficult to fully utilise mypy with mocks. I can see the following options.

  1. Use typing.Any to disable type checks.
  2. Use the type of the mocked class and live/deal with errors when using mock-specific attributes and methods (e.g. return_value, assert_*).
  3. Write a custom protocol for every mocked class as demonstrated above.

In other words, it's a choice between boilerplate and limitations. Please do let me know if I missed anything.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation files or tests are named. Start by reproducing the issue's Foo, create_autospec, and Mock examples in mypy, then inspect how mocked objects and callable attributes are typed. Done means spec'd mocks support type-checked return_value assignments without custom protocols while preserving errors for incompatible values.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
devtools, testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.