Skip to content

from reactivity.hmr.core import *

STATIC_ATTRS module-attribute

STATIC_ATTRS = frozenset(
    (
        "__path__",
        "__dict__",
        "__spec__",
        "__name__",
        "__file__",
        "__loader__",
        "__package__",
        "__cached__",
    )
)

_loader module-attribute

_loader = ReactiveModuleLoader()

__version__ module-attribute

__version__ = '0.7.6.2'

Name

Bases: Signal, BaseDerived

Source code in reactivity/hmr/core.py
33
34
35
36
class Name(Signal, BaseDerived):
    def get(self, track=True):
        self._sync_dirty_deps()
        return super().get(track)

get

get(track=True)
Source code in reactivity/hmr/core.py
34
35
36
def get(self, track=True):
    self._sync_dirty_deps()
    return super().get(track)

NamespaceProxy

Bases: Proxy

Source code in reactivity/hmr/core.py
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class NamespaceProxy(Proxy):
    def __init__(self, initial: MutableMapping, module: "ReactiveModule", check_equality=True, *, context: Context | None = None):
        self.module = module
        super().__init__(initial, check_equality, context=context)

    def _signal(self, value=False):
        self.module.load.subscribers.add(signal := Name(value, self._check_equality, context=self.context))
        signal.dependencies.add(self.module.load)
        return signal

    def __getitem__(self, key):
        try:
            return super().__getitem__(key)
        finally:
            signal = self._keys[key]
            if self.module.load in signal.subscribers:
                # a module's loader shouldn't subscribe its variables
                signal.subscribers.remove(self.module.load)
                self.module.load.dependencies.remove(signal)

module instance-attribute

module = module

__init__

__init__(
    initial: MutableMapping,
    module: ReactiveModule,
    check_equality=True,
    *,
    context: Context | None = None,
)
Source code in reactivity/hmr/core.py
40
41
42
def __init__(self, initial: MutableMapping, module: "ReactiveModule", check_equality=True, *, context: Context | None = None):
    self.module = module
    super().__init__(initial, check_equality, context=context)

_signal

_signal(value=False)
Source code in reactivity/hmr/core.py
44
45
46
47
def _signal(self, value=False):
    self.module.load.subscribers.add(signal := Name(value, self._check_equality, context=self.context))
    signal.dependencies.add(self.module.load)
    return signal

__getitem__

__getitem__(key)
Source code in reactivity/hmr/core.py
49
50
51
52
53
54
55
56
57
def __getitem__(self, key):
    try:
        return super().__getitem__(key)
    finally:
        signal = self._keys[key]
        if self.module.load in signal.subscribers:
            # a module's loader shouldn't subscribe its variables
            signal.subscribers.remove(self.module.load)
            self.module.load.dependencies.remove(signal)

ReactiveModule

Bases: ModuleType

Source code in reactivity/hmr/core.py
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class ReactiveModule(ModuleType):
    instances: WeakValueDictionary[Path, Self] = WeakValueDictionary()

    def __init__(self, file: Path, namespace: dict, name: str, doc: str | None = None):
        super().__init__(name, doc)
        self.__is_initialized = False
        self.__dict__.update(namespace)
        self.__is_initialized = True

        self.__namespace = namespace
        self.__namespace_proxy = NamespaceProxy(namespace, self, context=HMR_CONTEXT)
        self.__hooks: list[Callable[[], Any]] = []
        self.__file = file

        __class__.instances[file.resolve()] = self

    @property
    def file(self):
        if is_called_internally(extra_depth=1):  # + 1 for `__getattribute__`
            return self.__file
        raise AttributeError("file")

    @property
    def register_dispose_callback(self):
        if is_called_internally(extra_depth=1):  # + 1 for `__getattribute__`
            return self.__hooks.append
        raise AttributeError("register_dispose_callback")

    @derived_method(context=HMR_CONTEXT)
    def __load(self):
        try:
            file = self.__file
            ast = parse(file.read_text("utf-8"), str(file))
            code = compile(ast, str(file), "exec", dont_inherit=True)
            self.__flags = code.co_flags
        except SyntaxError as e:
            sys.excepthook(type(e), e, e.__traceback__)
        else:
            for dispose in self.__hooks:
                with suppress(Exception):
                    dispose()
            self.__hooks.clear()
            self.__doc__ = get_docstring(ast)
            exec(code, self.__namespace, self.__namespace_proxy)  # https://github.com/python/cpython/issues/121306
            self.__namespace_proxy.update(self.__namespace)
        finally:
            load = self.__load
            assert ismethod(load.fn)  # for type narrowing
            for dep in list(load.dependencies):
                if isinstance(dep, Derived) and ismethod(dep.fn) and isinstance(dep.fn.__self__, ReactiveModule) and dep.fn.__func__ is load.fn.__func__:
                    # unsubscribe it because we want invalidation to be fine-grained
                    dep.subscribers.remove(load)
                    load.dependencies.remove(dep)

    @property
    def load(self):
        if is_called_internally(extra_depth=1):  # + 1 for `__getattribute__`
            return self.__load
        raise AttributeError("load")

    def __dir__(self):
        return iter(self.__namespace_proxy)

    def __getattribute__(self, name: str):
        if name == "__dict__" and self.__is_initialized:
            return self.__namespace
        if name == "instances":  # class-level attribute
            raise AttributeError(name)
        return super().__getattribute__(name)

    def __getattr__(self, name: str):
        try:
            return self.__namespace_proxy[name] if name not in STATIC_ATTRS else self.__namespace[name]
        except KeyError as e:
            if name not in STATIC_ATTRS and (getattr := self.__namespace_proxy.get("__getattr__")):
                return getattr(name)
            raise AttributeError(*e.args) from None

    def __setattr__(self, name: str, value):
        if is_called_internally():
            return super().__setattr__(name, value)
        self.__namespace_proxy[name] = value

instances class-attribute instance-attribute

instances: WeakValueDictionary[Path, Self] = (
    WeakValueDictionary()
)

__is_initialized instance-attribute

__is_initialized = True

__namespace instance-attribute

__namespace = namespace

__namespace_proxy instance-attribute

__namespace_proxy = NamespaceProxy(
    namespace, self, context=HMR_CONTEXT
)

__hooks instance-attribute

__hooks: list[Callable[[], Any]] = []

__file instance-attribute

__file = file

file property

file

register_dispose_callback property

register_dispose_callback

load property

load

__init__

__init__(
    file: Path,
    namespace: dict,
    name: str,
    doc: str | None = None,
)
Source code in reactivity/hmr/core.py
66
67
68
69
70
71
72
73
74
75
76
77
def __init__(self, file: Path, namespace: dict, name: str, doc: str | None = None):
    super().__init__(name, doc)
    self.__is_initialized = False
    self.__dict__.update(namespace)
    self.__is_initialized = True

    self.__namespace = namespace
    self.__namespace_proxy = NamespaceProxy(namespace, self, context=HMR_CONTEXT)
    self.__hooks: list[Callable[[], Any]] = []
    self.__file = file

    __class__.instances[file.resolve()] = self

__load

__load()
Source code in reactivity/hmr/core.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
@derived_method(context=HMR_CONTEXT)
def __load(self):
    try:
        file = self.__file
        ast = parse(file.read_text("utf-8"), str(file))
        code = compile(ast, str(file), "exec", dont_inherit=True)
        self.__flags = code.co_flags
    except SyntaxError as e:
        sys.excepthook(type(e), e, e.__traceback__)
    else:
        for dispose in self.__hooks:
            with suppress(Exception):
                dispose()
        self.__hooks.clear()
        self.__doc__ = get_docstring(ast)
        exec(code, self.__namespace, self.__namespace_proxy)  # https://github.com/python/cpython/issues/121306
        self.__namespace_proxy.update(self.__namespace)
    finally:
        load = self.__load
        assert ismethod(load.fn)  # for type narrowing
        for dep in list(load.dependencies):
            if isinstance(dep, Derived) and ismethod(dep.fn) and isinstance(dep.fn.__self__, ReactiveModule) and dep.fn.__func__ is load.fn.__func__:
                # unsubscribe it because we want invalidation to be fine-grained
                dep.subscribers.remove(load)
                load.dependencies.remove(dep)

__dir__

__dir__()
Source code in reactivity/hmr/core.py
123
124
def __dir__(self):
    return iter(self.__namespace_proxy)

__getattribute__

__getattribute__(name: str)
Source code in reactivity/hmr/core.py
126
127
128
129
130
131
def __getattribute__(self, name: str):
    if name == "__dict__" and self.__is_initialized:
        return self.__namespace
    if name == "instances":  # class-level attribute
        raise AttributeError(name)
    return super().__getattribute__(name)

__getattr__

__getattr__(name: str)
Source code in reactivity/hmr/core.py
133
134
135
136
137
138
139
def __getattr__(self, name: str):
    try:
        return self.__namespace_proxy[name] if name not in STATIC_ATTRS else self.__namespace[name]
    except KeyError as e:
        if name not in STATIC_ATTRS and (getattr := self.__namespace_proxy.get("__getattr__")):
            return getattr(name)
        raise AttributeError(*e.args) from None

__setattr__

__setattr__(name: str, value)
Source code in reactivity/hmr/core.py
141
142
143
144
def __setattr__(self, name: str, value):
    if is_called_internally():
        return super().__setattr__(name, value)
    self.__namespace_proxy[name] = value

ReactiveModuleLoader

Bases: Loader

Source code in reactivity/hmr/core.py
147
148
149
150
151
152
153
154
155
156
157
158
class ReactiveModuleLoader(Loader):
    def create_module(self, spec: ModuleSpec):
        assert spec.origin is not None, "This loader can only load file-backed modules"
        path = Path(spec.origin)
        namespace = {"__file__": spec.origin, "__spec__": spec, "__loader__": self, "__name__": spec.name, "__package__": spec.parent, "__cached__": None, "__builtins__": __builtins__}
        if spec.submodule_search_locations is not None:
            namespace["__path__"] = spec.submodule_search_locations[:] = [str(path.parent)]
        return ReactiveModule(path, namespace, spec.name)

    def exec_module(self, module: ModuleType):
        assert isinstance(module, ReactiveModule)
        module.load()

create_module

create_module(spec: ModuleSpec)
Source code in reactivity/hmr/core.py
148
149
150
151
152
153
154
def create_module(self, spec: ModuleSpec):
    assert spec.origin is not None, "This loader can only load file-backed modules"
    path = Path(spec.origin)
    namespace = {"__file__": spec.origin, "__spec__": spec, "__loader__": self, "__name__": spec.name, "__package__": spec.parent, "__cached__": None, "__builtins__": __builtins__}
    if spec.submodule_search_locations is not None:
        namespace["__path__"] = spec.submodule_search_locations[:] = [str(path.parent)]
    return ReactiveModule(path, namespace, spec.name)

exec_module

exec_module(module: ModuleType)
Source code in reactivity/hmr/core.py
156
157
158
def exec_module(self, module: ModuleType):
    assert isinstance(module, ReactiveModule)
    module.load()

ReactiveModuleFinder

Bases: MetaPathFinder

Source code in reactivity/hmr/core.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
class ReactiveModuleFinder(MetaPathFinder):
    def __init__(self, includes: Iterable[str] = ".", excludes: Iterable[str] = ()):
        super().__init__()
        builtins = map(get_paths().__getitem__, ("stdlib", "platstdlib", "platlib", "purelib"))
        self.includes = _deduplicate(includes)
        self.excludes = _deduplicate((getenv("VIRTUAL_ENV"), *getsitepackages(), getusersitepackages(), *builtins, *excludes))
        setup_fs_audithook()
        add_filter(lambda path: not is_relative_to_any(path, self.excludes) and is_relative_to_any(path, self.includes))

        self._last_sys_path: list[str] = []
        self._last_cwd: Path = Path()
        self._cached_search_paths: list[Path] = []

    def _accept(self, path: Path):
        return path.is_file() and not is_relative_to_any(path, self.excludes) and is_relative_to_any(path, self.includes)

    @property
    def search_paths(self):
        # Currently we assume `includes` and `excludes` never change

        if sys.path == self._last_sys_path and self._last_cwd.exists() and Path.cwd().samefile(self._last_cwd):
            return self._cached_search_paths

        res = [
            path
            for path in (Path(p).resolve() for p in sys.path)
            if not path.is_file() and not is_relative_to_any(path, self.excludes) and any(i.is_relative_to(path) or path.is_relative_to(i) for i in self.includes)
        ]

        self._cached_search_paths = res
        self._last_cwd = Path.cwd()
        self._last_sys_path = [*sys.path]
        return res

    def find_spec(self, fullname: str, paths: Sequence[str | Path] | None, _=None):
        if fullname in sys.modules:
            return None

        if paths is not None:
            paths = [path.resolve() for path in (Path(p) for p in paths) if path.is_dir()]

        for directory in self.search_paths:
            file = directory / f"{fullname.replace('.', '/')}.py"
            if self._accept(file) and (paths is None or is_relative_to_any(file, paths)):
                return ModuleSpec(fullname, _loader, origin=str(file))
            file = directory / f"{fullname.replace('.', '/')}/__init__.py"
            if self._accept(file) and (paths is None or is_relative_to_any(file, paths)):
                return ModuleSpec(fullname, _loader, origin=str(file), is_package=True)

includes instance-attribute

includes = _deduplicate(includes)

excludes instance-attribute

excludes = _deduplicate(
    (
        getenv("VIRTUAL_ENV"),
        *(getsitepackages()),
        getusersitepackages(),
        *builtins,
        *excludes,
    )
)

_last_sys_path instance-attribute

_last_sys_path: list[str] = []

_last_cwd instance-attribute

_last_cwd: Path = Path()

_cached_search_paths instance-attribute

_cached_search_paths: list[Path] = []

search_paths property

search_paths

__init__

__init__(
    includes: Iterable[str] = ".",
    excludes: Iterable[str] = (),
)
Source code in reactivity/hmr/core.py
173
174
175
176
177
178
179
180
181
182
183
def __init__(self, includes: Iterable[str] = ".", excludes: Iterable[str] = ()):
    super().__init__()
    builtins = map(get_paths().__getitem__, ("stdlib", "platstdlib", "platlib", "purelib"))
    self.includes = _deduplicate(includes)
    self.excludes = _deduplicate((getenv("VIRTUAL_ENV"), *getsitepackages(), getusersitepackages(), *builtins, *excludes))
    setup_fs_audithook()
    add_filter(lambda path: not is_relative_to_any(path, self.excludes) and is_relative_to_any(path, self.includes))

    self._last_sys_path: list[str] = []
    self._last_cwd: Path = Path()
    self._cached_search_paths: list[Path] = []

_accept

_accept(path: Path)
Source code in reactivity/hmr/core.py
185
186
def _accept(self, path: Path):
    return path.is_file() and not is_relative_to_any(path, self.excludes) and is_relative_to_any(path, self.includes)

find_spec

find_spec(
    fullname: str,
    paths: Sequence[str | Path] | None,
    _=None,
)
Source code in reactivity/hmr/core.py
206
207
208
209
210
211
212
213
214
215
216
217
218
219
def find_spec(self, fullname: str, paths: Sequence[str | Path] | None, _=None):
    if fullname in sys.modules:
        return None

    if paths is not None:
        paths = [path.resolve() for path in (Path(p) for p in paths) if path.is_dir()]

    for directory in self.search_paths:
        file = directory / f"{fullname.replace('.', '/')}.py"
        if self._accept(file) and (paths is None or is_relative_to_any(file, paths)):
            return ModuleSpec(fullname, _loader, origin=str(file))
        file = directory / f"{fullname.replace('.', '/')}/__init__.py"
        if self._accept(file) and (paths is None or is_relative_to_any(file, paths)):
            return ModuleSpec(fullname, _loader, origin=str(file), is_package=True)

ErrorFilter

Source code in reactivity/hmr/core.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
class ErrorFilter:
    def __init__(self, *exclude_filenames: str):
        self.exclude_filenames = set(exclude_filenames)

    def __call__(self, tb: TracebackType):
        current = last = tb
        first = None
        while current is not None:
            if current.tb_frame.f_code.co_filename not in self.exclude_filenames:
                if first is None:
                    first = current
                else:
                    last.tb_next = current
                last = current
            current = current.tb_next
        return first or tb

    def __enter__(self):
        return self

    def __exit__(self, exc_type: type[BaseException], exc_value: BaseException, traceback: TracebackType):
        if exc_value is None:
            return
        tb = self(traceback)
        exc_value = exc_value.with_traceback(tb)
        sys.excepthook(exc_type, exc_value, tb)
        return True

exclude_filenames instance-attribute

exclude_filenames = set(exclude_filenames)

__init__

__init__(*exclude_filenames: str)
Source code in reactivity/hmr/core.py
243
244
def __init__(self, *exclude_filenames: str):
    self.exclude_filenames = set(exclude_filenames)

__call__

__call__(tb: TracebackType)
Source code in reactivity/hmr/core.py
246
247
248
249
250
251
252
253
254
255
256
257
def __call__(self, tb: TracebackType):
    current = last = tb
    first = None
    while current is not None:
        if current.tb_frame.f_code.co_filename not in self.exclude_filenames:
            if first is None:
                first = current
            else:
                last.tb_next = current
            last = current
        current = current.tb_next
    return first or tb

__enter__

__enter__()
Source code in reactivity/hmr/core.py
259
260
def __enter__(self):
    return self

__exit__

__exit__(
    exc_type: type[BaseException],
    exc_value: BaseException,
    traceback: TracebackType,
)
Source code in reactivity/hmr/core.py
262
263
264
265
266
267
268
def __exit__(self, exc_type: type[BaseException], exc_value: BaseException, traceback: TracebackType):
    if exc_value is None:
        return
    tb = self(traceback)
    exc_value = exc_value.with_traceback(tb)
    sys.excepthook(exc_type, exc_value, tb)
    return True

BaseReloader

Source code in reactivity/hmr/core.py
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
class BaseReloader:
    def __init__(self, entry_file: str, includes: Iterable[str] = (".",), excludes: Iterable[str] = ()):
        self.entry = entry_file
        self.includes = includes
        self.excludes = excludes
        patch_meta_path(includes, excludes)
        self.error_filter = ErrorFilter(*map(str, Path(__file__, "../..").resolve().glob("**/*.py")), "<frozen importlib._bootstrap>")

    @cached_property
    def entry_module(self):
        spec = ModuleSpec("__main__", _loader, origin=self.entry)
        assert spec is not None
        namespace = {"__file__": self.entry, "__name__": "__main__", "__spec__": spec, "__loader__": _loader, "__package__": spec.parent, "__cached__": None, "__builtins__": builtins}
        return ReactiveModule(Path(self.entry), namespace, "__main__")

    def run_entry_file(self):
        with self.error_filter:
            self.entry_module.load()

    def on_events(self, events: Iterable[tuple[int, str]]):
        from watchfiles import Change

        if not events:
            return

        self.on_changes({Path(file).resolve() for type, file in events if type is not Change.deleted})

    def on_changes(self, files: set[Path]):
        path2module = get_path_module_map()

        call_pre_reload_hooks()

        with self.error_filter, HMR_CONTEXT.batch():
            for path in files:
                if module := path2module.get(path):
                    module.load.invalidate()
                else:
                    notify(path)

        call_post_reload_hooks()

    @cached_property
    def _stop_event(self):
        return _SimpleEvent()

    def stop_watching(self):
        self._stop_event.set()

entry instance-attribute

entry = entry_file

includes instance-attribute

includes = includes

excludes instance-attribute

excludes = excludes

error_filter instance-attribute

error_filter = ErrorFilter(
    *(map(str, glob("**/*.py"))),
    "<frozen importlib._bootstrap>",
)

entry_module cached property

entry_module

_stop_event cached property

_stop_event

__init__

__init__(
    entry_file: str,
    includes: Iterable[str] = (".",),
    excludes: Iterable[str] = (),
)
Source code in reactivity/hmr/core.py
272
273
274
275
276
277
def __init__(self, entry_file: str, includes: Iterable[str] = (".",), excludes: Iterable[str] = ()):
    self.entry = entry_file
    self.includes = includes
    self.excludes = excludes
    patch_meta_path(includes, excludes)
    self.error_filter = ErrorFilter(*map(str, Path(__file__, "../..").resolve().glob("**/*.py")), "<frozen importlib._bootstrap>")

run_entry_file

run_entry_file()
Source code in reactivity/hmr/core.py
286
287
288
def run_entry_file(self):
    with self.error_filter:
        self.entry_module.load()

on_events

on_events(events: Iterable[tuple[int, str]])
Source code in reactivity/hmr/core.py
290
291
292
293
294
295
296
def on_events(self, events: Iterable[tuple[int, str]]):
    from watchfiles import Change

    if not events:
        return

    self.on_changes({Path(file).resolve() for type, file in events if type is not Change.deleted})

on_changes

on_changes(files: set[Path])
Source code in reactivity/hmr/core.py
298
299
300
301
302
303
304
305
306
307
308
309
310
def on_changes(self, files: set[Path]):
    path2module = get_path_module_map()

    call_pre_reload_hooks()

    with self.error_filter, HMR_CONTEXT.batch():
        for path in files:
            if module := path2module.get(path):
                module.load.invalidate()
            else:
                notify(path)

    call_post_reload_hooks()

stop_watching

stop_watching()
Source code in reactivity/hmr/core.py
316
317
def stop_watching(self):
    self._stop_event.set()

_SimpleEvent

Source code in reactivity/hmr/core.py
320
321
322
323
324
325
326
327
328
class _SimpleEvent:
    def __init__(self):
        self._set = False

    def set(self):
        self._set = True

    def is_set(self):
        return self._set

_set instance-attribute

_set = False

__init__

__init__()
Source code in reactivity/hmr/core.py
321
322
def __init__(self):
    self._set = False

set

set()
Source code in reactivity/hmr/core.py
324
325
def set(self):
    self._set = True

is_set

is_set()
Source code in reactivity/hmr/core.py
327
328
def is_set(self):
    return self._set

SyncReloader

Bases: BaseReloader

Source code in reactivity/hmr/core.py
331
332
333
334
335
336
337
338
339
340
341
342
343
344
class SyncReloader(BaseReloader):
    def start_watching(self):
        from watchfiles import watch

        for events in watch(self.entry, *self.includes, stop_event=self._stop_event):
            self.on_events(events)

        del self._stop_event

    def keep_watching_until_interrupt(self):
        call_pre_reload_hooks()
        with suppress(KeyboardInterrupt), HMR_CONTEXT.effect(self.run_entry_file):
            call_post_reload_hooks()
            self.start_watching()

start_watching

start_watching()
Source code in reactivity/hmr/core.py
332
333
334
335
336
337
338
def start_watching(self):
    from watchfiles import watch

    for events in watch(self.entry, *self.includes, stop_event=self._stop_event):
        self.on_events(events)

    del self._stop_event

keep_watching_until_interrupt

keep_watching_until_interrupt()
Source code in reactivity/hmr/core.py
340
341
342
343
344
def keep_watching_until_interrupt(self):
    call_pre_reload_hooks()
    with suppress(KeyboardInterrupt), HMR_CONTEXT.effect(self.run_entry_file):
        call_post_reload_hooks()
        self.start_watching()

AsyncReloader

Bases: BaseReloader

Source code in reactivity/hmr/core.py
347
348
349
350
351
352
353
354
355
356
357
358
359
360
class AsyncReloader(BaseReloader):
    async def start_watching(self):
        from watchfiles import awatch

        async for events in awatch(self.entry, *self.includes, stop_event=self._stop_event):  # type: ignore
            self.on_events(events)

        del self._stop_event

    async def keep_watching_until_interrupt(self):
        call_pre_reload_hooks()
        with suppress(KeyboardInterrupt), HMR_CONTEXT.effect(self.run_entry_file):
            call_post_reload_hooks()
            await self.start_watching()

start_watching async

start_watching()
Source code in reactivity/hmr/core.py
348
349
350
351
352
353
354
async def start_watching(self):
    from watchfiles import awatch

    async for events in awatch(self.entry, *self.includes, stop_event=self._stop_event):  # type: ignore
        self.on_events(events)

    del self._stop_event

keep_watching_until_interrupt async

keep_watching_until_interrupt()
Source code in reactivity/hmr/core.py
356
357
358
359
360
async def keep_watching_until_interrupt(self):
    call_pre_reload_hooks()
    with suppress(KeyboardInterrupt), HMR_CONTEXT.effect(self.run_entry_file):
        call_post_reload_hooks()
        await self.start_watching()

is_called_internally

is_called_internally(*, extra_depth=0) -> bool

Protect private methods from being called from outside this package.

Source code in reactivity/hmr/core.py
27
28
29
30
def is_called_internally(*, extra_depth=0) -> bool:
    """Protect private methods from being called from outside this package."""
    frame = sys._getframe(extra_depth + 2)
    return frame.f_globals.get("__package__") == __package__

_deduplicate

_deduplicate(input_paths: Iterable[str | Path | None])
Source code in reactivity/hmr/core.py
164
165
166
167
168
169
def _deduplicate(input_paths: Iterable[str | Path | None]):
    paths = [*{Path(p).resolve(): None for p in input_paths if p is not None}]  # dicts preserve insertion order
    for i, p in enumerate(s := sorted(paths, reverse=True), start=1):
        if is_relative_to_any(p, s[i:]):
            paths.remove(p)
    return paths

is_relative_to_any

is_relative_to_any(path: Path, paths: Iterable[str | Path])
Source code in reactivity/hmr/core.py
222
223
def is_relative_to_any(path: Path, paths: Iterable[str | Path]):
    return any(path.is_relative_to(p) for p in paths)

patch_module

patch_module(name_or_module: str | ModuleType)
Source code in reactivity/hmr/core.py
226
227
228
229
230
231
def patch_module(name_or_module: str | ModuleType):
    name = name_or_module if isinstance(name_or_module, str) else name_or_module.__name__
    module = sys.modules[name_or_module] if isinstance(name_or_module, str) else name_or_module
    assert isinstance(module.__file__, str), f"{name} is not a file-backed module"
    m = sys.modules[name] = ReactiveModule(Path(module.__file__), module.__dict__, module.__name__, module.__doc__)
    return m

patch_meta_path

patch_meta_path(
    includes: Iterable[str] = (".",),
    excludes: Iterable[str] = (),
)
Source code in reactivity/hmr/core.py
234
235
def patch_meta_path(includes: Iterable[str] = (".",), excludes: Iterable[str] = ()):
    sys.meta_path.insert(0, ReactiveModuleFinder(includes, excludes))

get_path_module_map

get_path_module_map()
Source code in reactivity/hmr/core.py
238
239
def get_path_module_map():
    return {**ReactiveModule.instances}