From daac14e0997faac9d157317f19fc01828ff86f0a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 27 Jul 2021 12:35:14 +0200 Subject: [PATCH] Improved avg query --- src/cpl_query/_extension/iterable.py | 8 ++++---- src/cpl_query/_helper.py | 2 ++ src/cpl_query/_query/avg.py | 23 +++++++++++------------ src/cpl_query/extension/iterable_abc.py | 22 ++++++++++++++++++++-- src/cpl_query/extension/list.py | 13 +------------ src/cpl_query/tests/query_test.py | 19 ++++++++++++------- 6 files changed, 50 insertions(+), 37 deletions(-) create mode 100644 src/cpl_query/_helper.py diff --git a/src/cpl_query/_extension/iterable.py b/src/cpl_query/_extension/iterable.py index 15037603..d2a9fb4e 100644 --- a/src/cpl_query/_extension/iterable.py +++ b/src/cpl_query/_extension/iterable.py @@ -20,8 +20,8 @@ from cpl_query.extension.iterable_abc import IterableABC class Iterable(IterableABC): - def __init__(self): - IterableABC.__init__(self) + def __init__(self, t: type = None, values: list = None): + IterableABC.__init__(self, t, values) def any(self, func: Callable) -> bool: return any_query(self, func) @@ -29,8 +29,8 @@ class Iterable(IterableABC): def all(self, func: Callable) -> bool: return all_query(self, func) - def average(self, t: type, func: Callable) -> Union[int, float, complex]: - return avg_query(self, t, func) + def average(self, func: Callable = None) -> Union[int, float, complex]: + return avg_query(self, func) def contains(self, value: object) -> bool: return contains_query(self, value) diff --git a/src/cpl_query/_helper.py b/src/cpl_query/_helper.py new file mode 100644 index 00000000..6f92e585 --- /dev/null +++ b/src/cpl_query/_helper.py @@ -0,0 +1,2 @@ +def is_number(t: type) -> bool: + return issubclass(t, int) or issubclass(t, float) or issubclass(t, complex) diff --git a/src/cpl_query/_query/avg.py b/src/cpl_query/_query/avg.py index 6d140da8..cf8d354a 100644 --- a/src/cpl_query/_query/avg.py +++ b/src/cpl_query/_query/avg.py @@ -1,28 +1,27 @@ from typing import Callable, Union +from cpl_query._helper import is_number from cpl_query.exceptions import InvalidTypeException, WrongTypeException, ExceptionArgument, ArgumentNoneException from cpl_query.extension.iterable_abc import IterableABC -def avg_query(_list: IterableABC, _t: type, _func: Callable) -> Union[int, float, complex]: - average = 0 - count = len(_list) - +def avg_query(_list: IterableABC, _func: Callable) -> Union[int, float, complex]: if _list is None: raise ArgumentNoneException(ExceptionArgument.list) - if _func is None: - raise ArgumentNoneException(ExceptionArgument.func) - - if _t != int and _t != float and _t != complex: - raise InvalidTypeException() + average = 0 + count = len(_list) for element in _list: - value = _func(element) - if type(value) != _t: + if _func is not None: + value = _func(element) + + else: + value = element + + if _list.type is not None and type(element) != _list.type or not is_number(type(value)): raise WrongTypeException() average += value return average / count - diff --git a/src/cpl_query/extension/iterable_abc.py b/src/cpl_query/extension/iterable_abc.py index 6a94c8c3..76a61f72 100644 --- a/src/cpl_query/extension/iterable_abc.py +++ b/src/cpl_query/extension/iterable_abc.py @@ -5,17 +5,35 @@ from typing import Optional, Callable, Union class IterableABC(ABC, list): @abstractmethod - def __init__(self): + def __init__(self, t: type = None, values: list = None): list.__init__(self) + if t == any: + t = None + self._type = t + + if values is not None: + for value in values: + self.append(value) + + @property + def type(self) -> type: + return self._type + @abstractmethod def any(self, func: Callable) -> bool: pass @abstractmethod def all(self, func: Callable) -> bool: pass + def append(self, __object: object) -> None: + if self._type is not None and type(__object) != self._type and not isinstance(type(__object), self._type): + raise Exception(f'Unexpected type: {type(__object)}') + + super().append(__object) + @abstractmethod - def average(self, t: type, func: Callable) -> Union[int, float, complex]: pass + def average(self, func: Callable = None) -> Union[int, float, complex]: pass @abstractmethod def contains(self, value: object) -> bool: pass diff --git a/src/cpl_query/extension/list.py b/src/cpl_query/extension/list.py index 94eeeb09..c642f0be 100644 --- a/src/cpl_query/extension/list.py +++ b/src/cpl_query/extension/list.py @@ -4,15 +4,4 @@ from .._extension.iterable import Iterable class List(Iterable): def __init__(self, t: type = None, values: list = None): - Iterable.__init__(self) - - self._type = t - - if values is not None: - self.extend(values) - - def append(self, __object: object) -> None: - if self._type is not None and type(__object) != self._type and not isinstance(type(__object), self._type): - raise Exception(f'Unexpected type: {type(__object)}') - - super().append(__object) + Iterable.__init__(self, t, values) diff --git a/src/cpl_query/tests/query_test.py b/src/cpl_query/tests/query_test.py index c5522813..e1d0b417 100644 --- a/src/cpl_query/tests/query_test.py +++ b/src/cpl_query/tests/query_test.py @@ -66,19 +66,24 @@ class QueryTest(unittest.TestCase): avg += user.address.nr avg = avg / len(self._tests) - res = self._tests.average(int, lambda u: u.address.nr) + res = self._tests.average(lambda u: u.address.nr) - self.assertEqual(res, avg) - - def invalid(): - e_res = self._tests.average(str, lambda u: u.address.nr) + self.assertEqual(avg, res) def wrong(): - e_res = self._tests.average(int, lambda u: u.address.street) + e_res = self._tests.average(lambda u: u.address.street) - self.assertRaises(InvalidTypeException, invalid) self.assertRaises(WrongTypeException, wrong) + tests = List(int, list(range(0, 100))) + self.assertEqual(sum(tests) / len(tests), tests.average()) + + def wrong2(): + tests2 = List(int, values=list(range(0, 100))) + e_res = tests2.average(lambda u: u.address.nr) + + self.assertRaises(AttributeError, wrong2) + def test_contains(self): self.assertTrue(self._tests.contains(self._t_user)) self.assertFalse(self._tests.contains(User("Test", None)))