Skip to content

Commit

Permalink
chore(optimization): update assert_values on Result construction to s…
Browse files Browse the repository at this point in the history
…peed up the object init (#65)
  • Loading branch information
acostapazo authored Jun 21, 2023
1 parent db952bb commit cdee17e
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 12 deletions.
83 changes: 83 additions & 0 deletions benchmark/pyperf_comparative.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from __future__ import annotations

import pyperf

from meiga import Error, Failure, Result, Success


# Without meiga
class NoSuchKeyException(Exception):
...


class TypeMismatchException(Exception):
...


def string_from_key(dictionary: dict, key: str) -> str:
if key not in dictionary.keys():
raise NoSuchKeyException()

value = dictionary[key]
if not isinstance(value, str):
raise TypeMismatchException()

return value


def string_from_key_without_meiga(dictionary: dict, key: str) -> str:
try:
return string_from_key(dictionary, key)
except Exception: # noqa
pass


# With meiga
class NoSuchKey(Error):
...


class TypeMismatch(Error):
...


def string_from_key_with_meiga(
dictionary: dict, key: str
) -> Result[str, NoSuchKey | TypeMismatch]:
if key not in dictionary.keys():
return Failure(NoSuchKey())

value = dictionary[key]
if not isinstance(value, str):
return Failure(TypeMismatch())

return Success(value)


dictionary = {
"key1": "value",
"key2": 2,
"key3": "value",
"key4": 2,
"key5": "value",
"key6": 2,
"key7": "value",
"key8": 2,
"key9": "value",
"key10": 2,
"key11": "value",
"key12": 2,
}


def meiga():
string_from_key_with_meiga(dictionary=dictionary, key="invalid_key")


def without_meiga():
string_from_key_without_meiga(dictionary=dictionary, key="invalid_key")


runner = pyperf.Runner()
runner.bench_func("meiga", meiga)
runner.bench_func("without meiga", without_meiga)
12 changes: 8 additions & 4 deletions benchmark/time_result.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from timeit import timeit
from timeit import default_number, timeit

from meiga import Error, Failure, Result, Success

Expand Down Expand Up @@ -42,14 +42,18 @@ def string_from_key(
}

time_success = timeit(lambda: string_from_key(dictionary=dictionary, key="key1"))
print(f"time when success: {time_success}")
print(f"time when success: {(time_success/default_number)*1000000000} ns")

time_failure_no_such_key = timeit(
lambda: string_from_key(dictionary=dictionary, key="invalid_key")
)
print(f"time when failure (no such key): {time_failure_no_such_key}")
print(
f"time when failure (no such key): {(time_failure_no_such_key/default_number)*1000000000} ns"
)

time_failure_type_missmatch = timeit(
lambda: string_from_key(dictionary=dictionary, key="key2")
)
print(f"time when failure (type missmatch): {time_failure_type_missmatch}")
print(
f"time when failure (type missmatch): {(time_failure_type_missmatch/default_number)*1000000000} ns"
)
14 changes: 6 additions & 8 deletions meiga/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,21 @@ def __hash__(self) -> int:

def _assert_values(self) -> None:
self._is_success = False
if isinstance(self._value_success, type(NoGivenValue)) and isinstance(
self._value_failure, type(NoGivenValue)
):
if self._value_success is NoGivenValue and self._value_failure is NoGivenValue:
raise TypeError(
"Result is a monad, it must be a success or a failure. "
"Please model your result selecting only one type [success or failure]."
)
elif not isinstance(self._value_success, type(NoGivenValue)) and not isinstance(
self._value_failure, type(NoGivenValue)
elif (
self._value_success is not NoGivenValue
and self._value_failure is not NoGivenValue
):
raise TypeError(
"Result is a monad, it cannot be success and failure at the same time. "
"Please model your result selecting only one type [success or failure]."
)
elif not isinstance(self._value_success, type(NoGivenValue)):
self._is_success = True
return None
else:
self._is_success = self._value_success is not NoGivenValue

def get_value(self) -> TS | TF:
if self._is_success:
Expand Down

0 comments on commit cdee17e

Please sign in to comment.