# `tibia`
> If you ask why `tibia` is called `tibia` - i don't remember why 😄
## Containers
`tibia` provides several containers for values:
- `Value` for already computed (sync) values with **pipe operator** / **fluent**
API
- `Future` for not yet computed (async) values with **pipe operator** /
**fluent** API
- `Maybe` is well-known monad for present and non-present already competed
values with **pipe operator** / **fluent** API; provides 2 containers:
- `Some` - value is present and actually contained inside
- `Empty` - nothing is contained (something like python `None`)
- `FutureMaybe` is like `Future` for `Value`, but for `Maybe`
- `Result` is well-known monad for successful or failed contained value states
with **pipe operator** / **fluent** API; provides 2 containers:
- `Ok` - value is successfully computed
- `Err` - failed to compute value
- `FutureResult` is like `Future` for `Value`, but for `Maybe`
Also `tibia` provides some utilitarian functions for `Iterable` and `Mapping` in
pipeline-based context:
- `Iterable`
- eager
- `map` - applies passed function to each element of iterable eagerly
- `filter` - filter values in iterable with passed predicate eagerly
- `reduce` & `reduce_to` - aggregates iterable values into single value
- `sort_asc` & `sort_desc` - sort iterable values
- `take` - take first or last N values from iterable (can fail on infinite
iterable)
- `first` - take first value or default
- `skip` - skip first or last N values from iterable (can fail on infinite
iterable)
- `join` - flatten iterable of iterables into single iterable
- async (aio)
- `map` - applies passed async function to each element of iterable
- `filter` - filters elements in iterable with async predicate function
- `group_by` - groups items of iterable with passed function
- lazy
- `map` - applies passed async function to each element of iterable lazily
- `filter` - filters elements in iterable with async predicate function
lazily
- `take_while` - takes elements from iterable until predicate is true
- `skip_while` - skips elements from iterable until predicate is true
- `join` - flattens iterable of iterables lazily
- threaded
- `map` - applies passed sync function to each element of iterable in
threads
- `filter` - filters in threads elements of iterable
- `Mapping`
- value
- `map` - applies function to each value of mapping
- `filter` - filters mapping pairs based on value
- `iterate` - returns iterable of values (lazy as generator)
- `set` - set value to key
- `get` - get value by key (can raise `KeyError`)
- `get_or` - get value or passed default by key
- `maybe_get` - get value by key in `Maybe` container (`Some` if key is
present, `Empty` if not)
- key
- `map` - applies function to each key of mapping
- `filter` - filters mapping pairs based on key
- `iterate` - returns iterable of keys (lazy as generator)
- item
- `map` - maps key-value pair to new key-value pair
- `map_to_value` - maps value based on key-value pair
- `map_to_key` - maps key based on key-value pair
- `filter` - filters mapping elements based on key-value pairs
- `iterate` - returns iterable of key-value pairs (lazy as generator of
tuples)
## Value
`Value` is a simple container that brings to python so called **pipe operator**.
So how to use it? Put some concrete value to the container, for example a
number. Now instead of passing this value as an argument to a function pass a
function as some action that you want to be performed on this value:
```python
_ = (
Value(1)
.map(add, 1)
.map(multiply_by, 3)
.map(subtract, 10)
.map(multiply_by, -1)
.inspect(print)
.unwrap()
)
```
Thus we build a declarative chain of actions we perform on some piece of data.
### `Value.map`
`Value.map` is method that invokes passed function on contained value. It
supports not only single-argument functions, but actually any function with only
one requirement: **contained value must be the first argument for the
function**. Other arguments can be passed as `*args` and/or `**kwargs` to the
`Value.map` method.
So image we have a `Value[int]`. The following example function will be
completely valid for `Value.map`:
```python
# simple single-argument function, contained value will be x
def add_one(x: int) -> int:
return x + 1
# 2 argument function, contained value will be x again, and argument for y must
# be passed following the function argument to map method
def add(x: int, y: int) -> int:
return x + y
# again 2 argument function, but in this case y argument can be ommited in map
def multiply_by(x: int, y: int = 1) -> int:
return x * y
```
`Value.map` returns new `Value` container for data returned from the passed
function, thus with `Value.map` method chaining one can build pipelines on data.
`Value.map` works only with synchronous functions. For asynchronous functions
use `Value.map_async`.
### `Value.map_async`
`Value.map_async` is direct analogue of `Value.map` but for async functions.
Main difference is that instead of `Value` it returns `Future` - `tibia`s simple
container over coroutine (`Future` is discussed further, but most things valid
for `Value` are valid for `Future` and their interface are very similar).
### `Value.inspect`
`Value.inspect` has nearly the same signature as `Value.map` with only
difference: it does not wrap returned from the passed function value into new
`Value` container, but returns the current self `Value` container.
Simply this is function for making side-effects - something we want to happen,
but don't care about result. In the example above `Value.inspect` was used to
print contained in container value. `print` returns `None`, so if we've used
`Value.map` we would lost the data, but with `Value.inspect` we just performed
an action and continued working on already contained data.
Like `Value.map` can be used only with synchronous functions.
### `Value.inspect_async`
Like `Value.map_async` is analogue of `Value.map` for async function that
returns `Future` containers `Value.inspect_async` is the same for
`Value.inspect`.
### `Value.unwrap`
Method for extracting value from container if one is not further needed.
### `Value.wraps`
Decorator that changes signature of wrapped function by containing returned
value in `Value` container. For example initial signature was:
```txt
fn: (int, int, str) -> str
```
With `Value.wraps` decorator applied it becomes:
```txt
fn: (int, int, str) -> Value[str]
```
## `Future`
`Future` is direct analogue of `Value`, but for values that are not calculated
(awaited) yet. For JS developers it might be widely know as `Promise`. It has
the same as `Value` interface:
- `Future.map` & `Future.inspect` for sync functions
- `Future.map_async` & `Future.inspect_async` for async functions
- `Future.unwrap` for extracting contained value (must be awaited)
Additionally one can `await` directly `Future` without `unwrap`:
```python
_ = await future.unwrap()
# same as
_ = await future
```
This is just a shortcut, but I would generally recommend explicit unwrapping and
waiting of contained value.
## `Maybe` & `FutureMaybe`
`Maybe` is an alternative for python `Optional`. At first glance it might seem
that it is not needed, but it provides to apply functions without checks on
emptiness and also can consider `None` as actual value.
It consists of 2 containers:
- `Some` - indicates that value is present (even if one is `None`)
- `Empty` - indicates that there is no value
For example let's imagine one is creating data structure for updating some data
(for example table in DB). Naive approach would be to create some class with
all-optional fields:
```python
class UpdateUser:
first_name: str | None = None
second_name: str | None = None
birthdate: datetime | None = None
```
Imagine that `birthdate` is nullable in table we want to update. If we get this
structure with `None` in `birthdate` field we cannot determine whether we want
to set it to `null` or we do not want to perform any update on this column.
With `Maybe` this problem goes away. `Empty` state tells us that we do not want
to perform action and `Some` unambiguously tells us that we want to set column
to contained value:
```python
class UpdateUser:
first_name: Maybe[str] = Empty()
second_name: Maybe[str] = Empty()
birthdate: Maybe[datetime | None] = Empty()
```
With this approach it is much more clear what each value means and what is valid
state.
### Piping API
For making pipelines `Maybe` & `FutureMaybe` like `Value` & `Future` provide the
following methods:
- `map` / `map_async` - apply contained value to function if one is present and
wrap result into `Some`
- `map_or` / `map_or_async` - apply contained value to function if one is
present and return result of function directly or replace it with passed
default value
- `inspect` / `inspect_async` - apply function as side-effect if value is
present ignoring result of passed function and return current container
Imagine we apply function that returns `R`:
| Container | Method | Returns |
| --------- | --------------- | ------------------------ |
| `Ok[T]` | `map` | `Ok[R]` |
| `Ok[T]` | `map_async` | `FutureMaybe(Ok[R])` |
| `Empty` | `map` | `Empty` |
| `Empty` | `map_async` | `FutureMaybe(Empty)` |
| `Ok[T]` | `map_or` | `R` |
| `Ok[T]` | `map_or_async` | `Future[R]` |
| `Empty` | `map_or` | `R` from default |
| `Empty` | `map_or_async` | `Future[R]` from default |
| `Ok[T]` | `inspect` | `Ok[T]` |
| `Ok[T]` | `inspect_async` | `FutureMaybe(Ok[T])` |
| `Empty` | `inspect` | `Empty` |
| `Empty` | `inspect_async` | `FutureMaybe(Empty)` |
Mainly one would use `map` and `map_async` to perform desired actions without
thinking if value is present, some side-effect functions (for debugging for
example) with `inspect` & `inspect_async` and than unwrap value with `map_or` or
`map_or_async` methods (or via Unwrapping API).
### Unwrapping API
In order to extract value from container one can use one of the following
methods:
- `expect`
- if `Some`: return contained value
- if `Empty`: raise `ValueError` with passed error message
- `unwrap` - same as `expect`, but uses built-in error message `"must be some"`
- `unwrap_or`
- if `Some`: return contained value
- if `Empty`: return passed default value
- `unwrap_or_none`
- if `Some`: return contained value
- if `Empty`: return `None`
### Logical API
In order to check / validate contained value on can use following methods:
- `is_some` - `True` if container is `Some`, otherwise `False`
- `is_empty` - `True` if container is `Empty`, otherwise `False`
- `is_some_and` - `True` if container is `Some` and passed predicate is `True`
(function that checks contained value), otherwise `False`
- `is_empty_or` - `True` if container is `Empty` or passed predicate is `True`
(function that check contained in `Some` value), otherwise `False`
For example imagine we have `is_even` predicate:
| Container | Method | Returns |
| --------- | ------------- | ------- |
| `Ok(2)` | `is_some_and` | `True` |
| `Ok(1)` | `is_some_and` | `False` |
| `Empty()` | `is_some_and` | `False` |
| `Ok(1)` | `is_empty_or` | `False` |
| `Ok(2)` | `is_empty_or` | `True` |
| `Empty()` | `is_empty_or` | `True` |
`is_some_and` & `is_empty_or` methods also have `is_some_and_async` &
`is_empty_or_async` alternatives for async predicates, as base versions work
only with sync functions. Async alternatives return `Future[bool]` for further
piping if needed.
### Construction API
There are a few static function in `Maybe` class used for constructing `Maybe`
containers:
- `Maybe.from_value` - always wraps value into `Some`
- `Maybe.from_value_when` - wraps value into `Some` if value satisfies passed
predicate, otherwise `Empty`
- `Maybe.from_optional` - wraps value into `Some` if one is not `None`,
otherwise `Empty`
- `Maybe.from_optional_when` - wraps value into `Some` if value is not `None`
and satisfies passed predicate , otherwise `Empty`
### Decorator API
Based on `from_value` and `from_optional` `Maybe` provides 2 decorators for
functions:
- `wraps` - wraps returned from function value via `Maybe.from_value`
- `safe` - wraps returned from function value via `Maybe.from_optional`
> One might also find `Maybe.wraps` & `Maybe.wraps_optional` static methods, but
> they are deprecated and not intended to be used.
### Point-free API
All discussed above methods can also be used as functions contained in
`tibia.maybe` module. They can be found useful when working with iterables of
`Maybe` for example (for massive filtering and unwrapping without loosing type
hints).
---
`FutureMaybe` provides exactly the same API, but for "futurized" `Maybe` value.
## `Result` & `FutureResult`
`Result` & `FutureResult` monads provide the ability for indicating computation
success and error states without implicit error raises. Yes, yes, raising errors
is actually implicit way, that highly resembles to `goto` operator widely
forbidden or not implemented for increasing code complexity exponentially. With
`Result` one does not raise exception, but explicitly returns it (like Rust and
Go do for example).
It consists of 2 containers:
- `Ok` - indicates successful result
- `Err` - indicates failed result
Both of the containers store some value, `Ok` - what was actually computed,
`Err` - some error representation (not always `Exception`).
### Piping API <!--noqa: MD024-->
It is a bit extended relative to `Maybe` or `Value` and consist of the following
methods:
- `map` / `map_async` - mapping for `Ok` container
- `map_err` / `map_err_async` - mapping for `Err` container
- `map_or` / `map_or_async` - mapping and unwrapping for `Ok` container
- `map_err_or` / `map_err_or_async` - mapping and unwrapping for `Err` container
- `inspect` / `inspect_async` - applying side-effect function for `Ok` container
- `inspect_err` / `inspect_err_async` - applying side-effect function for `Err`
container
### Unwrapping API <!--noqa: MD024-->
Also provides more options for unwrapping both containers:
- `expect`
- `Ok` - returns container value
- `Err` - raises `ValueError` with passed error message
- `unwrap`
- `Ok` - returns container value
- `Err` - raises `ValueError` with default error message `"must be ok"`
- `unwrap_or`
- `Ok` - returns container value
- `Err` - returns passed default value
- `expect_err`
- `Ok` - raises `ValueError` with passed error message
- `Err` - returns container value
- `unwrap_err`
- `Ok` - raises `ValueError` with default error message `"must be err"`
- `Err` - returns container value
- `unwrap_err_or`
- `Ok` - returns passed default value
- `Err` - returns container value
### Logical API <!--noqa: MD024-->
Many more options for validating containers and values:
- `is_ok` - `True` if `Ok`, otherwise `False`
- `is_ok_and` / `is_ok_and_async` - `True` if `Ok` and contained value satisfies
passed predicate, otherwise `False` (returns `Future[bool]` for async version)
- `is_ok_or` / `is_ok_or` - `True` if `Ok` or `Err` contained value satisfies
passed predicate, otherwise `False` (returns `Future[bool]` for async version)
- `is_err_` - `True` if `Err`, otherwise `False`
- `is_err__and` / `is_err__and_async` - `True` if `Err` and contained value satisfies
passed predicate, otherwise `False` (returns `Future[bool]` for async version)
- `is_err__or` / `is_err__or` - `True` if `Err` or `Ok` contained value satisfies
passed predicate, otherwise `False` (returns `Future[bool]` for async version)
### Decorator API <!--noqa: MD024-->
Provides 2 decorators:
- `wraps` - simply always returns `Ok`-wrapped function result
- `safe` - `try-excepts` `Exception` and returns `Ok` if `Exception` was not
raised, otherwise wraps `Exception` into `Err`
- `safe_from` - same as `safe` but firstly it excepts a tuple of `Exception`
types to be excepted in `try-except` block
> One might also find `Result.wraps` & `Result.safe` static methods, but they
> are deprecated and not intended to be used.
### Point-free API <!--noqa: MD024-->
Same as `Maybe`, `Result` provides simple functions that can replace any method.
---
`ResultMaybe` provides exactly the same API, but for "futurized" `Result` value.
Raw data
{
"_id": null,
"home_page": "https://github.com/katunilya/tibia",
"name": "tibia",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.12",
"maintainer_email": null,
"keywords": "monad, functional, pipeline, rust",
"author": "Ilya Katun",
"author_email": "katun.ilya@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/02/6b/db1b633281be6be547aea39f7739276a9b6ace7ba6974b58d67eb5d70145/tibia-2.2.0.tar.gz",
"platform": null,
"description": "# `tibia`\n\n> If you ask why `tibia` is called `tibia` - i don't remember why \ud83d\ude04\n\n## Containers\n\n`tibia` provides several containers for values:\n\n- `Value` for already computed (sync) values with **pipe operator** / **fluent**\n API\n- `Future` for not yet computed (async) values with **pipe operator** /\n **fluent** API\n- `Maybe` is well-known monad for present and non-present already competed\n values with **pipe operator** / **fluent** API; provides 2 containers:\n - `Some` - value is present and actually contained inside\n - `Empty` - nothing is contained (something like python `None`)\n- `FutureMaybe` is like `Future` for `Value`, but for `Maybe`\n- `Result` is well-known monad for successful or failed contained value states\n with **pipe operator** / **fluent** API; provides 2 containers:\n - `Ok` - value is successfully computed\n - `Err` - failed to compute value\n- `FutureResult` is like `Future` for `Value`, but for `Maybe`\n\nAlso `tibia` provides some utilitarian functions for `Iterable` and `Mapping` in\npipeline-based context:\n\n- `Iterable`\n - eager\n - `map` - applies passed function to each element of iterable eagerly\n - `filter` - filter values in iterable with passed predicate eagerly\n - `reduce` & `reduce_to` - aggregates iterable values into single value\n - `sort_asc` & `sort_desc` - sort iterable values\n - `take` - take first or last N values from iterable (can fail on infinite\n iterable)\n - `first` - take first value or default\n - `skip` - skip first or last N values from iterable (can fail on infinite\n iterable)\n - `join` - flatten iterable of iterables into single iterable\n - async (aio)\n - `map` - applies passed async function to each element of iterable\n - `filter` - filters elements in iterable with async predicate function\n - `group_by` - groups items of iterable with passed function\n - lazy\n - `map` - applies passed async function to each element of iterable lazily\n - `filter` - filters elements in iterable with async predicate function\n lazily\n - `take_while` - takes elements from iterable until predicate is true\n - `skip_while` - skips elements from iterable until predicate is true\n - `join` - flattens iterable of iterables lazily\n - threaded\n - `map` - applies passed sync function to each element of iterable in\n threads\n - `filter` - filters in threads elements of iterable\n- `Mapping`\n - value\n - `map` - applies function to each value of mapping\n - `filter` - filters mapping pairs based on value\n - `iterate` - returns iterable of values (lazy as generator)\n - `set` - set value to key\n - `get` - get value by key (can raise `KeyError`)\n - `get_or` - get value or passed default by key\n - `maybe_get` - get value by key in `Maybe` container (`Some` if key is\n present, `Empty` if not)\n - key\n - `map` - applies function to each key of mapping\n - `filter` - filters mapping pairs based on key\n - `iterate` - returns iterable of keys (lazy as generator)\n - item\n - `map` - maps key-value pair to new key-value pair\n - `map_to_value` - maps value based on key-value pair\n - `map_to_key` - maps key based on key-value pair\n - `filter` - filters mapping elements based on key-value pairs\n - `iterate` - returns iterable of key-value pairs (lazy as generator of\n tuples)\n\n## Value\n\n`Value` is a simple container that brings to python so called **pipe operator**.\n\nSo how to use it? Put some concrete value to the container, for example a\nnumber. Now instead of passing this value as an argument to a function pass a\nfunction as some action that you want to be performed on this value:\n\n```python\n_ = (\n Value(1)\n .map(add, 1)\n .map(multiply_by, 3)\n .map(subtract, 10)\n .map(multiply_by, -1)\n .inspect(print)\n .unwrap()\n)\n```\n\nThus we build a declarative chain of actions we perform on some piece of data.\n\n### `Value.map`\n\n`Value.map` is method that invokes passed function on contained value. It\nsupports not only single-argument functions, but actually any function with only\none requirement: **contained value must be the first argument for the\nfunction**. Other arguments can be passed as `*args` and/or `**kwargs` to the\n`Value.map` method.\n\nSo image we have a `Value[int]`. The following example function will be\ncompletely valid for `Value.map`:\n\n```python\n# simple single-argument function, contained value will be x\ndef add_one(x: int) -> int:\n return x + 1\n\n# 2 argument function, contained value will be x again, and argument for y must\n# be passed following the function argument to map method\ndef add(x: int, y: int) -> int:\n return x + y\n\n# again 2 argument function, but in this case y argument can be ommited in map\ndef multiply_by(x: int, y: int = 1) -> int:\n return x * y\n```\n\n`Value.map` returns new `Value` container for data returned from the passed\nfunction, thus with `Value.map` method chaining one can build pipelines on data.\n\n`Value.map` works only with synchronous functions. For asynchronous functions\nuse `Value.map_async`.\n\n### `Value.map_async`\n\n`Value.map_async` is direct analogue of `Value.map` but for async functions.\nMain difference is that instead of `Value` it returns `Future` - `tibia`s simple\ncontainer over coroutine (`Future` is discussed further, but most things valid\nfor `Value` are valid for `Future` and their interface are very similar).\n\n### `Value.inspect`\n\n`Value.inspect` has nearly the same signature as `Value.map` with only\ndifference: it does not wrap returned from the passed function value into new\n`Value` container, but returns the current self `Value` container.\n\nSimply this is function for making side-effects - something we want to happen,\nbut don't care about result. In the example above `Value.inspect` was used to\nprint contained in container value. `print` returns `None`, so if we've used\n`Value.map` we would lost the data, but with `Value.inspect` we just performed\nan action and continued working on already contained data.\n\nLike `Value.map` can be used only with synchronous functions.\n\n### `Value.inspect_async`\n\nLike `Value.map_async` is analogue of `Value.map` for async function that\nreturns `Future` containers `Value.inspect_async` is the same for\n`Value.inspect`.\n\n### `Value.unwrap`\n\nMethod for extracting value from container if one is not further needed.\n\n### `Value.wraps`\n\nDecorator that changes signature of wrapped function by containing returned\nvalue in `Value` container. For example initial signature was:\n\n```txt\nfn: (int, int, str) -> str\n```\n\nWith `Value.wraps` decorator applied it becomes:\n\n```txt\nfn: (int, int, str) -> Value[str]\n```\n\n## `Future`\n\n`Future` is direct analogue of `Value`, but for values that are not calculated\n(awaited) yet. For JS developers it might be widely know as `Promise`. It has\nthe same as `Value` interface:\n\n- `Future.map` & `Future.inspect` for sync functions\n- `Future.map_async` & `Future.inspect_async` for async functions\n- `Future.unwrap` for extracting contained value (must be awaited)\n\nAdditionally one can `await` directly `Future` without `unwrap`:\n\n```python\n_ = await future.unwrap()\n\n# same as\n\n_ = await future\n```\n\nThis is just a shortcut, but I would generally recommend explicit unwrapping and\nwaiting of contained value.\n\n## `Maybe` & `FutureMaybe`\n\n`Maybe` is an alternative for python `Optional`. At first glance it might seem\nthat it is not needed, but it provides to apply functions without checks on\nemptiness and also can consider `None` as actual value.\n\nIt consists of 2 containers:\n\n- `Some` - indicates that value is present (even if one is `None`)\n- `Empty` - indicates that there is no value\n\nFor example let's imagine one is creating data structure for updating some data\n(for example table in DB). Naive approach would be to create some class with\nall-optional fields:\n\n```python\nclass UpdateUser:\n first_name: str | None = None\n second_name: str | None = None\n birthdate: datetime | None = None\n```\n\nImagine that `birthdate` is nullable in table we want to update. If we get this\nstructure with `None` in `birthdate` field we cannot determine whether we want\nto set it to `null` or we do not want to perform any update on this column.\n\nWith `Maybe` this problem goes away. `Empty` state tells us that we do not want\nto perform action and `Some` unambiguously tells us that we want to set column\nto contained value:\n\n```python\nclass UpdateUser:\n first_name: Maybe[str] = Empty()\n second_name: Maybe[str] = Empty()\n birthdate: Maybe[datetime | None] = Empty()\n```\n\nWith this approach it is much more clear what each value means and what is valid\nstate.\n\n### Piping API\n\nFor making pipelines `Maybe` & `FutureMaybe` like `Value` & `Future` provide the\nfollowing methods:\n\n- `map` / `map_async` - apply contained value to function if one is present and\n wrap result into `Some`\n- `map_or` / `map_or_async` - apply contained value to function if one is\n present and return result of function directly or replace it with passed\n default value\n- `inspect` / `inspect_async` - apply function as side-effect if value is\n present ignoring result of passed function and return current container\n\nImagine we apply function that returns `R`:\n\n| Container | Method | Returns |\n| --------- | --------------- | ------------------------ |\n| `Ok[T]` | `map` | `Ok[R]` |\n| `Ok[T]` | `map_async` | `FutureMaybe(Ok[R])` |\n| `Empty` | `map` | `Empty` |\n| `Empty` | `map_async` | `FutureMaybe(Empty)` |\n| `Ok[T]` | `map_or` | `R` |\n| `Ok[T]` | `map_or_async` | `Future[R]` |\n| `Empty` | `map_or` | `R` from default |\n| `Empty` | `map_or_async` | `Future[R]` from default |\n| `Ok[T]` | `inspect` | `Ok[T]` |\n| `Ok[T]` | `inspect_async` | `FutureMaybe(Ok[T])` |\n| `Empty` | `inspect` | `Empty` |\n| `Empty` | `inspect_async` | `FutureMaybe(Empty)` |\n\nMainly one would use `map` and `map_async` to perform desired actions without\nthinking if value is present, some side-effect functions (for debugging for\nexample) with `inspect` & `inspect_async` and than unwrap value with `map_or` or\n`map_or_async` methods (or via Unwrapping API).\n\n### Unwrapping API\n\nIn order to extract value from container one can use one of the following\nmethods:\n\n- `expect`\n - if `Some`: return contained value\n - if `Empty`: raise `ValueError` with passed error message\n- `unwrap` - same as `expect`, but uses built-in error message `\"must be some\"`\n- `unwrap_or`\n - if `Some`: return contained value\n - if `Empty`: return passed default value\n- `unwrap_or_none`\n - if `Some`: return contained value\n - if `Empty`: return `None`\n\n### Logical API\n\nIn order to check / validate contained value on can use following methods:\n\n- `is_some` - `True` if container is `Some`, otherwise `False`\n- `is_empty` - `True` if container is `Empty`, otherwise `False`\n- `is_some_and` - `True` if container is `Some` and passed predicate is `True`\n (function that checks contained value), otherwise `False`\n- `is_empty_or` - `True` if container is `Empty` or passed predicate is `True`\n (function that check contained in `Some` value), otherwise `False`\n\nFor example imagine we have `is_even` predicate:\n\n| Container | Method | Returns |\n| --------- | ------------- | ------- |\n| `Ok(2)` | `is_some_and` | `True` |\n| `Ok(1)` | `is_some_and` | `False` |\n| `Empty()` | `is_some_and` | `False` |\n| `Ok(1)` | `is_empty_or` | `False` |\n| `Ok(2)` | `is_empty_or` | `True` |\n| `Empty()` | `is_empty_or` | `True` |\n\n`is_some_and` & `is_empty_or` methods also have `is_some_and_async` &\n`is_empty_or_async` alternatives for async predicates, as base versions work\nonly with sync functions. Async alternatives return `Future[bool]` for further\npiping if needed.\n\n### Construction API\n\nThere are a few static function in `Maybe` class used for constructing `Maybe`\ncontainers:\n\n- `Maybe.from_value` - always wraps value into `Some`\n- `Maybe.from_value_when` - wraps value into `Some` if value satisfies passed\n predicate, otherwise `Empty`\n- `Maybe.from_optional` - wraps value into `Some` if one is not `None`,\n otherwise `Empty`\n- `Maybe.from_optional_when` - wraps value into `Some` if value is not `None`\n and satisfies passed predicate , otherwise `Empty`\n\n### Decorator API\n\nBased on `from_value` and `from_optional` `Maybe` provides 2 decorators for\nfunctions:\n\n- `wraps` - wraps returned from function value via `Maybe.from_value`\n- `safe` - wraps returned from function value via `Maybe.from_optional`\n\n> One might also find `Maybe.wraps` & `Maybe.wraps_optional` static methods, but\n> they are deprecated and not intended to be used.\n\n### Point-free API\n\nAll discussed above methods can also be used as functions contained in\n`tibia.maybe` module. They can be found useful when working with iterables of\n`Maybe` for example (for massive filtering and unwrapping without loosing type\nhints).\n\n---\n\n`FutureMaybe` provides exactly the same API, but for \"futurized\" `Maybe` value.\n\n## `Result` & `FutureResult`\n\n`Result` & `FutureResult` monads provide the ability for indicating computation\nsuccess and error states without implicit error raises. Yes, yes, raising errors\nis actually implicit way, that highly resembles to `goto` operator widely\nforbidden or not implemented for increasing code complexity exponentially. With\n`Result` one does not raise exception, but explicitly returns it (like Rust and\nGo do for example).\n\nIt consists of 2 containers:\n\n- `Ok` - indicates successful result\n- `Err` - indicates failed result\n\nBoth of the containers store some value, `Ok` - what was actually computed,\n`Err` - some error representation (not always `Exception`).\n\n### Piping API <!--noqa: MD024-->\n\nIt is a bit extended relative to `Maybe` or `Value` and consist of the following\nmethods:\n\n- `map` / `map_async` - mapping for `Ok` container\n- `map_err` / `map_err_async` - mapping for `Err` container\n- `map_or` / `map_or_async` - mapping and unwrapping for `Ok` container\n- `map_err_or` / `map_err_or_async` - mapping and unwrapping for `Err` container\n- `inspect` / `inspect_async` - applying side-effect function for `Ok` container\n- `inspect_err` / `inspect_err_async` - applying side-effect function for `Err`\n container\n\n### Unwrapping API <!--noqa: MD024-->\n\nAlso provides more options for unwrapping both containers:\n\n- `expect`\n - `Ok` - returns container value\n - `Err` - raises `ValueError` with passed error message\n- `unwrap`\n - `Ok` - returns container value\n - `Err` - raises `ValueError` with default error message `\"must be ok\"`\n- `unwrap_or`\n - `Ok` - returns container value\n - `Err` - returns passed default value\n- `expect_err`\n - `Ok` - raises `ValueError` with passed error message\n - `Err` - returns container value\n- `unwrap_err`\n - `Ok` - raises `ValueError` with default error message `\"must be err\"`\n - `Err` - returns container value\n- `unwrap_err_or`\n - `Ok` - returns passed default value\n - `Err` - returns container value\n\n### Logical API <!--noqa: MD024-->\n\nMany more options for validating containers and values:\n\n- `is_ok` - `True` if `Ok`, otherwise `False`\n- `is_ok_and` / `is_ok_and_async` - `True` if `Ok` and contained value satisfies\n passed predicate, otherwise `False` (returns `Future[bool]` for async version)\n- `is_ok_or` / `is_ok_or` - `True` if `Ok` or `Err` contained value satisfies\n passed predicate, otherwise `False` (returns `Future[bool]` for async version)\n- `is_err_` - `True` if `Err`, otherwise `False`\n- `is_err__and` / `is_err__and_async` - `True` if `Err` and contained value satisfies\n passed predicate, otherwise `False` (returns `Future[bool]` for async version)\n- `is_err__or` / `is_err__or` - `True` if `Err` or `Ok` contained value satisfies\n passed predicate, otherwise `False` (returns `Future[bool]` for async version)\n\n### Decorator API <!--noqa: MD024-->\n\nProvides 2 decorators:\n\n- `wraps` - simply always returns `Ok`-wrapped function result\n- `safe` - `try-excepts` `Exception` and returns `Ok` if `Exception` was not\n raised, otherwise wraps `Exception` into `Err`\n- `safe_from` - same as `safe` but firstly it excepts a tuple of `Exception`\n types to be excepted in `try-except` block\n\n> One might also find `Result.wraps` & `Result.safe` static methods, but they\n> are deprecated and not intended to be used.\n\n### Point-free API <!--noqa: MD024-->\n\nSame as `Maybe`, `Result` provides simple functions that can replace any method.\n\n---\n\n`ResultMaybe` provides exactly the same API, but for \"futurized\" `Result` value.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Monads in python for pipeline-based development with Rust-like interface",
"version": "2.2.0",
"project_urls": {
"Homepage": "https://github.com/katunilya/tibia",
"Repository": "https://github.com/katunilya/tibia"
},
"split_keywords": [
"monad",
" functional",
" pipeline",
" rust"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "68bb91c0e68b30ef4b56b729e7f69d5f41c6c09e7280c35f9dfe2550ccf21c23",
"md5": "5d4cc70830de4150771d94a188d96eae",
"sha256": "8965f84e91c4c2ec373afede57ffdabd37ba77a58f0f9abbbd5fe46fe05386d4"
},
"downloads": -1,
"filename": "tibia-2.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5d4cc70830de4150771d94a188d96eae",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.12",
"size": 19643,
"upload_time": "2024-12-29T08:37:56",
"upload_time_iso_8601": "2024-12-29T08:37:56.920416Z",
"url": "https://files.pythonhosted.org/packages/68/bb/91c0e68b30ef4b56b729e7f69d5f41c6c09e7280c35f9dfe2550ccf21c23/tibia-2.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "026bdb1b633281be6be547aea39f7739276a9b6ace7ba6974b58d67eb5d70145",
"md5": "4e1f925b4f4c9e9c6390bbdf576cdb96",
"sha256": "6d994e2b9c5ba83716231cb90a3478dbadeb91c6a48d0490e11819260cdcb379"
},
"downloads": -1,
"filename": "tibia-2.2.0.tar.gz",
"has_sig": false,
"md5_digest": "4e1f925b4f4c9e9c6390bbdf576cdb96",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.12",
"size": 19680,
"upload_time": "2024-12-29T08:38:00",
"upload_time_iso_8601": "2024-12-29T08:38:00.599053Z",
"url": "https://files.pythonhosted.org/packages/02/6b/db1b633281be6be547aea39f7739276a9b6ace7ba6974b58d67eb5d70145/tibia-2.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-29 08:38:00",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "katunilya",
"github_project": "tibia",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "tibia"
}