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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hmr
3
- Version: 0.0.2.2
3
+ Version: 0.0.3.1
4
4
  Summary: Hot Module Reload for Python
5
5
  Project-URL: repository, https://github.com/promplate/pyth-on-line/tree/reactivity
6
6
  Requires-Python: >=3.12
@@ -6,7 +6,7 @@ description = "Hot Module Reload for Python"
6
6
  dependencies = [
7
7
  "watchfiles>=0.21,<2",
8
8
  ]
9
- version = "0.0.2.2"
9
+ version = "0.0.3.1"
10
10
 
11
11
  [project.scripts]
12
12
  hmr = "reactivity.hmr:cli"
@@ -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, Derived, Signal
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], auto_run=True):
23
- return Derived(fn, auto_run)
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, Self](method: Callable[[Self], 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, Self](method: Callable[[Self], 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, Self]:
40
- def __init__(self, method: Callable[[Self], T]):
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[Self, Memoized]()
45
+ self.map = WeakKeyDictionary[I, Memoized[T]]()
44
46
 
45
- def __get__(self, instance, owner):
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, Self]:
53
- def __init__(self, method: Callable[[Self], T]):
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[Self, Memoized]()
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
- try:
60
- return self.map[instance]
61
- except KeyError:
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 __init__(self, initial: Mapping | None = None, check_equality=True):
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: dict[K, Signal[V]] = {} if initial is None else {k: Signal(v, check_equality) for k, v in initial.items()}
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.setdefault(key, Signal(self.UNSET, self._check_equality)).get()
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
- try:
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 lambda: exec(self.__file.read_text("utf-8"), self.__namespace, self.__namespace_proxy)
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.2.2"
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 Derived[T](BaseComputation[T]):
98
- def __init__(self, fn: Callable[[], T], auto_run=True):
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 auto_run:
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"]