Put your functions returns in a pot, please.
🍴 forked from https://github.com/dry-python/returns
💡 Insired by https://github.com/dbrattli/OSlash
- Provides an initial functional programming monads to Python land;
- Fully typed with annotations and checked with
mypy
;
If you are using pip you can: pip install tupperware
.
Otherwise, if you are using poetry you can: poetry add tupperware
or add this to your pyproject.tml
:
[tool.poetry.dependencies]
tupperware = { git = "https://github.com/flpStrri/tupperware.git", tag = "v0.1.0" }
We also recommend to use the same mypy
settings we use.
If you want to help us building Tupperware, please start at our CONTRIBUTING and CODE_OF_CONDUCT documents.
- Maybe container that allows you to write
None
-free code - Either container that let's you to get rid of exceptions
The Maybe
type encapsulates an optional value.
Its content can be a value (represented as <Just a>
),
or it is empty (represented as <Nothing>
).
This way you can map functions inside your value without having to test it
explicitly (since the Maybe class will do it) every time it can return a None
like in one of this class tests
from functools import partial
from operator import add
from typing import Callable, Mapping, Optional
from tupperware.maybe import Just, Nothing
just_boris = Just({"name": "Boris"})
get_age: Callable[[Mapping], Optional[int]] = (
lambda mapping: mapping.get("age")
)
assert (
just_boris
.map(get_age)
.map(partial(add, 1))
) == Nothing()
The Either
type encapsulates a successful or failed computation.
Its content can be a successful computation value (represented as <Right a>
),
or a a failed computation value (represented as <Left a>
).
This way you can map and bind computations and have two different paths, errors
on the left and successful mapping and binding on the right as on this class tests
from random import choice
from typing import Callable
from tupperware.either import Either, Left, Right
# Should return <Right 2> when binding to a <Right 1>
# given a function returning Right:
right_one = Right(1)
right_add_one: Callable[[int], Either[int, int]] = (
lambda to_sum: Right(to_sum + 1)
)
assert right_one.bind(right_add_one) == Right(2)
assert right_one | right_add_one == Right(2)
# Should return <Left 1> when binding to a <Left 1>
# given any right typed function:
left_one = Left(1)
add_one: Callable[[int], Either[int, int]] = (
lambda to_sum: choice(
[Right(to_sum + 1), Left(to_sum + 1)]
)
)
assert left_one.bind(add_one) == left_one
assert left_one | add_one == left_one
— ⚜️️ —
A blameless life, St. Joseph, may we lead; by your patronage from danger freed.