Get the real function object of the (possibly) wrapped object by functools.wraps or functools.partial.
(obj)
| 265 | |
| 266 | |
| 267 | def get_real_func(obj): |
| 268 | """Get the real function object of the (possibly) wrapped object by |
| 269 | functools.wraps or functools.partial.""" |
| 270 | start_obj = obj |
| 271 | for i in range(100): |
| 272 | # __pytest_wrapped__ is set by @pytest.fixture when wrapping the fixture function |
| 273 | # to trigger a warning if it gets called directly instead of by pytest: we don't |
| 274 | # want to unwrap further than this otherwise we lose useful wrappings like @mock.patch (#3774) |
| 275 | new_obj = getattr(obj, "__pytest_wrapped__", None) |
| 276 | if isinstance(new_obj, _PytestWrapper): |
| 277 | obj = new_obj.obj |
| 278 | break |
| 279 | new_obj = getattr(obj, "__wrapped__", None) |
| 280 | if new_obj is None: |
| 281 | break |
| 282 | obj = new_obj |
| 283 | else: |
| 284 | from _pytest._io.saferepr import saferepr |
| 285 | |
| 286 | raise ValueError( |
| 287 | ("could not find real function of {start}\nstopped at {current}").format( |
| 288 | start=saferepr(start_obj), current=saferepr(obj) |
| 289 | ) |
| 290 | ) |
| 291 | if isinstance(obj, functools.partial): |
| 292 | obj = obj.func |
| 293 | return obj |
| 294 | |
| 295 | |
| 296 | def get_real_method(obj, holder): |