Skip to content

Commit 476914b

Browse files
committed
Closes #253, closes #251, closes #249
1 parent ce730f7 commit 476914b

File tree

18 files changed

+366
-155
lines changed

18 files changed

+366
-155
lines changed

CHANGELOG.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ See [0Ver](https://0ver.org/).
1212

1313
- **Breaking**: renames `join` to `flatten`, sorry!
1414
- **Breaking**: renames `box` to `bind` and moves it to `returns.pointfree`
15-
- **Breaking**: renames `coalesce` to `fold`
1615
- **Breaking**: removes `Maybe.rescue` and `Maybe.fix` methods
1716

1817
- Adds `rescue` pointfree function
@@ -33,7 +32,7 @@ See [0Ver](https://0ver.org/).
3332
- Adds `IOResult` support for `bind`
3433
- Adds `IOResult` support for `flatten`
3534
- Adds `IOResult` support for `@pipeline`
36-
- Adds `IOResult` support for `fold`
35+
- Adds `IOResult` support for `coalesce`
3736
- Adds `IOResult` support for `is_successful`
3837

3938
- Adds `RequiresContextIOResult` container
@@ -45,6 +44,8 @@ See [0Ver](https://0ver.org/).
4544
- Adds `Result.lift`, `Maybe.lift`, `RequiresContext.lift`,
4645
and `RequiresContextResult.lift` functions in addition to `IO.lift`
4746
- Adds `Immutable` primitive type
47+
- Adds `Unitable` protocol and `.from_success()` and `.from_failure()`
48+
methods for all `Result` realted classes
4849

4950

5051
### Bugfixes

docs/pages/container.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ Note::
101101

102102
All containers support these methods.
103103

104+
You can read more about methods
105+
that some other containers support
106+
and :ref:`interfaces <base-interfaces>` behind them.
107+
104108

105109
.. _immutability:
106110

@@ -117,6 +121,9 @@ since we are using ``__slots__`` for better performance and strictness.
117121

118122
Well, nothing is **really** immutable in python, but you were warned.
119123

124+
We also provide :class:`returns.primitives.types.Immutable` mixin
125+
that users can use to quickly make their classes immutable.
126+
120127

121128
.. _type-safety:
122129

@@ -217,10 +224,24 @@ Further reading
217224
- :ref:`Railway oriented programming <railway>`
218225

219226

227+
.. _base-interfaces:
228+
220229
API Reference
221230
-------------
222231

232+
``BaseContainer`` is a base class for all other container.
233+
It defines some basic things like representation, hashing, pickling, etc.
234+
223235
.. autoclasstree:: returns.primitives.container
224236

225237
.. automodule:: returns.primitives.container
226238
:members:
239+
:special-members:
240+
241+
Here are our interfaces (or protocols to be more specific)
242+
that we use inside our app:
243+
244+
.. autoclasstree:: returns.primitives.interfaces
245+
246+
.. automodule:: returns.primitives.interfaces
247+
:members:

docs/pages/result.rst

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,12 @@ FAQ
9898
How to create unit objects?
9999
~~~~~~~~~~~~~~~~~~~~~~~~~~~
100100

101-
Use ``Success`` or ``Failure`` together with the explicit annotation.
101+
Use ``Success`` or ``Failure``.
102+
Alternatively :meth:`retunrs.result.Result.from_success`
103+
or :meth:`retunrs.result.Result.from_failure`.
104+
105+
It might be a good idea to use unit functions
106+
together with the explicit annotation.
102107
Python's type system does not allow us to do much, so this is required:
103108

104109
.. code:: python
@@ -112,18 +117,8 @@ Python's type system does not allow us to do much, so this is required:
112117
>>> str(first.bind(callback))
113118
'<Success: 1.0>'
114119
115-
Otherwise it would raise a ``mypy`` error:
116-
117-
.. code:: python
118-
119-
first = Success(1)
120-
first.bind(callback)
121-
# Argument 1 to "bind" of "Result" has incompatible type
122-
# "Callable[[int], Result[float, int]]";
123-
# expected "Callable[[int], Result[float, NoReturn]]"
124-
125-
This happens because ``mypy`` is unable to implicitly
126-
cast ``NoReturn`` to any other type.
120+
Otherwise ``first`` will have ``Result[int, Any]`` type.
121+
Which is okay in some situations.
127122

128123
What is the difference between ``Success`` and ``_Success``?
129124
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

returns/context/requires_context_io_result.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,12 @@ class RequiresContextIOResult(
7070
7171
- raw values and pure functions
7272
- ``RequiresContext`` values and pure functions returning it
73-
- ``Result`` and functions returning it
73+
- ``RequiresContextResult`` values and pure functions returning it
74+
- ``Result`` and pure functions returning it
7475
- ``IOResult`` and functions returning it
76+
- other ``RequiresContextIOResult`` related functions and values
77+
78+
This is a complex type for complex tasks!
7579
7680
Imporatant implementation detail:
7781
due it is meaning, ``RequiresContextIOResult``
@@ -868,6 +872,33 @@ def from_failed_context(
868872
lambda deps: IOFailure(inner_value(deps)),
869873
)
870874

875+
@classmethod
876+
def from_result_context(
877+
cls, inner_value: RequiresContextResult[
878+
_EnvType, _ValueType, _ErrorType,
879+
],
880+
) -> 'RequiresContextIOResult[_EnvType, _ValueType, _ErrorType]':
881+
"""
882+
Creates new container from ``RequiresContextResult`` as a unit value.
883+
884+
.. code:: python
885+
886+
>>> from returns.context import RequiresContextResult
887+
>>> from returns.io import IOSuccess, IOFailure
888+
889+
>>> assert RequiresContextIOResult.from_result_context(
890+
... RequiresContextResult.from_success(1),
891+
... )(...) == IOSuccess(1)
892+
893+
>>> assert RequiresContextIOResult.from_result_context(
894+
... RequiresContextResult.from_failure(1),
895+
... )(...) == IOFailure(1)
896+
897+
"""
898+
return RequiresContextIOResult(
899+
lambda deps: IOResult.from_result(inner_value(deps)),
900+
)
901+
871902
@classmethod
872903
def from_success(
873904
cls, inner_value: _FirstType,

returns/io.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,48 @@ def from_result(
600600
return _IOSuccess(container)
601601
return _IOFailure(container)
602602

603+
@classmethod
604+
def from_success(
605+
cls, inner_value: _NewValueType,
606+
) -> 'IOResult[_NewValueType, Any]':
607+
"""
608+
One more value to create success unit values.
609+
610+
This is a part of :class:`returns.primitives.interfaces.Unitable`.
611+
It is useful as a united way to create a new value from any container.
612+
613+
.. code:: python
614+
615+
>>> from returns.io import IOResult, IOSuccess
616+
>>> assert IOResult.from_success(1) == IOSuccess(1)
617+
618+
You can use this method or :func:`~IOSuccess`,
619+
choose the most convenient for you.
620+
621+
"""
622+
return IOSuccess(inner_value)
623+
624+
@classmethod
625+
def from_failure(
626+
cls, inner_value: _NewErrorType,
627+
) -> 'IOResult[Any, _NewErrorType]':
628+
"""
629+
One more value to create failred unit values.
630+
631+
This is a part of :class:`returns.primitives.interfaces.Unitable`.
632+
It is useful as a united way to create a new value from any container.
633+
634+
.. code:: python
635+
636+
>>> from returns.io import IOResult, IOFailure
637+
>>> assert IOResult.from_failure(1) == IOFailure(1)
638+
639+
You can use this method or :func:`~IOFailure`,
640+
choose the most convenient for you.
641+
642+
"""
643+
return IOFailure(inner_value)
644+
603645
def __str__(self) -> str:
604646
"""Custom ``str`` representation for better readability."""
605647
return '<IOResult: {0}>'.format(self._inner_value)

returns/primitives/container.py

Lines changed: 1 addition & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
# -*- coding: utf-8 -*-
22

33
from abc import ABCMeta
4-
from typing import Any, Callable, TypeVar, Union
5-
6-
from typing_extensions import Protocol, runtime
4+
from typing import Any, TypeVar
75

86
from returns.primitives.types import Immutable
97

@@ -51,129 +49,3 @@ def __getstate__(self) -> Any:
5149
def __setstate__(self, state: Any) -> None:
5250
"""Loading state from pickled data."""
5351
object.__setattr__(self, '_inner_value', state) # noqa: WPS609
54-
55-
56-
@runtime
57-
class Bindable(Protocol[_ValueType]):
58-
"""
59-
Represents a "context" in which calculations can be executed.
60-
61-
``Bindable`` allows you to bind together
62-
a series of calculations while maintaining
63-
the context of that specific container.
64-
"""
65-
66-
def bind(
67-
self, function: Callable[[_ValueType], 'Bindable[_NewValueType]'],
68-
) -> 'Bindable[_NewValueType]':
69-
"""
70-
Applies 'function' to the result of a previous calculation.
71-
72-
And returns a new container.
73-
Works for containers that represent success.
74-
Is the opposite of :meth:`Rescueable.rescue`.
75-
"""
76-
77-
78-
@runtime
79-
class Mappable(Protocol[_ValueType]):
80-
"""
81-
Allows to chain wrapped values with regular functions.
82-
83-
Behaves like functor.
84-
"""
85-
86-
def map( # noqa: A003
87-
self, function: Callable[[_ValueType], _NewValueType],
88-
) -> 'Mappable[_NewValueType]':
89-
"""
90-
Applies 'function' to the contents of the functor.
91-
92-
And returns a new functor value.
93-
Is the opposite of :meth:`Fixable.fix`.
94-
"""
95-
96-
97-
@runtime
98-
class Fixable(Protocol[_ValueType, _ErrorType]):
99-
"""Represents containers that can be fixed and rescued."""
100-
101-
def fix(
102-
self, function: Callable[[_ErrorType], _NewValueType],
103-
) -> 'Fixable[_NewValueType, _ErrorType]':
104-
"""
105-
Applies 'function' to the error and transforms failure to success.
106-
107-
And returns a new functor value.
108-
Works for containers that represent failure.
109-
Is the opposite of :meth:`Mappable.map`.
110-
"""
111-
112-
113-
@runtime
114-
class Rescueable(Protocol[_NewValueType, _ErrorType]):
115-
"""
116-
Represents a "context" in which calculations can be executed.
117-
118-
``Rescueable`` allows you to bind together
119-
a series of calculations while maintaining
120-
the context of that specific container.
121-
"""
122-
123-
def rescue(
124-
self,
125-
function: Callable[
126-
[_ErrorType], 'Rescueable[_NewValueType, _NewErrorType]',
127-
],
128-
) -> 'Rescueable[_NewValueType, _NewErrorType]':
129-
"""
130-
Applies 'function' to the result of a previous calculation.
131-
132-
And returns a new container.
133-
Works for containers that represent failure.
134-
Is the opposite of :meth:`~bind`.
135-
"""
136-
137-
138-
@runtime
139-
class Unwrapable(Protocol[_ValueType, _ErrorType]):
140-
"""Represents containers that can unwrap and return its wrapped value."""
141-
142-
def value_or(
143-
self, default_value: _NewValueType,
144-
) -> Union[_ValueType, _NewValueType]:
145-
"""Forces to unwrap value from container or return a default."""
146-
147-
def unwrap(self) -> _ValueType:
148-
"""
149-
Custom magic method to unwrap inner value from container.
150-
151-
Should be redefined for ones that actually have values.
152-
And for ones that raise an exception for no values.
153-
154-
This method is the opposite of :meth:`~failure`.
155-
"""
156-
157-
def failure(self) -> _ErrorType:
158-
"""
159-
Custom magic method to unwrap inner value from the failed container.
160-
161-
This method is the opposite of :meth:`~unwrap`.
162-
"""
163-
164-
165-
@runtime
166-
class Altable(Protocol[_ValueType, _ErrorType]):
167-
"""Allows to unwrap failures."""
168-
169-
def alt(
170-
self,
171-
function: Callable[[_ErrorType], _NewErrorType],
172-
) -> 'Fixable[_ValueType, _NewErrorType]':
173-
"""
174-
Uses 'function' to transform one error to another.
175-
176-
And returns a new functor value.
177-
Works for containers that represent failure.
178-
Is the opposite of :meth:`~map`.
179-
"""

0 commit comments

Comments
 (0)