hmr 0.5.2.3__py3-none-any.whl → 0.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hmr-0.5.2.3.dist-info → hmr-0.6.0.dist-info}/METADATA +1 -1
- hmr-0.6.0.dist-info/RECORD +15 -0
- reactivity/context.py +52 -0
- reactivity/helpers.py +21 -19
- reactivity/hmr/api.py +2 -2
- reactivity/hmr/core.py +14 -11
- reactivity/primitives.py +36 -52
- hmr-0.5.2.3.dist-info/RECORD +0 -14
- {hmr-0.5.2.3.dist-info → hmr-0.6.0.dist-info}/WHEEL +0 -0
- {hmr-0.5.2.3.dist-info → hmr-0.6.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
hmr-0.6.0.dist-info/METADATA,sha256=AQEgb94qk_NRTRAap3w-eie4GVIebx3ZPzUPWrrN_98,1999
|
2
|
+
hmr-0.6.0.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
|
3
|
+
hmr-0.6.0.dist-info/entry_points.txt,sha256=g_T0uJ43WgsdG14kkkdaBQuIL0HO-m1qvtjXMP6d060,59
|
4
|
+
reactivity/__init__.py,sha256=pX-RUzkezCC1x4eOWGxNhXbwrbvBLP_3pQuZr9eZz1Y,300
|
5
|
+
reactivity/context.py,sha256=Iuq1uXYJjQeizOucocu56ObGy5O_sb7Q-mXeKJzAwMA,1239
|
6
|
+
reactivity/functional.py,sha256=jJLEq88w5ag2cXuD1T118uEjnEg37_mqvWmFkb47KVY,1300
|
7
|
+
reactivity/helpers.py,sha256=MoIU6UmvPDC31HW5mQn2kFKJZNjrzioLXXEyYQMHUuw,5820
|
8
|
+
reactivity/hmr/__init__.py,sha256=S5ZIHqCRpevdzWuhS0aCua_S8F0LkK0YNg6IgeTScFQ,177
|
9
|
+
reactivity/hmr/__main__.py,sha256=uIcyjR5gMFIXH_3hS0B3SD00RirVf7GIct-uItx675o,64
|
10
|
+
reactivity/hmr/api.py,sha256=ypS_LyzMH1JbN5cSwamAJ0HEcHMOY7BOIINuJmWJwo8,2283
|
11
|
+
reactivity/hmr/core.py,sha256=OMgjdnvv6QWUmDmJxInuT93RwWuwNSicHTdgF0k4vL4,11835
|
12
|
+
reactivity/hmr/hooks.py,sha256=jIFpe4CNxfaS9RcR4OIodx_sOZlnJ_IA1T1RtHPXhwU,945
|
13
|
+
reactivity/hmr/utils.py,sha256=h9m7iRXlvsLTrHoXV9gEVbhz3XsPK4KgnStYoCAWE5I,1616
|
14
|
+
reactivity/primitives.py,sha256=z69PqQxizN2sbursmpKW5SlWshlZZzdLgFH9u8E5eZc,6857
|
15
|
+
hmr-0.6.0.dist-info/RECORD,,
|
reactivity/context.py
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections.abc import Iterable
|
4
|
+
from contextlib import contextmanager
|
5
|
+
from functools import partial
|
6
|
+
from typing import TYPE_CHECKING, NamedTuple
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from .primitives import BaseComputation, Batch
|
10
|
+
|
11
|
+
|
12
|
+
class Context(NamedTuple):
|
13
|
+
current_computations: list[BaseComputation]
|
14
|
+
batches: list[Batch]
|
15
|
+
|
16
|
+
def schedule_callbacks(self, callbacks: Iterable[BaseComputation]):
|
17
|
+
self.batches[-1].callbacks.update(callbacks)
|
18
|
+
|
19
|
+
@contextmanager
|
20
|
+
def enter(self, computation: BaseComputation):
|
21
|
+
computation.dispose()
|
22
|
+
self.current_computations.append(computation)
|
23
|
+
try:
|
24
|
+
yield
|
25
|
+
finally:
|
26
|
+
last = self.current_computations.pop()
|
27
|
+
assert last is computation # sanity check
|
28
|
+
|
29
|
+
@property
|
30
|
+
def batch(self):
|
31
|
+
from .primitives import Batch
|
32
|
+
|
33
|
+
return partial(Batch, context=self)
|
34
|
+
|
35
|
+
@property
|
36
|
+
def signal(self):
|
37
|
+
from .primitives import Signal
|
38
|
+
|
39
|
+
return partial(Signal, context=self)
|
40
|
+
|
41
|
+
@property
|
42
|
+
def effect(self):
|
43
|
+
from .primitives import Effect
|
44
|
+
|
45
|
+
return partial(Effect, context=self)
|
46
|
+
|
47
|
+
|
48
|
+
def new_context():
|
49
|
+
return Context([], [])
|
50
|
+
|
51
|
+
|
52
|
+
default_context = new_context()
|
reactivity/helpers.py
CHANGED
@@ -3,23 +3,21 @@ from collections.abc import Callable, Mapping, MutableMapping
|
|
3
3
|
from typing import Self, overload
|
4
4
|
from weakref import WeakKeyDictionary
|
5
5
|
|
6
|
+
from .context import Context
|
6
7
|
from .primitives import BaseComputation, Batch, Derived, Signal, Subscribable
|
7
8
|
|
8
9
|
|
9
10
|
class Memoized[T](Subscribable, BaseComputation[T]):
|
10
|
-
def __init__(self, fn: Callable[[], T]):
|
11
|
-
super().__init__()
|
11
|
+
def __init__(self, fn: Callable[[], T], *, context: Context | None = None):
|
12
|
+
super().__init__(context=context)
|
12
13
|
self.fn = fn
|
13
14
|
self.is_stale = True
|
14
15
|
self.cached_value: T
|
15
16
|
|
16
17
|
def recompute(self):
|
17
|
-
self.
|
18
|
-
try:
|
18
|
+
with self._enter():
|
19
19
|
self.cached_value = self.fn()
|
20
20
|
self.is_stale = False
|
21
|
-
finally:
|
22
|
-
self._after()
|
23
21
|
|
24
22
|
def trigger(self):
|
25
23
|
self.invalidate()
|
@@ -38,10 +36,11 @@ class Memoized[T](Subscribable, BaseComputation[T]):
|
|
38
36
|
|
39
37
|
|
40
38
|
class MemoizedProperty[T, I]:
|
41
|
-
def __init__(self, method: Callable[[I], T]):
|
39
|
+
def __init__(self, method: Callable[[I], T], *, context: Context | None = None):
|
42
40
|
super().__init__()
|
43
41
|
self.method = method
|
44
42
|
self.map = WeakKeyDictionary[I, Memoized[T]]()
|
43
|
+
self.context = context
|
45
44
|
|
46
45
|
@overload
|
47
46
|
def __get__(self, instance: None, owner: type[I]) -> Self: ...
|
@@ -53,15 +52,16 @@ class MemoizedProperty[T, I]:
|
|
53
52
|
return self
|
54
53
|
if func := self.map.get(instance):
|
55
54
|
return func()
|
56
|
-
self.map[instance] = func = Memoized(self.method.__get__(instance, owner))
|
55
|
+
self.map[instance] = func = Memoized(self.method.__get__(instance, owner), context=self.context)
|
57
56
|
return func()
|
58
57
|
|
59
58
|
|
60
59
|
class MemoizedMethod[T, I]:
|
61
|
-
def __init__(self, method: Callable[[I], T]):
|
60
|
+
def __init__(self, method: Callable[[I], T], *, context: Context | None = None):
|
62
61
|
super().__init__()
|
63
62
|
self.method = method
|
64
63
|
self.map = WeakKeyDictionary[I, Memoized[T]]()
|
64
|
+
self.context = context
|
65
65
|
|
66
66
|
@overload
|
67
67
|
def __get__(self, instance: None, owner: type[I]) -> Self: ...
|
@@ -73,7 +73,7 @@ class MemoizedMethod[T, I]:
|
|
73
73
|
return self
|
74
74
|
if memo := self.map.get(instance):
|
75
75
|
return memo
|
76
|
-
self.map[instance] = memo = Memoized(self.method.__get__(instance, owner))
|
76
|
+
self.map[instance] = memo = Memoized(self.method.__get__(instance, owner), context=self.context)
|
77
77
|
return memo
|
78
78
|
|
79
79
|
|
@@ -86,9 +86,9 @@ class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
|
86
86
|
def _null(self):
|
87
87
|
return Signal(self.UNSET, self._check_equality)
|
88
88
|
|
89
|
-
def __init__(self, initial: Mapping[K, V] | None = None, check_equality=True):
|
90
|
-
super().__init__()
|
91
|
-
self._signals = defaultdict[K, Signal[V]](self._null) if initial is None else defaultdict(self._null, {k: Signal(v, check_equality) for k, v in initial.items()})
|
89
|
+
def __init__(self, initial: Mapping[K, V] | None = None, check_equality=True, *, context: Context | None = None):
|
90
|
+
super().__init__(context=context)
|
91
|
+
self._signals = defaultdict[K, Signal[V]](self._null) if initial is None else defaultdict(self._null, {k: Signal(v, check_equality, context=context) for k, v in initial.items()})
|
92
92
|
self._check_equality = check_equality
|
93
93
|
|
94
94
|
def __getitem__(self, key: K):
|
@@ -98,7 +98,7 @@ class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
|
98
98
|
return value
|
99
99
|
|
100
100
|
def __setitem__(self, key: K, value: V):
|
101
|
-
with Batch(force_flush=False):
|
101
|
+
with Batch(force_flush=False, context=self.context):
|
102
102
|
if self._signals[key].set(value):
|
103
103
|
self.notify()
|
104
104
|
|
@@ -106,7 +106,7 @@ class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
|
106
106
|
state = self._signals[key]
|
107
107
|
if state.get(track=False) is self.UNSET:
|
108
108
|
raise KeyError(key)
|
109
|
-
with Batch(force_flush=False):
|
109
|
+
with Batch(force_flush=False, context=self.context):
|
110
110
|
state.set(self.UNSET)
|
111
111
|
self.notify()
|
112
112
|
|
@@ -131,10 +131,11 @@ class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
|
131
131
|
|
132
132
|
|
133
133
|
class DerivedProperty[T, I]:
|
134
|
-
def __init__(self, method: Callable[[I], T]):
|
134
|
+
def __init__(self, method: Callable[[I], T], *, context: Context | None = None):
|
135
135
|
super().__init__()
|
136
136
|
self.method = method
|
137
137
|
self.map = WeakKeyDictionary[I, Derived[T]]()
|
138
|
+
self.context = context
|
138
139
|
|
139
140
|
@overload
|
140
141
|
def __get__(self, instance: None, owner: type[I]) -> Self: ...
|
@@ -146,16 +147,17 @@ class DerivedProperty[T, I]:
|
|
146
147
|
return self
|
147
148
|
if func := self.map.get(instance):
|
148
149
|
return func()
|
149
|
-
self.map[instance] = func = Derived(self.method.__get__(instance, owner))
|
150
|
+
self.map[instance] = func = Derived(self.method.__get__(instance, owner), context=self.context)
|
150
151
|
return func()
|
151
152
|
|
152
153
|
|
153
154
|
class DerivedMethod[T, I]:
|
154
|
-
def __init__(self, method: Callable[[I], T], check_equality=True):
|
155
|
+
def __init__(self, method: Callable[[I], T], check_equality=True, *, context: Context | None = None):
|
155
156
|
super().__init__()
|
156
157
|
self.method = method
|
157
158
|
self.check_equality = check_equality
|
158
159
|
self.map = WeakKeyDictionary[I, Derived[T]]()
|
160
|
+
self.context = context
|
159
161
|
|
160
162
|
@overload
|
161
163
|
def __get__(self, instance: None, owner: type[I]) -> Self: ...
|
@@ -168,5 +170,5 @@ class DerivedMethod[T, I]:
|
|
168
170
|
if func := self.map.get(instance):
|
169
171
|
return func
|
170
172
|
|
171
|
-
self.map[instance] = func = Derived(self.method.__get__(instance, owner), self.check_equality)
|
173
|
+
self.map[instance] = func = Derived(self.method.__get__(instance, owner), self.check_equality, context=self.context)
|
172
174
|
return func
|
reactivity/hmr/api.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import sys
|
2
2
|
|
3
|
-
from .core import AsyncReloader, BaseReloader, SyncReloader
|
3
|
+
from .core import HMR_CONTEXT, AsyncReloader, BaseReloader, SyncReloader
|
4
4
|
from .hooks import call_post_reload_hooks, call_pre_reload_hooks
|
5
5
|
|
6
6
|
|
@@ -9,7 +9,7 @@ class LifecycleMixin(BaseReloader):
|
|
9
9
|
self._original_main_module = sys.modules["__main__"]
|
10
10
|
sys.modules["__main__"] = self.entry_module
|
11
11
|
call_pre_reload_hooks()
|
12
|
-
self.effect =
|
12
|
+
self.effect = HMR_CONTEXT.effect(self.run_entry_file)
|
13
13
|
call_post_reload_hooks()
|
14
14
|
|
15
15
|
def clean_up(self):
|
reactivity/hmr/core.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import sys
|
2
2
|
from collections.abc import Iterable, MutableMapping, Sequence
|
3
3
|
from contextlib import suppress
|
4
|
-
from functools import cached_property
|
4
|
+
from functools import cached_property, partial
|
5
5
|
from importlib.abc import Loader, MetaPathFinder
|
6
6
|
from importlib.machinery import ModuleSpec
|
7
7
|
from importlib.util import spec_from_loader
|
@@ -12,8 +12,8 @@ from types import ModuleType, TracebackType
|
|
12
12
|
from typing import Any, Self
|
13
13
|
from weakref import WeakValueDictionary
|
14
14
|
|
15
|
-
from .. import Reactive
|
16
|
-
from ..
|
15
|
+
from .. import Reactive
|
16
|
+
from ..context import new_context
|
17
17
|
from ..helpers import DerivedMethod
|
18
18
|
from ..primitives import BaseDerived, Derived, Signal
|
19
19
|
from .hooks import call_post_reload_hooks, call_pre_reload_hooks
|
@@ -36,14 +36,17 @@ class Name(Signal, BaseDerived):
|
|
36
36
|
pass
|
37
37
|
|
38
38
|
|
39
|
+
HMR_CONTEXT = new_context()
|
40
|
+
|
41
|
+
|
39
42
|
class NamespaceProxy(Reactive[str, Any]):
|
40
43
|
def __init__(self, initial: MutableMapping, module: "ReactiveModule", check_equality=True):
|
41
|
-
super().__init__(initial, check_equality)
|
44
|
+
super().__init__(initial, check_equality, context=HMR_CONTEXT)
|
42
45
|
self._original = initial
|
43
46
|
self.module = module
|
44
47
|
|
45
48
|
def _null(self):
|
46
|
-
self.module.load.subscribers.add(signal := Name(self.UNSET, self._check_equality))
|
49
|
+
self.module.load.subscribers.add(signal := Name(self.UNSET, self._check_equality, context=HMR_CONTEXT))
|
47
50
|
signal.dependencies.add(self.module.load)
|
48
51
|
return signal
|
49
52
|
|
@@ -87,7 +90,7 @@ class ReactiveModule(ModuleType):
|
|
87
90
|
return self.__file
|
88
91
|
raise AttributeError("file")
|
89
92
|
|
90
|
-
@DerivedMethod
|
93
|
+
@partial(DerivedMethod, context=HMR_CONTEXT)
|
91
94
|
def __load(self):
|
92
95
|
try:
|
93
96
|
code = compile(self.__file.read_text("utf-8"), str(self.__file), "exec", dont_inherit=True)
|
@@ -253,7 +256,7 @@ class BaseReloader:
|
|
253
256
|
|
254
257
|
call_pre_reload_hooks()
|
255
258
|
|
256
|
-
with batch():
|
259
|
+
with HMR_CONTEXT.batch():
|
257
260
|
for type, file in events:
|
258
261
|
if type is not Change.deleted:
|
259
262
|
path = Path(file).resolve()
|
@@ -297,7 +300,7 @@ class SyncReloader(BaseReloader):
|
|
297
300
|
|
298
301
|
def keep_watching_until_interrupt(self):
|
299
302
|
call_pre_reload_hooks()
|
300
|
-
with suppress(KeyboardInterrupt),
|
303
|
+
with suppress(KeyboardInterrupt), HMR_CONTEXT.effect(self.run_entry_file):
|
301
304
|
call_post_reload_hooks()
|
302
305
|
self.start_watching()
|
303
306
|
|
@@ -322,7 +325,7 @@ class AsyncReloader(BaseReloader):
|
|
322
325
|
|
323
326
|
async def keep_watching_until_interrupt(self):
|
324
327
|
call_pre_reload_hooks()
|
325
|
-
with suppress(KeyboardInterrupt),
|
328
|
+
with suppress(KeyboardInterrupt), HMR_CONTEXT.effect(self.run_entry_file):
|
326
329
|
call_post_reload_hooks()
|
327
330
|
await self.start_watching()
|
328
331
|
|
@@ -335,10 +338,10 @@ def cli():
|
|
335
338
|
entry = sys.argv[0]
|
336
339
|
if not (path := Path(entry)).is_file():
|
337
340
|
raise FileNotFoundError(path.resolve())
|
338
|
-
sys.path.insert(0,
|
341
|
+
sys.path.insert(0, str(path.parent.resolve()))
|
339
342
|
reloader = SyncReloader(entry)
|
340
343
|
sys.modules["__main__"] = reloader.entry_module
|
341
344
|
reloader.keep_watching_until_interrupt()
|
342
345
|
|
343
346
|
|
344
|
-
__version__ = "0.
|
347
|
+
__version__ = "0.6.0"
|
reactivity/primitives.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
from collections.abc import Callable
|
1
|
+
from collections.abc import Callable
|
2
2
|
from typing import Any, Self, overload
|
3
3
|
from weakref import WeakKeyDictionary, WeakSet
|
4
4
|
|
5
|
+
from .context import Context, default_context
|
6
|
+
|
5
7
|
|
6
8
|
def _equal(a, b):
|
7
9
|
if a is b:
|
@@ -22,43 +24,40 @@ def _equal(a, b):
|
|
22
24
|
|
23
25
|
|
24
26
|
class Subscribable:
|
25
|
-
def __init__(self):
|
27
|
+
def __init__(self, *, context: Context | None = None):
|
26
28
|
super().__init__()
|
27
29
|
self.subscribers = set[BaseComputation]()
|
30
|
+
self.context = context or default_context
|
28
31
|
|
29
32
|
def track(self):
|
30
|
-
if not
|
33
|
+
if not self.context.current_computations:
|
31
34
|
return
|
32
|
-
last =
|
35
|
+
last = self.context.current_computations[-1]
|
33
36
|
if last is not self:
|
34
37
|
self.subscribers.add(last)
|
35
38
|
last.dependencies.add(self)
|
36
39
|
|
37
40
|
def notify(self):
|
38
|
-
if
|
39
|
-
schedule_callbacks(self.subscribers)
|
41
|
+
if self.context.batches:
|
42
|
+
self.context.schedule_callbacks(self.subscribers)
|
40
43
|
else:
|
41
|
-
with Batch(force_flush=False):
|
42
|
-
schedule_callbacks(self.subscribers)
|
44
|
+
with Batch(force_flush=False, context=self.context):
|
45
|
+
self.context.schedule_callbacks(self.subscribers)
|
43
46
|
|
44
47
|
|
45
48
|
class BaseComputation[T]:
|
46
|
-
def __init__(self):
|
49
|
+
def __init__(self, *, context: Context | None = None):
|
47
50
|
super().__init__()
|
48
51
|
self.dependencies = WeakSet[Subscribable]()
|
52
|
+
self.context = context or default_context
|
49
53
|
|
50
54
|
def dispose(self):
|
51
55
|
for dep in self.dependencies:
|
52
56
|
dep.subscribers.remove(self)
|
53
57
|
self.dependencies.clear()
|
54
58
|
|
55
|
-
def
|
56
|
-
self.
|
57
|
-
_current_computations.append(self)
|
58
|
-
|
59
|
-
def _after(self):
|
60
|
-
last = _current_computations.pop()
|
61
|
-
assert last is self # sanity check
|
59
|
+
def _enter(self):
|
60
|
+
return self.context.enter(self)
|
62
61
|
|
63
62
|
def __enter__(self):
|
64
63
|
return self
|
@@ -72,12 +71,9 @@ class BaseComputation[T]:
|
|
72
71
|
return self.trigger()
|
73
72
|
|
74
73
|
|
75
|
-
_current_computations: list[BaseComputation] = []
|
76
|
-
|
77
|
-
|
78
74
|
class Signal[T](Subscribable):
|
79
|
-
def __init__(self, initial_value: T = None, check_equality=True):
|
80
|
-
super().__init__()
|
75
|
+
def __init__(self, initial_value: T = None, check_equality=True, *, context: Context | None = None):
|
76
|
+
super().__init__(context=context)
|
81
77
|
self._value: T = initial_value
|
82
78
|
self._check_equality = check_equality
|
83
79
|
|
@@ -95,8 +91,8 @@ class Signal[T](Subscribable):
|
|
95
91
|
|
96
92
|
|
97
93
|
class State[T](Signal[T]):
|
98
|
-
def __init__(self, initial_value: T = None, check_equality=True):
|
99
|
-
super().__init__(initial_value, check_equality)
|
94
|
+
def __init__(self, initial_value: T = None, check_equality=True, *, context: Context | None = None):
|
95
|
+
super().__init__(initial_value, check_equality, context=context)
|
100
96
|
self._value = initial_value
|
101
97
|
self._check_equality = check_equality
|
102
98
|
self.map = WeakKeyDictionary[Any, Signal[T]]()
|
@@ -112,20 +108,20 @@ class State[T](Signal[T]):
|
|
112
108
|
try:
|
113
109
|
return self.map[instance].get()
|
114
110
|
except KeyError:
|
115
|
-
self.map[instance] = state = Signal(self._value, self._check_equality)
|
111
|
+
self.map[instance] = state = Signal(self._value, self._check_equality, context=self.context)
|
116
112
|
return state.get()
|
117
113
|
|
118
114
|
def __set__(self, instance, value: T):
|
119
115
|
try:
|
120
116
|
state = self.map[instance]
|
121
117
|
except KeyError:
|
122
|
-
self.map[instance] = state = Signal(self._value, self._check_equality)
|
118
|
+
self.map[instance] = state = Signal(self._value, self._check_equality, context=self.context)
|
123
119
|
state.set(value)
|
124
120
|
|
125
121
|
|
126
122
|
class Effect[T](BaseComputation[T]):
|
127
|
-
def __init__(self, fn: Callable[[], T], call_immediately=True):
|
128
|
-
super().__init__()
|
123
|
+
def __init__(self, fn: Callable[[], T], call_immediately=True, *, context: Context | None = None):
|
124
|
+
super().__init__(context=context)
|
129
125
|
|
130
126
|
self._fn = fn
|
131
127
|
|
@@ -133,17 +129,15 @@ class Effect[T](BaseComputation[T]):
|
|
133
129
|
self()
|
134
130
|
|
135
131
|
def trigger(self):
|
136
|
-
self.
|
137
|
-
try:
|
132
|
+
with self._enter():
|
138
133
|
return self._fn()
|
139
|
-
finally:
|
140
|
-
self._after()
|
141
134
|
|
142
135
|
|
143
136
|
class Batch:
|
144
|
-
def __init__(self, force_flush=True):
|
137
|
+
def __init__(self, force_flush=True, *, context: Context | None = None):
|
145
138
|
self.callbacks = set[BaseComputation]()
|
146
139
|
self.force_flush = force_flush
|
140
|
+
self.context = context or default_context
|
147
141
|
|
148
142
|
def flush(self):
|
149
143
|
triggered = set()
|
@@ -157,30 +151,23 @@ class Batch:
|
|
157
151
|
triggered.add(computation)
|
158
152
|
|
159
153
|
def __enter__(self):
|
160
|
-
|
154
|
+
self.context.batches.append(self)
|
161
155
|
|
162
156
|
def __exit__(self, *_):
|
163
|
-
if self.force_flush or len(
|
157
|
+
if self.force_flush or len(self.context.batches) == 1:
|
164
158
|
try:
|
165
159
|
self.flush()
|
166
160
|
finally:
|
167
|
-
last =
|
161
|
+
last = self.context.batches.pop()
|
168
162
|
else:
|
169
|
-
last =
|
170
|
-
schedule_callbacks(self.callbacks)
|
163
|
+
last = self.context.batches.pop()
|
164
|
+
self.context.schedule_callbacks(self.callbacks)
|
171
165
|
assert last is self
|
172
166
|
|
173
167
|
|
174
|
-
_batches: list[Batch] = []
|
175
|
-
|
176
|
-
|
177
|
-
def schedule_callbacks(callbacks: Iterable[BaseComputation]):
|
178
|
-
_batches[-1].callbacks.update(callbacks)
|
179
|
-
|
180
|
-
|
181
168
|
class BaseDerived[T](Subscribable, BaseComputation[T]):
|
182
|
-
def __init__(self):
|
183
|
-
super().__init__()
|
169
|
+
def __init__(self, *, context: Context | None = None):
|
170
|
+
super().__init__(context=context)
|
184
171
|
self.dirty = True
|
185
172
|
|
186
173
|
def _sync_dirty_deps(self):
|
@@ -192,15 +179,14 @@ class BaseDerived[T](Subscribable, BaseComputation[T]):
|
|
192
179
|
class Derived[T](BaseDerived[T]):
|
193
180
|
UNSET: T = object() # type: ignore
|
194
181
|
|
195
|
-
def __init__(self, fn: Callable[[], T], check_equality=True):
|
196
|
-
super().__init__()
|
182
|
+
def __init__(self, fn: Callable[[], T], check_equality=True, *, context: Context | None = None):
|
183
|
+
super().__init__(context=context)
|
197
184
|
self.fn = fn
|
198
185
|
self._check_equality = check_equality
|
199
186
|
self._value = self.UNSET
|
200
187
|
|
201
188
|
def recompute(self):
|
202
|
-
self.
|
203
|
-
try:
|
189
|
+
with self._enter():
|
204
190
|
value = self.fn()
|
205
191
|
self.dirty = False
|
206
192
|
if self._check_equality:
|
@@ -211,8 +197,6 @@ class Derived[T](BaseDerived[T]):
|
|
211
197
|
return
|
212
198
|
self._value = value
|
213
199
|
self.notify()
|
214
|
-
finally:
|
215
|
-
self._after()
|
216
200
|
|
217
201
|
def __call__(self):
|
218
202
|
self.track()
|
hmr-0.5.2.3.dist-info/RECORD
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
hmr-0.5.2.3.dist-info/METADATA,sha256=brOwFOjTaxu3v-7VKwtAyecOo1zq1-hCEbW0zdXf6yA,2001
|
2
|
-
hmr-0.5.2.3.dist-info/WHEEL,sha256=tSfRZzRHthuv7vxpI4aehrdN9scLjk-dCJkPLzkHxGg,90
|
3
|
-
hmr-0.5.2.3.dist-info/entry_points.txt,sha256=g_T0uJ43WgsdG14kkkdaBQuIL0HO-m1qvtjXMP6d060,59
|
4
|
-
reactivity/__init__.py,sha256=pX-RUzkezCC1x4eOWGxNhXbwrbvBLP_3pQuZr9eZz1Y,300
|
5
|
-
reactivity/functional.py,sha256=jJLEq88w5ag2cXuD1T118uEjnEg37_mqvWmFkb47KVY,1300
|
6
|
-
reactivity/helpers.py,sha256=rcrCXy1mmlei-if_BN4nSgS2IG9kBj-jq1YRwEfcITo,5329
|
7
|
-
reactivity/hmr/__init__.py,sha256=S5ZIHqCRpevdzWuhS0aCua_S8F0LkK0YNg6IgeTScFQ,177
|
8
|
-
reactivity/hmr/__main__.py,sha256=uIcyjR5gMFIXH_3hS0B3SD00RirVf7GIct-uItx675o,64
|
9
|
-
reactivity/hmr/api.py,sha256=sKDQV7uKRVoDifTZKrLQGZP-fzgYbdVjfEOC6ki4NKY,2280
|
10
|
-
reactivity/hmr/core.py,sha256=JZcnF3fKpcNMiL6XKMZVjjLRxAods0I7I0BkwrVYZbU,11693
|
11
|
-
reactivity/hmr/hooks.py,sha256=jIFpe4CNxfaS9RcR4OIodx_sOZlnJ_IA1T1RtHPXhwU,945
|
12
|
-
reactivity/hmr/utils.py,sha256=h9m7iRXlvsLTrHoXV9gEVbhz3XsPK4KgnStYoCAWE5I,1616
|
13
|
-
reactivity/primitives.py,sha256=alFH1W7y2UHgXI3Vlk8GFdIlcFTcQ3Q9cpz2Y1vDZuQ,6553
|
14
|
-
hmr-0.5.2.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|