Skip to content

Commit 2942791

Browse files
committed
refactor(autorun): remove auto_call option as it was addressing such a rare use case that it was not worth the complexity
1 parent 3708af6 commit 2942791

8 files changed

+110
-29
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Version 0.17.0
4+
5+
- refactor(autorun): remove `auto_call` option as it was addressing such a rare use case that it was not worth the complexity
6+
37
## Version 0.16.1
48

59
- feat(core): add `_type` field to the serialized immutable instances

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "python-redux"
3-
version = "0.16.1"
3+
version = "0.17.0"
44
description = "Redux implementation for Python"
55
authors = ["Sassan Haradji <sassanh@gmail.com>"]
66
license = "Apache-2.0"

redux/autorun.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,6 @@ def __init__(
4545
],
4646
options: AutorunOptions[AutorunOriginalReturnType],
4747
) -> None:
48-
if not options.reactive and options.auto_call:
49-
msg = '`reactive` must be `True` if `auto_call` is `True`'
50-
raise ValueError(msg)
5148
self._store = store
5249
self._selector = selector
5350
self._comparator = comparator
@@ -80,9 +77,7 @@ def __init__(
8077

8178
if self._options.reactive:
8279
self._unsubscribe = store.subscribe(
83-
lambda state: self._call()
84-
if self._check(state) and self._options.auto_call
85-
else None,
80+
lambda state: self._call() if self._check(state) else None,
8681
)
8782
else:
8883
self._unsubscribe = None

redux/basic_types.py

-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ class CreateStoreOptions(Immutable, Generic[Action, Event]):
134134
class AutorunOptions(Immutable, Generic[AutorunOriginalReturnType]):
135135
default_value: AutorunOriginalReturnType | None = None
136136
initial_call: bool = True
137-
auto_call: bool = True
138137
reactive: bool = True
139138
keep_ref: bool = True
140139
subscribers_initial_run: bool = True

redux/main.py

-1
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,6 @@ def decorator(
389389
options=AutorunOptions(
390390
default_value=_options.default_value,
391391
initial_call=False,
392-
auto_call=False,
393392
reactive=False,
394393
keep_ref=_options.keep_ref,
395394
subscribers_initial_run=_options.subscribers_initial_run,

tests/test_autorun.py

+5-20
Original file line numberDiff line numberDiff line change
@@ -183,20 +183,6 @@ def render(value: int) -> int:
183183
)
184184

185185

186-
def test_auto_call_without_reactive(store: StoreType) -> None:
187-
with pytest.raises(
188-
ValueError,
189-
match='^`reactive` must be `True` if `auto_call` is `True`$',
190-
):
191-
192-
@store.autorun(
193-
lambda state: state.value,
194-
options=AutorunOptions(reactive=False, auto_call=True),
195-
)
196-
def _(_: int) -> int:
197-
pytest.fail('This should never be called')
198-
199-
200186
call_sequence = [
201187
# 0
202188
[
@@ -229,7 +215,7 @@ def render(_: int) -> None: ...
229215

230216
render_autorun = store.autorun(
231217
lambda state: state.value,
232-
options=AutorunOptions(reactive=True, auto_call=False, initial_call=True),
218+
options=AutorunOptions(reactive=False, initial_call=True),
233219
)(render)
234220

235221
for actions in call_sequence:
@@ -250,7 +236,7 @@ def render(_: int) -> None: ...
250236

251237
render_autorun = store.autorun(
252238
lambda state: state.value,
253-
options=AutorunOptions(reactive=True, auto_call=False, initial_call=False),
239+
options=AutorunOptions(reactive=False, initial_call=False),
254240
)(render)
255241

256242
for actions in call_sequence:
@@ -269,15 +255,15 @@ def render(_: int) -> None: ...
269255

270256
render = mocker.create_autospec(render)
271257

272-
render_autorun = store.autorun(
258+
trigger_autorun = store.autorun(
273259
lambda state: state.value,
274-
options=AutorunOptions(reactive=True, auto_call=True, initial_call=True),
260+
options=AutorunOptions(reactive=True, initial_call=True),
275261
)(render)
276262

277263
for actions in call_sequence:
278264
for action in actions:
279265
store.dispatch(action)
280-
render_autorun()
266+
trigger_autorun()
281267

282268
assert render.mock_calls == [
283269
call(0),
@@ -299,7 +285,6 @@ def test_view_mode_with_arguments_autorun(
299285
lambda state: state.value,
300286
options=AutorunOptions(
301287
reactive=False,
302-
auto_call=False,
303288
initial_call=False,
304289
default_value=0,
305290
),

tests/test_combinations.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# ruff: noqa: D100, D101, D102, D103, D104, D107
2+
from __future__ import annotations
3+
4+
from dataclasses import replace
5+
from typing import Literal
6+
7+
import pytest
8+
from immutable import Immutable
9+
10+
from redux.basic_types import (
11+
BaseAction,
12+
CompleteReducerResult,
13+
CreateStoreOptions,
14+
FinishAction,
15+
FinishEvent,
16+
InitAction,
17+
InitializationActionError,
18+
)
19+
from redux.main import Store
20+
21+
22+
class StateType(Immutable):
23+
value1: int
24+
value2: int
25+
26+
27+
class IncrementAction(BaseAction):
28+
which: Literal[1, 2]
29+
30+
31+
Action = IncrementAction | InitAction | FinishAction
32+
33+
34+
def reducer(
35+
state: StateType | None,
36+
action: Action,
37+
) -> StateType | CompleteReducerResult[StateType, Action, FinishEvent]:
38+
if state is None:
39+
if isinstance(action, InitAction):
40+
return StateType(value1=0, value2=0)
41+
raise InitializationActionError(action)
42+
43+
if isinstance(action, IncrementAction):
44+
field_name = f'value{action.which}'
45+
return replace(
46+
state,
47+
**{field_name: getattr(state, field_name) + 1},
48+
)
49+
50+
return state
51+
52+
53+
StoreType = Store[StateType, Action, FinishEvent]
54+
55+
56+
@pytest.fixture
57+
def store() -> StoreType:
58+
return Store(reducer, options=CreateStoreOptions(auto_init=True))
59+
60+
61+
def test_autorun_of_view(store: StoreType) -> None:
62+
@store.autorun(
63+
lambda state: state.value2,
64+
lambda state: (state.value1, state.value2),
65+
)
66+
@store.view(lambda state: state.value1)
67+
def view(value1: int, value2: int) -> tuple[int, int]:
68+
return (value1, value2)
69+
70+
assert view() == (0, 0)
71+
72+
store.dispatch(IncrementAction(which=1))
73+
74+
assert view() == (1, 0)
75+
76+
store.dispatch(IncrementAction(which=2))
77+
78+
assert view() == (1, 1)
79+
80+
store.dispatch(FinishAction())

tests/test_views.py

+19
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,25 @@ def render(value: int) -> int:
8585
assert render() == 1
8686

8787

88+
def test_not_reactive(
89+
store: StoreType,
90+
) -> None:
91+
runs = 0
92+
93+
@store.view(lambda state: state.value)
94+
def render(value: int) -> int:
95+
nonlocal runs
96+
runs += 1
97+
return value
98+
99+
store.dispatch(IncrementAction())
100+
store.dispatch(IncrementAction())
101+
store.dispatch(IncrementAction())
102+
103+
assert render() == 3
104+
assert runs == 1
105+
106+
88107
def test_uninitialized_store(
89108
store: StoreType,
90109
) -> None:

0 commit comments

Comments
 (0)