88 ContextManager ,
99 GeneratorContextManager ,
1010)
11- from .core import DecoyCore , StubCore
11+ from .core import DecoyCore , StubCore , PropCore
1212from .types import ClassT , ContextValueT , FuncT , ReturnT
1313
1414# ensure decoy does not pollute pytest tracebacks
@@ -19,7 +19,7 @@ class Decoy:
1919 """Decoy mock factory and state container.
2020
2121 You should create a new Decoy instance before each test and call
22- [reset][decoy.Decoy.reset] after each test. If you use the
22+ [` reset` ][decoy.Decoy.reset] after each test. If you use the
2323 [`decoy` pytest fixture][decoy.pytest_plugin.decoy], this is done
2424 automatically. See the [setup guide](../#setup) for more details.
2525
@@ -92,7 +92,7 @@ def create_decoy(
9292 """Create a class mock for `spec`.
9393
9494 !!! warning "Deprecated since v1.6.0"
95- Use [decoy.Decoy.mock][ ] with the `cls` parameter, instead.
95+ Use [`mock`][ decoy.Decoy.mock] with the `cls` parameter, instead.
9696 """
9797 warn (
9898 "decoy.create_decoy is deprecated; use decoy.mock(cls=...) instead." ,
@@ -111,7 +111,7 @@ def create_decoy_func(
111111 """Create a function mock for `spec`.
112112
113113 !!! warning "Deprecated since v1.6.0"
114- Use [decoy.Decoy.mock][ ] with the `func` parameter, instead.
114+ Use [`mock`][ decoy.Decoy.mock] with the `func` parameter, instead.
115115 """
116116 warn (
117117 "decoy.create_decoy_func is deprecated; use decoy.mock(func=...) instead." ,
@@ -127,7 +127,7 @@ def when(
127127 * ,
128128 ignore_extra_args : bool = False ,
129129 ) -> "Stub[ReturnT]" :
130- """Create a [Stub][decoy.Stub] configuration using a rehearsal call.
130+ """Create a [` Stub` ][decoy.Stub] configuration using a rehearsal call.
131131
132132 See [stubbing usage guide](../usage/when/) for more details.
133133
@@ -138,8 +138,9 @@ def when(
138138 ignoring unspecified arguments.
139139
140140 Returns:
141- A stub to configure using `then_return`, `then_raise`, `then_do`, or
142- `then_enter_with`.
141+ A stub to configure using [`then_return`][decoy.Stub.then_return],
142+ [`then_raise`][decoy.Stub.then_raise], [`then_do`][decoy.Stub.then_do],
143+ or [`then_enter_with`][decoy.Stub.then_enter_with].
143144
144145 Example:
145146 ```python
@@ -202,12 +203,27 @@ def test_create_something(decoy: Decoy):
202203 ignore_extra_args = ignore_extra_args ,
203204 )
204205
206+ def prop (self , _rehearsal_result : ReturnT ) -> "Prop[ReturnT]" :
207+ """Create property setter and deleter rehearsals.
208+
209+ See [property mocking guide](../advanced/properties/) for more details.
210+
211+ Arguments:
212+ _rehearsal_result: The property to mock, for typechecking.
213+
214+ Returns:
215+ A prop rehearser on which you can call [`set`][decoy.Prop.set] or
216+ [`delete`][decoy.Prop.delete] to create property rehearsals.
217+ """
218+ prop_core = self ._core .prop (_rehearsal_result )
219+ return Prop (core = prop_core )
220+
205221 def reset (self ) -> None :
206222 """Reset all mock state.
207223
208224 This method should be called after every test to ensure spies and stubs
209- don't leak between tests. The `decoy` fixture provided by the pytest plugin
210- will call `reset` automatically.
225+ don't leak between tests. The [ `decoy`][decoy.pytest_plugin.decoy] fixture
226+ provided by the pytest plugin will call `reset` automatically.
211227
212228 The `reset` method may also trigger warnings if Decoy detects any questionable
213229 mock usage. See [decoy.warnings][] for more details.
@@ -243,7 +259,8 @@ def then_raise(self, error: Exception) -> None:
243259 Note:
244260 Setting a stub to raise will prevent you from writing new
245261 rehearsals, because they will raise. If you need to make more calls
246- to `when`, you'll need to wrap your rehearsal in a `try`.
262+ to [`when`][decoy.Decoy.when], you'll need to wrap your rehearsal
263+ in a `try`.
247264 """
248265 self ._core .then_raise (error )
249266
@@ -299,4 +316,50 @@ def then_enter_with(
299316 self ._core .then_enter_with (value )
300317
301318
302- __all__ = ["Decoy" , "Stub" , "matchers" , "warnings" , "errors" ]
319+ class Prop (Generic [ReturnT ]):
320+ """Rehearsal creator for mocking property setters and deleters.
321+
322+ See [property mocking guide](../advanced/properties/) for more details.
323+ """
324+
325+ def __init__ (self , core : PropCore ) -> None :
326+ self ._core = core
327+
328+ def set (self , value : ReturnT ) -> None :
329+ """Create a property setter rehearsal.
330+
331+ By wrapping `set` in a call to [`when`][decoy.Decoy.when] or
332+ [`verify`][decoy.Decoy.verify], you can stub or verify a call
333+ to a property setter.
334+
335+ Arguments:
336+ value: The value
337+
338+ Example:
339+ ```python
340+ some_obj = decoy.mock()
341+ some_obj.prop = 42
342+ decoy.verify(decoy.prop(some_obj.prop).set(42))
343+ ```
344+ """
345+ self ._core .set (value )
346+
347+ def delete (self ) -> None :
348+ """Create a property deleter rehearsal.
349+
350+ By wrapping `delete` in a call to [`when`][decoy.Decoy.when] or
351+ [`verify`][decoy.Decoy.verify], you can stub or verify a call
352+ to a property deleter.
353+
354+
355+ Example:
356+ ```python
357+ some_obj = decoy.mock()
358+ del some_obj.prop
359+ decoy.verify(decoy.prop(some_obj.prop).delete())
360+ ```
361+ """
362+ self ._core .delete ()
363+
364+
365+ __all__ = ["Decoy" , "Stub" , "Prop" , "matchers" , "warnings" , "errors" ]
0 commit comments