Skip to content
This repository was archived by the owner on Aug 7, 2023. It is now read-only.

Commit afd7065

Browse files
committed
Decorator for a function that causes it to execute only once
1 parent 23cbac3 commit afd7065

2 files changed

Lines changed: 32 additions & 6 deletions

File tree

sculpting/tools.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
from typing import Any
1+
from typing import Any, Callable
22

3-
from pyhandling import return_
3+
from pyhandling import return_, nothing
44
from pyhandling.annotations import handler
55

66
from sculpting.annotations import attribute_setter
77

88

9-
__all__ = ("setting_of", )
9+
__all__ = ("setting_of", "once")
1010

1111

1212
def setting_of_attr(attribute_name: str, *, value_transformer: handler = return_) -> attribute_setter:
@@ -23,4 +23,22 @@ def wrapper(object_: object, value: Any) -> Any:
2323

2424
return setattr(object_, attribute_name, value_transformer(value))
2525

26-
return wrapper
26+
return wrapper
27+
28+
29+
class once:
30+
"""
31+
Decorator for a function that causes it to execute only once, after which it
32+
always returns its result.
33+
"""
34+
35+
__result = nothing
36+
37+
def __init__(self, func: Callable):
38+
self._func = func
39+
40+
def __call__(self, *args, **kwargs) -> Any:
41+
if self.__result is nothing:
42+
self.__result = self._func(*args, **kwargs)
43+
44+
return self.__result

tests.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from typing import Any, Type
22

3-
from pyhandling import by, then, operation_by, execute_operation, to, ArgumentPack
3+
from pyhandling import times, by, then, operation_by, execute_operation, to, ArgumentPack
44
from pytest import mark, raises
55

66
from sculpting.annotations import attribute_getter, attribute_setter
77
from sculpting.core import *
8-
from sculpting.tools import setting_of_attr
8+
from sculpting.tools import setting_of_attr, once
99

1010

1111
class AttributeKeeper:
@@ -29,6 +29,14 @@ def test_setting_of_attr(attribute_name: str, attribute_value: Any):
2929
assert getattr(obj, attribute_name) == attribute_value
3030

3131

32+
def test_once():
33+
runner = times(1)
34+
once_runner = once(runner)
35+
36+
assert tuple(once_runner() for _ in range(8)) == (True, ) * 8
37+
assert tuple(runner() for _ in range(8)) == (False, True) * 4
38+
39+
3240
@mark.parametrize(
3341
"obj, attribute_getter, result",
3442
[

0 commit comments

Comments
 (0)