1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
.. _development-tooling:
Development tooling
===================
Tracing Failures
----------------
Sometimes we want to trace where the ``Failure`` has occurred in our system,
``returns`` provide a way to trace those failures.
By default tracing is disabled.
The trace is accessible by :meth:`trace <returns.result.Result.trace>` property
that is available for ``Result``, ``IOResult`` containers. It's basically a list
containing all :class:`inspect.FrameInfo` objects from the call stack when the
``Failure`` was originally created.
To enable it you can use
:func:`collect_traces <returns.primitives.tracing.collect_traces>`.
See examples below:
You can use it as a context manager:
.. code:: python
>>> from inspect import FrameInfo
>>> from returns.result import Failure, Result
>>> from returns.primitives.tracing import collect_traces
>>> def get_failure(argument: str) -> Result[str, str]:
... return Failure(argument)
>>> non_traced_failure = get_failure('Normal Failure')
>>> with collect_traces():
... traced_failure = get_failure('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(f"{trace_line.filename}:{trace_line.lineno} in `{trace_line.function}`") # doctest: +SKIP
...
/returns/returns/result.py:529 in `Failure`
/example_folder/example.py:5 in `get_failure`
/example_folder/example.py:1 in `<module>`
Or as a decorator:
.. code:: python
>>> from inspect import FrameInfo
>>> from returns.io import IOFailure, IOResult
>>> from returns.result import Failure, Result
>>> from returns.primitives.tracing import collect_traces
>>> @collect_traces
... def traced_function(value: str) -> IOResult[str, str]:
... return IOFailure(value)
>>> non_traced_failure = Failure('Normal Failure')
>>> traced_failure = traced_function('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(f"{trace_line.filename}:{trace_line.lineno} in `{trace_line.function}`") # doctest: +SKIP
...
/returns/returns/result.py:525 in `Failure`
/returns/returns/io.py:852 in `IOFailure`
/example_folder/example.py:7: in `traced_function`
/usr/lib/python3.8/contextlib.py:75 in `inner`
/example_folder/example.py:1 in `<module>`
.. warning::
Activating trace can make your program noticeably slower if it has many points where ``Failure`` is often created.
.. warning::
``collect_traces`` is not thread safe, beware to use it with threading!
.. warning::
Traces are meant to be used during development only.
API Reference
-------------
.. automodule:: returns.primitives.tracing
:members:
|