Source code for returns.primitives.tracing
import types
from contextlib import contextmanager
from inspect import FrameInfo, stack
from typing import (
Callable,
ContextManager,
Iterator,
List,
Optional,
TypeVar,
Union,
overload,
)
from returns.result import Failure
_FunctionType = TypeVar('_FunctionType', bound=Callable)
@overload
def collect_traces() -> ContextManager[None]:
"""Context Manager to active traces collect to the Failures."""
@overload
def collect_traces(function: _FunctionType) -> _FunctionType:
"""Decorator to active traces collect to the Failures."""
[docs]def collect_traces(
function: Optional[_FunctionType] = None,
) -> Union[_FunctionType, ContextManager[None]]: # noqa: DAR101, DAR201, DAR301
"""
Context Manager/Decorator to active traces collect to the Failures.
.. code:: python
>>> from inspect import FrameInfo
>>> from returns.io import IOResult
>>> from returns.result import Result
>>> from returns.primitives.tracing import collect_traces
>>> with collect_traces():
... traced_failure = Result.from_failure('Traced Failure')
>>> non_traced_failure = IOResult.from_failure('Non Traced Failure')
>>> assert non_traced_failure.trace is None
>>> assert isinstance(traced_failure.trace, list)
>>> assert all(isinstance(trace_line, FrameInfo) for trace_line in traced_failure.trace)
>>> for trace_line in traced_failure.trace:
... print( # doctest: +SKIP
... '{0}:{1} in `{2}`'.format(
... trace_line.filename,
... trace_line.lineno,
... trace_line.function,
... ),
... )
...
/returns/returns/result.py:525 in `Failure`
/returns/returns/result.py:322 in `from_failure`
/example_folder/example.py:1 in `<module>`
# doctest: # noqa: DAR301, E501
"""
@contextmanager
def factory() -> Iterator[None]:
unpatched_get_trace = getattr(Failure, '_get_trace') # noqa: B009
substitute_get_trace = types.MethodType(_get_trace, Failure)
setattr(Failure, '_get_trace', substitute_get_trace) # noqa: B010
try: # noqa: WPS501
yield
finally:
setattr(Failure, '_get_trace', unpatched_get_trace) # noqa: B010
return factory()(function) if function else factory()
def _get_trace(_self: Failure) -> Optional[List[FrameInfo]]:
"""
Function to be used on Monkey Patching.
This function is the substitute for '_get_trace' method from ``Failure``
class on Monkey Patching promoted by
:func:`returns.primitives.tracing.collect_traces` function.
We get all the call stack from the current call and return it from the
third position, to avoid two useless calls on the call stack.
Those useless calls are a call to this function and a call to `__init__`
method from ``Failure`` class. We're just interested in the call stack
ending on ``Failure`` function call!
See also:
- https://github.com/dry-python/returns/issues/409
"""
current_stack = stack()
return current_stack[2:]