From 2663a5582ce17f9450cdb6ffb3d711b1e22d1500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Mat=C4=9Bjka?= <jan@matejka.ninja> Date: Thu, 30 Jan 2025 21:07:24 +0100 Subject: [PATCH] refactor(message-queue/python): SampleIterator its ugly but its an interesting question of 1. if genrator or iterator is preferred. 2. why is not working. --- message-queue/python/src/jmcgmqp/algorithm.py | 44 +++++++++++++++++++ message-queue/python/test/test_algorithm.py | 16 +++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/message-queue/python/src/jmcgmqp/algorithm.py b/message-queue/python/src/jmcgmqp/algorithm.py index b68b916c..9416338c 100644 --- a/message-queue/python/src/jmcgmqp/algorithm.py +++ b/message-queue/python/src/jmcgmqp/algorithm.py @@ -1,3 +1,4 @@ +from collections.abc import Iterator from dataclasses import dataclass from typing import * import itertools @@ -5,6 +6,49 @@ T = TypeVar('T') Sampler = Callable[[int],[T]] +@dataclass +class SampleIterator(Iterator): + sampler: Sampler + i:int = 0 + + _prev:T | None = None + + def __post_init__(self): + print(self.__next__) + print(self._next_power) + self.__next__ = self._next_power + print(self.__next__) + + def __next__(self): + ... # pragma: nocover this is here only to satisfy the interface. + print("what") + + def _next_power(self): + print("power") + r = self.sampler(2**self.i) + print(r) + if prev and prev >= r: + self.__next__ = self._next_step + self.i -= 1 + else: + self.i += 1 + return r + + def _next_step(self): + print("step") + self.i += 1 + r = self.sampler(self.i) + if prev and prev >= r: + self.__next__ = self._next_stop + return r + + def _next_stop(self): + print("stop") + raise StopIteration() + + def __iter__(self): + return self + def SampleGenerator( sample: Sampler, starting_power: int = 0, diff --git a/message-queue/python/test/test_algorithm.py b/message-queue/python/test/test_algorithm.py index 5081362b..fbc659b3 100644 --- a/message-queue/python/test/test_algorithm.py +++ b/message-queue/python/test/test_algorithm.py @@ -1,18 +1,28 @@ -from jmcgmqp.algorithm import find_maximum, Sampler +from jmcgmqp.algorithm import find_maximum, Sampler, SampleIterator from unittest.mock import create_autospec, call import pytest -@pytest.mark.parametrize('sequence, result, args, power', ( +cases = ( ((1, 1, 1), 1, (1, 2), 0), ((1, 2, 1, 1), 2, (1, 2, 4, 3), 0), ((1, 2, 1, 3), 3, (1, 2, 4, 3), 0), ((1, 2, 3, 4, 5, 1, 1), 5, (1, 2, 4, 8, 16, 32, 17), 0), ((1, 2, 3, 1, 4, 5, 1), 5, (1, 2, 4, 8, 5, 6, 7), 0), ((1, 1, 1), 1, (4, 8, 5), 2), -)) +) + +@pytest.mark.parametrize('sequence, result, args, power', cases) def test_find_maximum(sequence, result, args, power): sample = create_autospec(Sampler, spec_set=True) sample.side_effect = sequence assert find_maximum(sample, power) == result assert sample.call_args_list == [call(x) for x in args] + +@pytest.mark.parametrize('sequence, result, args, power', cases) +def test_SampleIterator(sequence, result, args, power): + sample = create_autospec(Sampler, spec_set=True) + sample.side_effect = sequence + assert next(SampleIterator(sample, power)) == args[0] + return + assert tuple(SampleIterator(sample, power)) == args