Skip to content

Commit

Permalink
make ModuleReloader a singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
smacke committed Nov 5, 2023
1 parent 8e73e98 commit df540be
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 17 deletions.
4 changes: 2 additions & 2 deletions core/superduperreload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
__version__ = _version.get_versions()['version']


def make_autoreload_magics(shell: "InteractiveShell", enable_file_watching: bool = True) -> AutoreloadMagics:
def make_autoreload_magics(shell: "InteractiveShell") -> AutoreloadMagics:
try:
from ipyflow import flow

flow_ = flow()
except:
flow_ = None

return AutoreloadMagics(shell, flow=flow_, enable_file_watching=enable_file_watching)
return AutoreloadMagics(shell, flow=flow_)


def load_ipython_extension(ip: "InteractiveShell", magics: Optional[AutoreloadMagics] = None) -> None:
Expand Down
5 changes: 1 addition & 4 deletions core/superduperreload/magics.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,8 @@ def __init__(self, *a, **kw):
if platform.python_implementation().lower() != "cpython":
raise RuntimeError("CPython required for superduperreload extension")
flow = kw.pop("flow", None)
enable_file_watching = kw.pop("enable_file_watching", True)
super().__init__(*a, **kw)
self._reloader = ModuleReloader(
self.shell, flow=flow, enable_file_watching=enable_file_watching
)
self._reloader = ModuleReloader.instance(self.shell, flow=flow)
self.loaded_modules = set(sys.modules)

@line_magic
Expand Down
7 changes: 5 additions & 2 deletions core/superduperreload/patching.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from types import FunctionType, MethodType
from typing import Callable, Dict, List, Optional, Set, Sized, Tuple, Type, Union

from traitlets.config import SingletonConfigurable

from superduperreload.utils import isinstance2

if sys.maxsize > 2**32:
Expand Down Expand Up @@ -82,10 +84,11 @@ class UnpatchableList(list):
pass


class ObjectPatcher:
class ObjectPatcher(SingletonConfigurable):
_FIELD_OFFSET_LOOKUP_TABLE_BY_STRUCT_TYPE: Dict[str, Dict[str, int]] = {}

def __init__(self, patch_referrers: bool) -> None:
def __init__(self, patch_referrers: bool, **kwargs) -> None:
super().__init__(**kwargs)
self._patched_obj_ids: Set[int] = set()
self._remapped_classes: Dict[Type[object], Type[object]] = UnpatchableDict()
self._patch_rules: List[Tuple[Callable, Callable]] = [
Expand Down
25 changes: 19 additions & 6 deletions core/superduperreload/superduperreload.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@


class ImportTracer(pyc.BaseTracer):
def __init__(self, *args, **kwargs):
def __init__(self, *args, **kwargs) -> None:
self._reloader: "ModuleReloader" = kwargs.pop("reloader")
super().__init__(*args, **kwargs)

@pyc.register_raw_handler(pyc.after_import)
def after_import(self, *_, module: ModuleType, **__):
def after_import(self, *_, module: ModuleType, **__) -> None:
self._reloader.handle_module_refreshed(module)


Expand All @@ -94,7 +94,6 @@ def __init__(
self,
shell: Optional[Union["InteractiveShell", "FakeShell"]] = None,
flow: Optional["NotebookFlow"] = None,
enable_file_watching: bool = True,
) -> None:
super().__init__(patch_referrers=SHOULD_PATCH_REFERRERS)
# Whether this reloader is enabled
Expand Down Expand Up @@ -140,8 +139,22 @@ def __init__(

# Cache module modification times
self.check(do_reload=False)
if self.flow is not None and enable_file_watching:
Thread(target=self._watch, daemon=True).start()
self._watcher: Optional[Thread] = None
self._watcher_running = False
if self.flow is not None:
self._watcher = Thread(target=self._watch, daemon=True)
self._watcher_running = True
self._watcher.start()

@classmethod
def clear_instance(cls) -> None:
if cls.initialized():
reloader: "ModuleReloader" = cls._instance
if reloader._watcher_running:
reloader._watcher_running = False
if reloader._watcher is not None:
reloader._watcher.join()
super().clear_instance()

def _report(self, msg: str) -> None:
if self.verbose:
Expand Down Expand Up @@ -303,7 +316,7 @@ def _watch(self, interval: float = 1) -> None:
assert self.flow is not None
for m in list(sys.modules.values()):
self.handle_module_refreshed(m)
while True:
while self._watcher_running:
try:
with self._reloading_lock:
self._poll_module_changes_once()
Expand Down
6 changes: 3 additions & 3 deletions core/test/test_ipyflow_superduperreload.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from ipyflow.tracing.ipyflow_tracer import DataflowTracer

from superduperreload import load_ipython_extension, make_autoreload_magics
from superduperreload.superduperreload import ModuleReloader

try:
import numpy
Expand Down Expand Up @@ -105,13 +106,12 @@ def setUp(self):
self.test_dir = tempfile.mkdtemp()
self.old_sys_path = list(sys.path)
sys.path.insert(0, self.test_dir)
ModuleReloader.clear_instance()
DataflowTracer.clear_instance()
NotebookFlow.clear_instance()
IPyflowInteractiveShell.clear_instance()
self.shell = IPyflowInteractiveShell.instance()
self.auto_magics = make_autoreload_magics(
self.shell, enable_file_watching=False
)
self.auto_magics = make_autoreload_magics(self.shell)
load_ipython_extension(self.shell, magics=self.auto_magics)

def tearDown(self):
Expand Down

0 comments on commit df540be

Please sign in to comment.