From c7bca2cbcf2ebace255ec5bbd5a782d5ba51d315 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Mon, 30 Nov 2020 03:04:04 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20Lazy=20object=20(undocumented?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/source/autodoc/lazy.rst | 9 +++++++ royalnet/__init__.py | 0 royalnet/lazy/__init__.py | 1 + royalnet/lazy/lazy.py | 46 ++++++++++++++++++++++++++++++++ royalnet/lazy/tests/__init__.py | 0 royalnet/lazy/tests/test_lazy.py | 35 ++++++++++++++++++++++++ 6 files changed, 91 insertions(+) create mode 100644 docs/source/autodoc/lazy.rst create mode 100644 royalnet/__init__.py create mode 100644 royalnet/lazy/__init__.py create mode 100644 royalnet/lazy/lazy.py create mode 100644 royalnet/lazy/tests/__init__.py create mode 100644 royalnet/lazy/tests/test_lazy.py diff --git a/docs/source/autodoc/lazy.rst b/docs/source/autodoc/lazy.rst new file mode 100644 index 00000000..c98f5a36 --- /dev/null +++ b/docs/source/autodoc/lazy.rst @@ -0,0 +1,9 @@ +Lazy autodoc +================= + +.. note:: The documentation for this section hasn't been written yet. + +.. currentmodule:: royalnet.lazy +.. automodule:: royalnet.lazy + :members: + :undoc-members: diff --git a/royalnet/__init__.py b/royalnet/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/royalnet/lazy/__init__.py b/royalnet/lazy/__init__.py new file mode 100644 index 00000000..dea06c56 --- /dev/null +++ b/royalnet/lazy/__init__.py @@ -0,0 +1 @@ +from .lazy import * diff --git a/royalnet/lazy/lazy.py b/royalnet/lazy/lazy.py new file mode 100644 index 00000000..f1473c02 --- /dev/null +++ b/royalnet/lazy/lazy.py @@ -0,0 +1,46 @@ +from __future__ import annotations +from royalnet.typing import * +import functools + + +Result = TypeVar("Result") + + +class Lazy: + def __init__(self, obj: Callable[[Any], Result], *args, **kwargs): + self._func: Callable[[Any], Result] = obj + self._args = args + self._kwargs = kwargs + self.evaluated = False + self._result = None + + def _evaluate_args(self) -> List[Any]: + evaluated_args = [] + for arg in self._args: + if isinstance(arg, Lazy): + arg = arg.evaluate() + evaluated_args.append(arg) + return evaluated_args + + def _evaluate_kwargs(self) -> Dict[str, Any]: + evaluated_kwargs = {} + for key, value in self._kwargs.items(): + if isinstance(value, Lazy): + value = value.evaluate() + evaluated_kwargs[key] = value + return evaluated_kwargs + + def evaluate(self) -> Result: + if not self.evaluated: + self._result = self._func(*self._evaluate_args(), **self._evaluate_kwargs()) + self.evaluated = True + return self._result + + @property + def e(self) -> Result: + return self.evaluate() + + +__all__ = ( + "Lazy", +) diff --git a/royalnet/lazy/tests/__init__.py b/royalnet/lazy/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/royalnet/lazy/tests/test_lazy.py b/royalnet/lazy/tests/test_lazy.py new file mode 100644 index 00000000..6f4c2b6c --- /dev/null +++ b/royalnet/lazy/tests/test_lazy.py @@ -0,0 +1,35 @@ +import pytest +from royalnet.lazy import Lazy + + +def test_single_eval_no_args(): + lazy = Lazy(lambda: 1) + assert not lazy.evaluated + assert lazy._result is None + result = lazy.evaluate() + assert result == 1 + assert lazy.evaluated + assert lazy._result == 1 + + +def test_single_eval_with_args(): + lazy = Lazy(lambda a, b: a + b, 10, 10) + result = lazy.evaluate() + assert result == 20 + assert lazy.evaluated + assert lazy._result == 20 + + +def test_chained_eval(): + twenty = Lazy(lambda a, b: a + b, 10, 10) + assert not twenty.evaluated + assert twenty._result is None + twentyfive = Lazy(lambda a, b: a + b, twenty, 5) + assert not twentyfive.evaluated + assert twentyfive._result is None + result = twentyfive.evaluate() + assert result == 25 + assert twenty.evaluated + assert twenty._result == 20 + assert twentyfive.evaluated + assert twentyfive._result == 25