with-err is a python library that converts try-except pattern into Go-like result, err pattern. I feel result, err pattern easier to maintain in large projects.
pip install with-err(with uv)
uv pip install with-errimport json
from with_err import with_err
json_loads_e = with_err(json.loads)
data, err = json_loads_e('{"a": 1}')
assert err is None
assert data == {"a": 1}
data, err = json_loads_e('{"a": }')
assert isinstance(err, json.decoder.JSONDecodeError)
assert data is Noneimport json
from with_err import with_err
@with_err
def json_loads_e(a: str):
return json.loads(a)
data, err = json_loads_e('{"a": 1}')
assert err is None
assert data == {"a": 1}
data, err = json_loads_e('{"a": }')
assert isinstance(err, json.decoder.JSONDecodeError)
assert data is NoneReturn err only with specified exceptions and raise other exceptions.
import json
from with_err import with_err
@with_err(json.decoder.JSONDecodeError)
def json_loads_e(a: str):
return json.loads(a)
data, err = json_loads_e('{"a": 1}')
assert err is None
assert data == {"a": 1}
data, err = json_loads_e('{"a": }')
assert isinstance(err, json.decoder.JSONDecodeError)
assert data is None# raise json.decoder.JSONDecodeError
import json
import re
from with_err import with_err
@with_err(re.PatternError)
def json_loads_e(a: str):
return json.loads(a)
data, err = json_loads_e('{"a": }')# function
import json
from with_err import with_err
json_loads_e = with_err(json.decoder.JSONDecodeError)(json.loads)
data, err = json_loads_e('{"a": 1}')
assert err is None
assert data == {"a": 1}
data, err = json_loads_e('{"a": }')
assert isinstance(err, json.decoder.JSONDecodeError)
assert data is None# empty: return all Exceptions
import json
from with_err import with_err
json_loads_e = with_err()(json.loads)
data, err = json_loads_e('{"a": 1}')
assert err is None
assert data == {"a": 1}
data, err = json_loads_e('{"a": }')
assert isinstance(err, json.decoder.JSONDecodeError)
assert data is Nonefrom with_err import with_err
async def async_fetch_data(endpoint: str) -> dict[str, str]:
if endpoint == "bad":
raise ValueError("Failed to reach endpoint")
return {"status": "ok"}
async_fetch_data_e = with_err(async_fetch_data)
res, err = await async_fetch_data_e("bad")
assert isinstance(err, ValueError)
assert res is Nonefrom with_err import with_err
@with_err
def my_stream():
yield 1
raise ValueError('invalid')
for idx, (each, err) in enumerate(my_stream()):
if idx == 0:
assert each == 1
assert err is None
else:
assert each is None
assert isinstance(err, ValueError)from with_err import with_err
@with_err
async def my_async_stream():
yield 1
raise ValueError('invalid')
async for each, err in my_async_stream():
if each == 1:
assert each == 1
assert err is None
else:
assert each is None
assert isinstance(err, ValueError)@with_err
def my_list_func(is_good=False):
if not is_good:
raise ValueError('not good')
return [1, 2]
data, err = my_list_func()
assert data is None
assert isinstance(err, ValueError)
data, err = my_list_func(True)
assert data is not None
assert err is None
item1, item2 = data
assert item1 == 1
assert item2 == 2import json
from with_err import with_err, get_err_strs
@with_err
def json_loads_e(a: str):
return json.loads(a)
_data, err = json_loads_e('{"a": 1}')
err_stack = get_err_strs(err)
assert err is None
assert err_stack == []import json
import re
from with_err import with_err, get_err_strs
@with_err
def json_loads_e(a: str):
return json.loads(a)
_data, err = json_loads_e('{"a": }')
err_stack = get_err_strs(err)
err_str = '\n'.join(err_stack)
assert isinstance(err, json.decoder.JSONDecodeError)
assert len(err_stack) > 0
assert re.search(r', line \d+, in json_loads_e', err_str)
assert re.search(r'json/__init__.py", line \d+, in loads', err_str)
assert 'json.decoder.JSONDecodeError: Expecting value:' in err_strimport json
import re
from with_err import with_err, get_err_strs, raise_err
@with_err
def json_loads_e(a: str):
return json.loads(a)
def gen_err():
data, err = json_loads_e('{"a": }')
return data, raise_err(err)
data, err = gen_err()
err_stack = get_err_strs(err)
err_str = '\n'.join(err_stack)
assert isinstance(err, json.decoder.JSONDecodeError)
assert len(err_stack) > 0
assert re.search(r', line \d+, in gen_err', err_str)
assert re.search(r', line \d+, in json_loads_e', err_str)
assert re.search(r'json/__init__.py", line \d+, in loads', err_str)
assert 'json.decoder.JSONDecodeError: Expecting value:' in err_strimport json
import re
from with_err import with_err, get_err_strs, raise_err
@with_err
def json_loads_e(a: str):
return json.loads(a)
@with_err
def gen_err():
data, err = json_loads_e('{"a": }')
if err is not None:
raise err
return data
data, err = gen_err()
err_stack = get_err_strs(err)
err_str = '\n'.join(err_stack)
assert isinstance(err, json.decoder.JSONDecodeError)
assert len(err_stack) > 0
assert re.search(r', line \d+, in gen_err', err_str)
assert re.search(r', line \d+, in json_loads_e', err_str)
assert re.search(r'json/__init__.py", line \d+, in loads', err_str)
assert 'json.decoder.JSONDecodeError: Expecting value:' in err_strThe implementation is based on the following Gemini / ChatGPT suggestions: