Skip to content

Commit 8b3dfaf

Browse files
authored
fix: consume self argument of builtin methods (#326)
1 parent 19af603 commit 8b3dfaf

File tree

4 files changed

+26
-5
lines changed

4 files changed

+26
-5
lines changed

decoy/next/_internal/inspect.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ def get_child_spec(spec: object, child_name: str) -> object:
105105
_get_type_hints(unwrapped_child_source.fget).get("return")
106106
)
107107

108-
if inspect.isfunction(unwrapped_child_source):
109-
# consume `self` argument
108+
# consume `self` and `cls` arguments
109+
if inspect.isroutine(unwrapped_child_source):
110110
return functools.partial(unwrapped_child_source, None)
111111

112112
return _unwrap_type_alias(unwrapped_child_source)

decoy/spy_core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
"""Core spy logic."""
22

3-
import inspect
43
import functools
4+
import inspect
55
import warnings
66
from typing import (
77
Any,
88
Dict,
99
NamedTuple,
1010
Optional,
11+
Sequence,
1112
Tuple,
1213
Type,
1314
Union,
14-
Sequence,
1515
get_type_hints,
1616
)
1717

@@ -142,7 +142,7 @@ def create_child_core(self, name: str, is_async: bool) -> "SpyCore":
142142

143143
child_source = inspect.unwrap(child_source)
144144

145-
if inspect.isfunction(child_source):
145+
if inspect.isroutine(child_source):
146146
# consume the `self` argument of the method to ensure proper
147147
# signature reporting by wrapping it in a partial
148148
child_source = functools.partial(child_source, None)

tests/legacy/test_mock.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Smoke and acceptance tests for main Decoy interface."""
22

3+
import asyncio
34
import inspect
45
import sys
56
from typing import Any
@@ -327,3 +328,13 @@ async def test_async_context_manager(decoy: Decoy) -> None:
327328

328329
async with subject as result:
329330
assert result is None
331+
332+
333+
@pytest.mark.skipif(sys.version_info < (3, 9), reason="msg param added in 3.9")
334+
def test_builtin(decoy: Decoy) -> None:
335+
"""It can mock builtin classes."""
336+
subject = decoy.mock(cls=asyncio.Task)
337+
subject.cancel(msg="hello")
338+
339+
with pytest.warns(IncorrectCallWarning):
340+
subject.cancel(message="oops") # type: ignore[call-arg]

tests/test_mock.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import asyncio
56
import inspect
67
import sys
78
from typing import Any
@@ -364,3 +365,12 @@ async def test_async_context_manager(decoy: Decoy) -> None:
364365

365366
async with subject as result:
366367
assert result is None
368+
369+
370+
def test_builtin(decoy: Decoy) -> None:
371+
"""It can mock builtin classes."""
372+
subject = decoy.mock(cls=asyncio.Task)
373+
subject.cancel(msg="hello")
374+
375+
with pytest.raises(errors.SignatureMismatchError):
376+
subject.cancel(message="oops") # type: ignore[call-arg]

0 commit comments

Comments
 (0)