Package: fateful
fatefulOptionandResultcontainer for pythondocumentation:https://jerkos.github.io/fateful/Python has some great functional features. The most notable ones are list / dict
comprehensions. However, when you start to chain function calls (or predicate
or whatever), it becomes rapidly a pain.In some famous languages, we haveOptionandResultmonad helping user to handle
optional values (i.e. None values) and possibly failing computation (Rust, Java, Kotlin...)So, this very small Python library implements those monads - Option, Result or AsyncResult -
providing a way to handle optional values / computation failures in a functional style.A focus has been made to typing (but can still be improved of course !)Installationpipinstallfateful

pipinstallfateful[http]# install aiohttp to enable async api calls helperpipinstallfateful[orjson]# install orjson a fast json implementationpipinstallfateful[all]# install all optional dependenciesOption monadThe Option Monad, also known as the Maybe Monad, is a concept from functional programming that provides
a way to handle optional values in a more controlled and expressive manner. It helps avoid null or
undefined errors by encapsulating a value that may or may not be present. The key idea behind the
Option Monad is to provide a container that can either hold a value (Some) or indicate the absence
of a value (None).The Option Monad offers several benefits, including:Safety: It helps prevent null or undefined errors that can occur when working with optional values.Clarity: It makes the presence or absence of a value explicit, enhancing the readability of code.Composability: It allows for chaining operations on optional values without explicitly checking for
null or undefined values.Functional style: It promotes functional programming principles by encouraging pure functions and
immutability.When you do not know if a value is None or is actually a real value / object, useoptto wrap it into an optionfromfatefulimportopt,Null,Some# Null is a singleton which is basically Empty(None)>>>opt('value').or_('new value')value>>>opt('value').or_else(lambda:'another value)value>>>Null.or_else(lambda:'new value')newvalue>>>opt(None).get()# same as none.get()Traceback(mostrecentcalllast):...ValueError:OptionisemptyOption monad implements the iteration protocl>>>o=opt([1,2,3]).for_each(print)[1,2,3]>>>a=opt('optional option value')>>>foriina:>>>print(i)optionaloptionvalueIt supports also forwarding a value>>># forwarding value>>>classA(object):def__init__(self,x):self.x=xdefget_x(self):returnself.x>>>opt(A(1)).get_x().or_(0)1>>>opt(A(1)).get_y().or_(0)0A option value can be transformed into another enabling chaining operationfromfateful.monad.optionimportoptionresult=option("some").map(lambdax:len(x)*2).or_(0)An option can contain another option type but can be flattenedx=option(option(option(1))).flatten()# x is Some[Some[Some[int]]]y:Some[Some[Some[int]]]=Some(Some(Some(1)))x:Some[int]=Some(Some(Some(1))).flatten()We can lift an function to return anoptiontype using a decoratorfromfateful.monad.optionimportlift_option@lift_optiondefmaybe(value:int):ifvalue>=2:return2returnNonex:Some[int]=maybe(2)x:Empty=maybe(0)Result monadThe Result Monad is another concept from functional programming that is used to handle computations
that may produce a successful result or a failure. It provides a way to encapsulate the outcome of
an operation, allowing you to handle and propagate errors in a controlled manner.The Result Monad typically has two possible states: Ok (representing a successful result) and Err
(representing a failure or an error condition). The Ok state contains the successful result value,
while the Err state contains information about the failure, such as an error message or an error object.The Result Monad offers several benefits:Explicit error handling: It makes error handling explicit and separates the handling of successful results from error conditions.Propagation of errors: It allows errors to be easily propagated through a chain of operations, avoiding the need for explicit error-checking at each step.Composition: It enables the chaining and composition of operations on results in a concise and expressive manner.Error recovery: It provides mechanisms to handle and recover from errors, such as by mapping to alternative values or applying fallback strategies.defmay_fail(x:int)->float:return1/xfromfateful.monad.resutimportsync_tryr:Ok[float]|Err[ZeroDivisionError]=sync_try(may_fail,ZeroDivisionError)(1)result=sync_try(may_fail,ZeroDivisionError)(1).or_(10.0)assertresult==1.0result=sync_try(may_fail,ZeroDivisonError)(0).or_(10.0)assertresult==10.0Async ResultAsync result provides exactly same functionalites than regular Result monadasyncdefdivide_async(a,b):awaitasyncio.sleep(0.1)returna/bfromfateful.monadimportasync_tryvalue=awaitasync_try(add_async)(1,1).or_else(lambda:4)value=awaitasync_try(add_async)(1,1).or_(4)divide:AsyncResult[...,float,ZeroDivisionError]=async_try(add_async,ZeroDivisionError)(1,1)result:Ok[float]|Err[ZeroDivisionError]=awaitdivide..execute()# transforming valuevalue=awaitdivide.map(lambdar:r-100).or_(0)match(awaitdivide.execute()):caseOk(val):returnvalcaseErr(err):raiseerrcase_:raiseTypeError("Never supposed to happen")Http moduleMiscellaneous functions dealing with http client functionsWraps aiohttp for perform http call and parsing results optionnaly as jsonaiohttpis a library of choice for making http requests. A good alternative ishttpxbut various benchmarks show that it is slightly slower.page_content:str=awaittry_get("http://google.com").or_raise()Container moduleSimple subclass to return option monad when getting values
implementation of list and dictx=opt_list([1,2,3])v:Some[int]=x.at(0)v:Empty=x.at(12)Json moduleMiscellaneous functions dealing with json (parsing, manipulating...)>>>fromfateful.jsonimportopt_dict>>>i=opt_dict({'z-index':1000})>>>i.toto=[4,5,6]>>>str(i)'{"z-index": 1000, "toto": [4, 5, 6]}'Notes: I found some python packages doing almost the same things. I did
this essentially to learn and wanted to keep it simple.LicensesMIT