Skip to main content

TangledHub Result

Project description

License Build Coverage

thresult

Overview

TangledHub library for handling returned values from functions/methods and handling errors.

Licencing

thresult is licensed under the BSD license. Check the LICENSE file for details

Installation

pip install thresult

Testing

docker-compose build thresult-test ; docker-compose run --rm thresult-test

Building

docker-compose build thresult-build ; docker-compose run --rm thresult-build

Publish

docker-compose build thresult-publish ; docker-compose run --rm -e PYPI_USERNAME=__token__ -e PYPI_PASSWORD=__SECRET__ thresult-publish

Run examples from Docker

docker run -it -v $PWD/examples:/code -v $PWD:/deps/thresult -e PYTHONPATH=/deps python:3.10 /bin/bash
cd /code
python -B traceback_0.py
python -B traceback_1.py
python -B traceback_2.py
python -B traceback_3.py

Usage

thresult provides type system for handling values and exceptions in Python. Expressions can return value of type Result and variables can hold value of type Result. Result can be Ok or Err. Ok type has attribute v and Err type has attribute e. If some expression doesn't rise exception, it will return Ok type where v attribute will be result of expression. If error occurs, Err type will be returned, and e attribute of that type will contain error message. Custom types can be created, and they must extend Result, Ok or Err type.

Example when returned value is Ok type

from thresult import Result, Ok, Err

def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res

r: Result = f(1.0, 20.0) # r is Ok[<class 'float'>] object

Example when returned value is Err type

from thresult import Result, Ok, Err

def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)

    return res

# divide with 0.0 will not rise exception,
# object type Err[<class 'Exception'>] is returned
r: Result = f(1.0, 0.0) # r is Err[<class 'Exception'>] object

To obtain a value from Ok or Err type

  • structural pattern matching
  • unwrap()
  • unwrap_value()
  • unwrap_or(v: Any)

There are different ways to handle exceptions

Obtain a value from Ok or Err type with structural pattern matching

from thresult import Result, Ok, Err

def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


r: Result = f(1.0, 0.0)

match r:
    case Ok(v):
        print('Ok, value: ', v)
    case Err(e):
        print('Err, error: ', e) # float division by zero

Using structural pattern matching to handle exceptions.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


match f(1.0, 0.0):
    case Ok(v):
        print('Ok, value: ', v)
    case Err(e):
        print('Err, error: ', e) # float division by zero

Using unwrap to handle exceptions. In case of error, exception is thrown.

from thresult import Result, Ok, Err

def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res

r: Result = f(1.0, 0.0)
z: float = r.unwrap() # ZeroDivisionError: float division by zero

Using unwrap_value to handle exceptions. In case of error, unwrap_value returns error message and doesn't terminate program.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


r: Result = f(1.0, 0.0)
v: str = r.unwrap_value()
# v will contain error message, float division by zero

Using unwrap_or to handle exceptions. In case of error, unwrap_or returns value passed as argument and doesn't terminate program. In this example it is 0.0.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


r: Result = f(1.0, 0.0)
v: float = r.unwrap_or(0.0)
# v will contain value 0.0

Obtain a value from Ok type using structural pattern matching.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


r: Result = f(1.0, 10.0)

match r:
    case Ok(v):
        # v holds value of division operation - 0.1
        print('Ok, value: ', v)
    case Err(e):
        print('Err, error: ', e)

Obtain a value from Ok type using structural pattern matching.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


match f(1.0, 10.0):
    case Ok(v):
        # v holds value of division operation - 0.1
        print('Ok, value: ', v)
    case Err(e):
        print('Err, error: ', e) 

Obtain a value from Ok type using unwrap method on variable. Variable holds a value of Ok type.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


r: Result = f(1.0, 10.0)
v: float = r.unwrap() # v is 0.1

Obtain a value from Ok type using unwrap method on expression. Expression returns a value of Ok type.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


v: float = (f(1.0, 10.0)).unwrap() # v is 0.1

Obtain a value from Ok type using unwrap_value method on variable. Variable holds a value of Ok type. If value is Ok type, unwrap_value has no effects, it is same as unwrap method.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res

    
r: Result = f(1.0, 10.0)
v: float = r.unwrap_value() # v is 0.1

Obtain a value from Ok type using unwrap method on expression. Expression returns a value of Ok type. If value is Ok type, unwrap_value has no effects, it is same as unwrap method.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


v: float = (f(1.0, 10.0)).unwrap_value() # v is 0.1

Obtain a value from Ok type using unwrap_or method on variable. Variable holds a value of Ok type. If value is Ok type, unwrap_or has no effects, it is same as unwrap or unwrap_value method.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


r: Result = f(1.0, 10.0)
v: float = r.unwrap_or(10.1) # v is 0.1

Obtain a value from Ok type using unwrap_or method on expression. Expression returns a value of Ok type. If value is Ok type, unwrap_or has no effects, it is same as unwrap or unwrap_value method.

from thresult import Result, Ok, Err


def f(a: float, b: float) -> Result[float, Exception]:
    try:
        r: float = a / b
        res = Ok[float](r)
    except Exception as e:
        res = Err[Exception](e)
    
    return res


v: float = (f(1.0, 10.0)).unwrap_or(10.1) # v is 0.1

thresult provides type checking

from thresult import Result, Ok, Err


class A:
    pass

    
a = A()
at: Ok[A] = Ok[A](a) 
at: Ok[A] = Ok[A](4) # TypeError: Got <class 'int'> but expected <class 'A'>

create custom types by extending Ok and Err

from thresult import Result, Ok, Err


class AOk(Ok):
    pass


class AErr(Err):
    pass


CustomResult: type = AOk[float] | AErr[str]


r: CustomResult = AOk[int](5)
v: int = r.unwrap_value() # v holds value of 5

Using decorators to obtain Ok type

from thresult import Result, Ok, Err


@Result[float, str]
def f(n: float):
    return 1/n


v = f(10.0) # Ok[<class 'float'>]
f: float = v.unwrap() # 0.1

Using decorators to obtain Err type

from thresult import Result, Ok, Err


@Result[float, str]
def f(n: float):
    return 1 / n


v = f(0.0)
m: str = v.unwrap_value() # float division by zero

Using decorators to obtain Ok Custom result type

from thresult import Result, Ok, Err


# custom result type
CustomResult: type = Ok[float] | Err[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]
f: float = v.unwrap() # 0.1

Using decorators to obtain Ok Custom result type Using unwrap_value

from thresult import Result, Ok, Err


# custom result type
CustomResult: type = Ok[float] | Err[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]
f: float = v.unwrap_value() # 0.1

Using decorators to obtain Ok Custom result type Using unwrap_or

from thresult import Result, Ok, Err


# custom result type
CustomResult: type = Ok[float] | Err[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]
f: float = v.unwrap_or(10.1) # 0.1

Using decorators to obtain Err Custom result type

from thresult import Result, Ok, Err


CustomResult: type = Ok[float] | Err[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(0.0) # Err[<class 'str'>]
# panic: raising exception
f: float = v.unwrap() # ZeroDivisionError: float division by zero

Using decorators to obtain Err Custom result type

from thresult import Result, Ok, Err


CustomResult: type = Ok[float] | Err[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(0.0) # Err[<class 'str'>]

# doesn't panic, returns exception's message as string
f: float = v.unwrap_value() # string value: float division by zero

Using decorators to obtain Err. Custom result type Using unwrap_or()

from thresult import Result, Ok, Err


CustomResult: type = Ok[float] | Err[str] 


@CustomResult[float, 'str']
def f(n: float):
    return 1 / n


v = f(0.0) # Err[<class 'str'>]

# doesn't panic, returns custom exception's message as string
f: float = v.unwrap_or('Zero division: Custom message') # string value: Zero division: Custom message 

Using decorators to obtain Ok. Custom result type and custom Ok type

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass

class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]

Using decorators to obtain Ok. Custom result type and custom Ok type. Obtain value with unwrap

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]
r: float = v.unwrap() # 0.1

Using decorators to obtain Ok. Custom result type and custom Ok type. Obtain value with unwrap_value

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]
r: float = v.unwrap_value() # 0.1

Using decorators to obtain Ok. Custom result type and custom Ok type. Obtain value with unwrap_or

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 

@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(10.0) # Ok[<class 'float'>]
r: float = v.unwrap_or(10.1) # 0.1

Using decorators to obtain Err. Custom result type and custom Err type

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n

v = f(0.0) # Err[<class 'str'>]

Using decorators to obtain Err. Custom result type and custom Err type. Handling exceptions using unwrap

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(0.0) # Err[<class 'str'>]

try:
    v.unwrap()
except ZeroDivisionError as e:
    pass

Using decorators to obtain Err. Custom result type and custom Err type. Handling exceptions using unwrap_value

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(0.0) # Err[<class 'str'>]
message: str = v.unwrap_value() # float division by zero

Using decorators to obtain Err. Custom result type and custom Err type. Handling exceptions using unwrap_or

from thresult import Result, Ok, Err


class CustomOk(Ok):
    pass


class CustomErr(Err):
    pass


CustomResult: type = CustomOk[float] | CustomErr[str] 


@CustomResult[float, str]
def f(n: float):
    return 1 / n


v = f(0.0) # Err[<class 'str'>]
message: str = v.unwrap_or('Custom message') # Custom message

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

thresult-0.9.5.tar.gz (7.2 kB view hashes)

Uploaded Source

Built Distribution

thresult-0.9.5-py3-none-any.whl (5.7 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page