Skip to content

Commit 3796b3e

Browse files
committed
Refactor InOrder to facade/impl and hide internal API
1 parent ebbce99 commit 3796b3e

2 files changed

Lines changed: 47 additions & 10 deletions

File tree

mockito/inorder.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ class InOrder:
9393
9494
"""
9595

96+
def __init__(self, *objects: object) -> None:
97+
self._core = InOrderImpl(*objects)
98+
99+
def verify(
100+
self,
101+
obj: object,
102+
times=None,
103+
atleast=None,
104+
atmost=None,
105+
between=None,
106+
):
107+
return self._core.verify(
108+
obj,
109+
times=times,
110+
atleast=atleast,
111+
atmost=atmost,
112+
between=between,
113+
)
114+
115+
def __enter__(self):
116+
self._core.__enter__()
117+
return self
118+
119+
def __exit__(self, exc_type, exc_val, exc_tb):
120+
self._core.__exit__(exc_type, exc_val, exc_tb)
121+
122+
123+
class InOrderImpl:
124+
"""Internal implementation behind the public `InOrder` facade."""
125+
96126

97127
def __init__(self, *objects: object):
98128
objects_: list[object] = []
@@ -221,11 +251,12 @@ def _guess_object_labels_from_callsite(self, count: int) -> list[str | None]:
221251
return [None]
222252

223253
frame = inspect.currentframe()
224-
caller_frame = (
225-
frame.f_back.f_back
226-
if frame and frame.f_back and frame.f_back.f_back
227-
else None
228-
)
254+
# Start at the direct caller and then walk out of our own module.
255+
# This is important because public `InOrder` delegates to `InOrderImpl`,
256+
# so the first stack frames are internal wrappers.
257+
caller_frame = frame.f_back if frame else None
258+
while caller_frame and caller_frame.f_code.co_filename == __file__:
259+
caller_frame = caller_frame.f_back
229260

230261
if caller_frame is None:
231262
return [None] * count
@@ -292,7 +323,7 @@ def _is_inorder_constructor_call(self, node: ast.Call) -> bool:
292323

293324

294325
class InOrderVerifiableInvocation(VerifiableInvocation):
295-
def __init__(self, mock, method_name, verification, inorder: InOrder):
326+
def __init__(self, mock, method_name, verification, inorder: InOrderImpl):
296327
super().__init__(mock, method_name, verification)
297328
self._inorder = inorder
298329

tests/in_order_test.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ def test_legacy_inorder_verify_is_deprecated():
6262
)
6363

6464

65+
def test_in_order_public_surface_is_verify_only():
66+
in_order = InOrder(mock())
67+
68+
public = [name for name in dir(in_order) if not name.startswith('_')]
69+
assert public == ["verify"]
70+
71+
6572
def test_observing_the_same_mock_twice_should_raise():
6673
a = mock()
6774
with pytest.raises(ValueError) as e:
@@ -393,12 +400,11 @@ def test_allow_double_entrance():
393400
in_order.verify(cat, times=1).meow()
394401

395402

396-
def test_close_should_detach_and_stop_late_registration_capture():
403+
def test_exited_in_order_should_stop_late_registration_capture():
397404
bob = Dog()
398405

399-
in_order = InOrder(bob)
400-
in_order.close()
401-
in_order.close()
406+
with InOrder(bob) as in_order:
407+
pass
402408

403409
expect(bob).say(...)
404410
bob.say("Wuff!")

0 commit comments

Comments
 (0)