1
1
# ruff: noqa: D100, D101, D102, D103, D104, D105, D107
2
2
from __future__ import annotations
3
3
4
+ import inspect
4
5
import weakref
6
+ from asyncio import iscoroutinefunction
5
7
from inspect import signature
6
- from types import MethodType
7
- from typing import TYPE_CHECKING , Any , Callable , Generic , cast
8
+ from typing import TYPE_CHECKING , Any , Callable , Coroutine , Generic , cast
8
9
9
10
from redux .basic_types import (
10
11
Action ,
17
18
)
18
19
19
20
if TYPE_CHECKING :
21
+ from types import MethodType
22
+
20
23
from redux .main import Store
21
24
22
25
@@ -43,30 +46,104 @@ def __init__( # noqa: PLR0913
43
46
self ._store = store
44
47
self ._selector = selector
45
48
self ._comparator = comparator
46
- self ._func = func
49
+ if options .keep_ref :
50
+ self ._func = func
51
+ elif inspect .ismethod (func ):
52
+ self ._func = weakref .WeakMethod (func )
53
+ else :
54
+ self ._func = weakref .ref (func )
47
55
self ._options = options
48
56
49
57
self ._last_selector_result : SelectorOutput | None = None
50
58
self ._last_comparator_result : ComparatorOutput = cast (
51
59
ComparatorOutput ,
52
60
object (),
53
61
)
54
- self ._latest_value : AutorunOriginalReturnType | None = options .default_value
62
+ self ._latest_value : AutorunOriginalReturnType = options .default_value
55
63
self ._subscriptions : set [
56
64
Callable [[AutorunOriginalReturnType ], Any ]
57
65
| weakref .ref [Callable [[AutorunOriginalReturnType ], Any ]]
58
66
] = set ()
67
+ self ._immediate_run = (
68
+ not iscoroutinefunction (func )
69
+ if options .subscribers_immediate_run is None
70
+ else options .subscribers_immediate_run
71
+ )
59
72
60
73
if self ._options .initial_run and store ._state is not None : # noqa: SLF001
61
- self .check_and_call (store ._state ) # noqa: SLF001
74
+ self ._check_and_call (store ._state ) # noqa: SLF001
62
75
63
- store .subscribe (self .check_and_call )
76
+ store .subscribe (self ._check_and_call )
64
77
65
- def check_and_call (self : Autorun , state : State ) -> None :
78
+ def inform_subscribers (
79
+ self : Autorun [
80
+ State ,
81
+ Action ,
82
+ Event ,
83
+ SelectorOutput ,
84
+ ComparatorOutput ,
85
+ AutorunOriginalReturnType ,
86
+ ],
87
+ ) -> None :
88
+ for subscriber_ in self ._subscriptions .copy ():
89
+ if isinstance (subscriber_ , weakref .ref ):
90
+ subscriber = subscriber_ ()
91
+ if subscriber is None :
92
+ self ._subscriptions .discard (subscriber_ )
93
+ continue
94
+ else :
95
+ subscriber = subscriber_
96
+ subscriber (self ._latest_value )
97
+
98
+ def call_func (
99
+ self : Autorun [
100
+ State ,
101
+ Action ,
102
+ Event ,
103
+ SelectorOutput ,
104
+ ComparatorOutput ,
105
+ AutorunOriginalReturnType ,
106
+ ],
107
+ selector_result : SelectorOutput ,
108
+ previous_result : SelectorOutput | None ,
109
+ func : Callable [
110
+ [SelectorOutput , SelectorOutput ],
111
+ AutorunOriginalReturnType ,
112
+ ]
113
+ | Callable [[SelectorOutput ], AutorunOriginalReturnType ]
114
+ | MethodType ,
115
+ ) -> AutorunOriginalReturnType :
116
+ if len (signature (func ).parameters ) == 1 :
117
+ return cast (
118
+ Callable [[SelectorOutput ], AutorunOriginalReturnType ],
119
+ func ,
120
+ )(selector_result )
121
+ return cast (
122
+ Callable [
123
+ [SelectorOutput , SelectorOutput | None ],
124
+ AutorunOriginalReturnType ,
125
+ ],
126
+ func ,
127
+ )(selector_result , previous_result )
128
+
129
+ def _check_and_call (
130
+ self : Autorun [
131
+ State ,
132
+ Action ,
133
+ Event ,
134
+ SelectorOutput ,
135
+ ComparatorOutput ,
136
+ AutorunOriginalReturnType ,
137
+ ],
138
+ state : State ,
139
+ ) -> None :
66
140
try :
67
141
selector_result = self ._selector (state )
68
142
except AttributeError :
69
143
return
144
+ func = self ._func () if isinstance (self ._func , weakref .ref ) else self ._func
145
+ if func is None :
146
+ return
70
147
if self ._comparator is None :
71
148
comparator_result = cast (ComparatorOutput , selector_result )
72
149
else :
@@ -75,31 +152,11 @@ def check_and_call(self: Autorun, state: State) -> None:
75
152
previous_result = self ._last_selector_result
76
153
self ._last_selector_result = selector_result
77
154
self ._last_comparator_result = comparator_result
78
- if len (signature (self ._func ).parameters ) == 1 :
79
- self ._latest_value = cast (
80
- Callable [[SelectorOutput ], AutorunOriginalReturnType ],
81
- self ._func ,
82
- )(selector_result )
155
+ self ._latest_value = self .call_func (selector_result , previous_result , func )
156
+ if self ._immediate_run :
157
+ self .inform_subscribers ()
83
158
else :
84
- self ._latest_value = cast (
85
- Callable [
86
- [SelectorOutput , SelectorOutput | None ],
87
- AutorunOriginalReturnType ,
88
- ],
89
- self ._func ,
90
- )(
91
- selector_result ,
92
- previous_result ,
93
- )
94
- for subscriber_ in self ._subscriptions .copy ():
95
- if isinstance (subscriber_ , weakref .ref ):
96
- subscriber = subscriber_ ()
97
- if subscriber is None :
98
- self ._subscriptions .discard (subscriber_ )
99
- continue
100
- else :
101
- subscriber = subscriber_
102
- subscriber (self ._latest_value )
159
+ self ._store ._create_task (cast (Coroutine , self ._latest_value )) # noqa: SLF001
103
160
104
161
def __call__ (
105
162
self : Autorun [
@@ -112,7 +169,7 @@ def __call__(
112
169
],
113
170
) -> AutorunOriginalReturnType :
114
171
if self ._store ._state is not None : # noqa: SLF001
115
- self .check_and_call (self ._store ._state ) # noqa: SLF001
172
+ self ._check_and_call (self ._store ._state ) # noqa: SLF001
116
173
return cast (AutorunOriginalReturnType , self ._latest_value )
117
174
118
175
def __repr__ (
@@ -161,7 +218,7 @@ def subscribe(
161
218
keep_ref = self ._options .subscribers_keep_ref
162
219
if keep_ref :
163
220
callback_ref = callback
164
- elif isinstance (callback , MethodType ):
221
+ elif inspect . ismethod (callback ):
165
222
callback_ref = weakref .WeakMethod (callback )
166
223
else :
167
224
callback_ref = weakref .ref (callback )
0 commit comments