hmr 0.0.2.2__tar.gz → 0.0.3.1__tar.gz
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.0.2.2 → hmr-0.0.3.1}/PKG-INFO +1 -1
- {hmr-0.0.2.2 → hmr-0.0.3.1}/pyproject.toml +1 -1
- hmr-0.0.3.1/reactivity/__init__.py +5 -0
- {hmr-0.0.2.2 → hmr-0.0.3.1}/reactivity/functional.py +5 -5
- {hmr-0.0.2.2 → hmr-0.0.3.1}/reactivity/helpers.py +34 -21
- {hmr-0.0.2.2 → hmr-0.0.3.1}/reactivity/hmr.py +21 -4
- {hmr-0.0.2.2 → hmr-0.0.3.1}/reactivity/primitives.py +11 -4
- hmr-0.0.2.2/reactivity/__init__.py +0 -5
@@ -0,0 +1,5 @@
|
|
1
|
+
from .functional import batch, create_effect, create_memo, create_signal, memoized_method, memoized_property
|
2
|
+
from .helpers import Reactive
|
3
|
+
from .primitives import State
|
4
|
+
|
5
|
+
__all__ = ["Reactive", "State", "batch", "create_effect", "create_memo", "create_signal", "memoized_method", "memoized_property"]
|
@@ -3,7 +3,7 @@ from functools import wraps
|
|
3
3
|
from typing import Protocol, overload
|
4
4
|
|
5
5
|
from .helpers import Memoized, MemoizedMethod, MemoizedProperty
|
6
|
-
from .primitives import Batch,
|
6
|
+
from .primitives import Batch, Effect, Signal
|
7
7
|
|
8
8
|
|
9
9
|
class Getter[T](Protocol):
|
@@ -19,19 +19,19 @@ def create_signal[T](initial_value: T = None, check_equality=True) -> tuple[Gett
|
|
19
19
|
return signal.get, signal.set
|
20
20
|
|
21
21
|
|
22
|
-
def create_effect[T](fn: Callable[[], T],
|
23
|
-
return
|
22
|
+
def create_effect[T](fn: Callable[[], T], call_immediately=True):
|
23
|
+
return Effect(fn, call_immediately)
|
24
24
|
|
25
25
|
|
26
26
|
def create_memo[T](fn: Callable[[], T]):
|
27
27
|
return Memoized(fn)
|
28
28
|
|
29
29
|
|
30
|
-
def memoized_property[T,
|
30
|
+
def memoized_property[T, I](method: Callable[[I], T]):
|
31
31
|
return MemoizedProperty(method)
|
32
32
|
|
33
33
|
|
34
|
-
def memoized_method[T,
|
34
|
+
def memoized_method[T, I](method: Callable[[I], T]):
|
35
35
|
return MemoizedMethod(method)
|
36
36
|
|
37
37
|
|
@@ -1,5 +1,7 @@
|
|
1
|
+
from collections import defaultdict
|
1
2
|
from collections.abc import Callable, Mapping, MutableMapping
|
2
3
|
from functools import partial
|
4
|
+
from typing import Self, overload
|
3
5
|
from weakref import WeakKeyDictionary
|
4
6
|
|
5
7
|
from .primitives import BaseComputation, Batch, Signal, Subscribable
|
@@ -36,31 +38,44 @@ class Memoized[T](Subscribable, BaseComputation[T]):
|
|
36
38
|
self.is_stale = True
|
37
39
|
|
38
40
|
|
39
|
-
class MemoizedProperty[T,
|
40
|
-
def __init__(self, method: Callable[[
|
41
|
+
class MemoizedProperty[T, I]:
|
42
|
+
def __init__(self, method: Callable[[I], T]):
|
41
43
|
super().__init__()
|
42
44
|
self.method = method
|
43
|
-
self.map = WeakKeyDictionary[
|
45
|
+
self.map = WeakKeyDictionary[I, Memoized[T]]()
|
44
46
|
|
45
|
-
|
47
|
+
@overload
|
48
|
+
def __get__(self, instance: None, owner: type[I]) -> Self: ...
|
49
|
+
@overload
|
50
|
+
def __get__(self, instance: I, owner: type[I]) -> T: ...
|
51
|
+
|
52
|
+
def __get__(self, instance: I | None, owner):
|
53
|
+
if instance is None:
|
54
|
+
return self
|
46
55
|
if func := self.map.get(instance):
|
47
56
|
return func()
|
48
57
|
self.map[instance] = func = Memoized(partial(self.method, instance))
|
49
58
|
return func()
|
50
59
|
|
51
60
|
|
52
|
-
class MemoizedMethod[T,
|
53
|
-
def __init__(self, method: Callable[[
|
61
|
+
class MemoizedMethod[T, I]:
|
62
|
+
def __init__(self, method: Callable[[I], T]):
|
54
63
|
super().__init__()
|
55
64
|
self.method = method
|
56
|
-
self.map = WeakKeyDictionary[
|
65
|
+
self.map = WeakKeyDictionary[I, Memoized[T]]()
|
66
|
+
|
67
|
+
@overload
|
68
|
+
def __get__(self, instance: None, owner: type[I]) -> Self: ...
|
69
|
+
@overload
|
70
|
+
def __get__(self, instance: I, owner: type[I]) -> Memoized[T]: ...
|
57
71
|
|
58
|
-
def __get__(self, instance, owner):
|
59
|
-
|
60
|
-
return self
|
61
|
-
|
62
|
-
self.map[instance] = memo = Memoized(partial(self.method, instance))
|
72
|
+
def __get__(self, instance: I | None, owner):
|
73
|
+
if instance is None:
|
74
|
+
return self
|
75
|
+
if memo := self.map.get(instance):
|
63
76
|
return memo
|
77
|
+
self.map[instance] = memo = Memoized(partial(self.method, instance))
|
78
|
+
return memo
|
64
79
|
|
65
80
|
|
66
81
|
class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
@@ -69,24 +84,23 @@ class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
|
69
84
|
def __hash__(self):
|
70
85
|
return id(self)
|
71
86
|
|
72
|
-
def
|
87
|
+
def _null(self):
|
88
|
+
return Signal(self.UNSET, self._check_equality)
|
89
|
+
|
90
|
+
def __init__(self, initial: Mapping[K, V] | None = None, check_equality=True):
|
73
91
|
super().__init__()
|
74
|
-
self._signals
|
92
|
+
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()})
|
75
93
|
self._check_equality = check_equality
|
76
94
|
|
77
95
|
def __getitem__(self, key: K):
|
78
|
-
value = self._signals
|
96
|
+
value = self._signals[key].get()
|
79
97
|
if value is self.UNSET:
|
80
98
|
raise KeyError(key)
|
81
99
|
return value
|
82
100
|
|
83
101
|
def __setitem__(self, key: K, value: V):
|
84
102
|
with Batch():
|
85
|
-
|
86
|
-
self._signals[key].set(value)
|
87
|
-
except KeyError:
|
88
|
-
self._signals[key] = Signal(value, self._check_equality)
|
89
|
-
self._signals[key].set(value)
|
103
|
+
self._signals[key].set(value)
|
90
104
|
self.notify()
|
91
105
|
|
92
106
|
def __delitem__(self, key: K):
|
@@ -95,7 +109,6 @@ class Reactive[K, V](Subscribable, MutableMapping[K, V]):
|
|
95
109
|
raise KeyError(key)
|
96
110
|
with Batch():
|
97
111
|
state.set(self.UNSET)
|
98
|
-
state.notify()
|
99
112
|
self.notify()
|
100
113
|
|
101
114
|
def __iter__(self):
|
@@ -9,6 +9,7 @@ from inspect import currentframe
|
|
9
9
|
from pathlib import Path
|
10
10
|
from runpy import run_path
|
11
11
|
from types import ModuleType
|
12
|
+
from typing import Any
|
12
13
|
|
13
14
|
from . import Reactive, batch, create_effect, memoized_method
|
14
15
|
|
@@ -26,7 +27,7 @@ def is_called_in_this_file() -> bool:
|
|
26
27
|
return frame.f_globals.get("__file__") == __file__
|
27
28
|
|
28
29
|
|
29
|
-
class NamespaceProxy(Reactive):
|
30
|
+
class NamespaceProxy(Reactive[str, Any]):
|
30
31
|
def __init__(self, initial: MutableMapping, check_equality=True):
|
31
32
|
super().__init__(initial, check_equality)
|
32
33
|
self._original = initial
|
@@ -43,6 +44,10 @@ class NamespaceProxy(Reactive):
|
|
43
44
|
class ReactiveModule(ModuleType):
|
44
45
|
def __init__(self, file: Path, namespace: dict, name: str, doc: str | None = None):
|
45
46
|
super().__init__(name, doc)
|
47
|
+
self.__is_initialized = False
|
48
|
+
self.__dict__.update(namespace)
|
49
|
+
self.__is_initialized = True
|
50
|
+
|
46
51
|
self.__namespace = namespace
|
47
52
|
self.__namespace_proxy = NamespaceProxy(namespace)
|
48
53
|
self.__file = file
|
@@ -53,12 +58,24 @@ class ReactiveModule(ModuleType):
|
|
53
58
|
return self.__file
|
54
59
|
raise AttributeError("file")
|
55
60
|
|
61
|
+
def __load(self):
|
62
|
+
code = compile(self.__file.read_text("utf-8"), str(self.__file), "exec", dont_inherit=True)
|
63
|
+
exec(code, self.__namespace, self.__namespace_proxy)
|
64
|
+
|
56
65
|
@property
|
57
66
|
def load(self):
|
58
67
|
if is_called_in_this_file():
|
59
|
-
return
|
68
|
+
return self.__load
|
60
69
|
raise AttributeError("load")
|
61
70
|
|
71
|
+
def __dir__(self):
|
72
|
+
return iter(self.__namespace_proxy)
|
73
|
+
|
74
|
+
def __getattribute__(self, name: str):
|
75
|
+
if name == "__dict__" and self.__is_initialized:
|
76
|
+
return self.__namespace
|
77
|
+
return super().__getattribute__(name)
|
78
|
+
|
62
79
|
def __getattr__(self, name: str):
|
63
80
|
try:
|
64
81
|
return self.__namespace_proxy[name]
|
@@ -78,7 +95,7 @@ class ReactiveModuleLoader(Loader):
|
|
78
95
|
self._is_package = is_package
|
79
96
|
|
80
97
|
def create_module(self, spec: ModuleSpec):
|
81
|
-
namespace = {}
|
98
|
+
namespace = {"__file__": str(self._file), "__spec__": spec, "__loader__": self}
|
82
99
|
if self._is_package:
|
83
100
|
assert self._file.name == "__init__.py"
|
84
101
|
namespace["__path__"] = [str(self._file.parent.parent)]
|
@@ -232,4 +249,4 @@ def cli():
|
|
232
249
|
SyncReloader(entry, excludes={".venv"}).keep_watching_until_interrupt()
|
233
250
|
|
234
251
|
|
235
|
-
__version__ = "0.0.
|
252
|
+
__version__ = "0.0.3.1"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from collections.abc import Callable
|
2
|
-
from typing import Any
|
2
|
+
from typing import Any, Self, overload
|
3
3
|
from weakref import WeakKeyDictionary, WeakSet
|
4
4
|
|
5
5
|
|
@@ -79,7 +79,14 @@ class State[T](Signal[T]):
|
|
79
79
|
self._check_equality = check_equality
|
80
80
|
self.map = WeakKeyDictionary[Any, Signal[T]]()
|
81
81
|
|
82
|
+
@overload
|
83
|
+
def __get__(self, instance: None, owner: type) -> Self: ...
|
84
|
+
@overload
|
85
|
+
def __get__(self, instance: Any, owner: type) -> T: ...
|
86
|
+
|
82
87
|
def __get__(self, instance, owner):
|
88
|
+
if instance is None:
|
89
|
+
return self
|
83
90
|
try:
|
84
91
|
return self.map[instance].get()
|
85
92
|
except KeyError:
|
@@ -94,13 +101,13 @@ class State[T](Signal[T]):
|
|
94
101
|
state.set(value)
|
95
102
|
|
96
103
|
|
97
|
-
class
|
98
|
-
def __init__(self, fn: Callable[[], T],
|
104
|
+
class Effect[T](BaseComputation[T]):
|
105
|
+
def __init__(self, fn: Callable[[], T], call_immediately=True):
|
99
106
|
super().__init__()
|
100
107
|
|
101
108
|
self._fn = fn
|
102
109
|
|
103
|
-
if
|
110
|
+
if call_immediately:
|
104
111
|
self()
|
105
112
|
|
106
113
|
def trigger(self):
|
@@ -1,5 +0,0 @@
|
|
1
|
-
from .functional import batch, create_effect, create_memo, create_signal, memoized_method, memoized_property
|
2
|
-
from .helpers import Reactive
|
3
|
-
from .primitives import Derived, State
|
4
|
-
|
5
|
-
__all__ = ["Derived", "Reactive", "State", "batch", "create_effect", "create_memo", "create_signal", "memoized_method", "memoized_property"]
|