Skip to content

Commit

Permalink
Lay the ground work for hot reloading without throwing
Browse files Browse the repository at this point in the history
  • Loading branch information
DubiousCactus committed Dec 30, 2024
1 parent 39275cc commit cd226c7
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 6 deletions.
12 changes: 11 additions & 1 deletion bootstrap/hot_reloading/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,21 @@ async def catch_and_hang(self, module: MatchboxModule, *args, **kwargs):
await self.ui.hang(threw=True)

async def reload_module(self, module: MatchboxModule):
if module.throw_frame is None:
if module.to_reload and module.throw_frame is None:
self.ui.exit(1)
raise RuntimeError(
f"Module {module} is set to reload but we don't have the frame that threw!"
)
elif not module.to_reload:
# TODO: This works as long as we init the builder UI with skip_frozen=True
# so that we can get the root frame at least once, but it will fail if the
# module never throws in the first place. We should fix it by decoupling
# root frame finding from the catch_and_hang() method above. Or ideally by
# finding the code object more efficiently!
self.ui.print_info(f"Reloading MatchboxModule({module.underlying_fn})...")
self.ui.print_err("Hot reloading without throwing is not implemented yet.")
code_obj = None
await self.ui.hang(threw=False)
self.ui.log_tracer(
Text(
f"Reloading code from {module.throw_frame.f_code.co_filename}",
Expand Down
20 changes: 15 additions & 5 deletions bootstrap/tui/builder_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
Tuple,
Expand Down Expand Up @@ -39,14 +40,16 @@ class BuilderUI(App):
BINDINGS = [
("q", "quit", "Quit"),
("d", "toggle_dark", "Toggle dark mode"),
("r", "reload", "Hot reload"),
("r", "forward_reload", "Hot reload (thrown only)"),
("R", "reload", "Hot reload (all)"),
]

def __init__(self, chain: List[MatchboxModule]):
super().__init__()
self._module_chain: List[MatchboxModule] = chain
self._runner_task = None
self._engine = HotReloadingEngine(self)
self._skip_frozen = True # NOTE: Leave this to true for the first run or it will attempt to reload on the first run, which is not really desireable

async def on_mount(self):
await self._chain_up()
Expand All @@ -71,10 +74,10 @@ async def _run_chain(self) -> None:
for module in self._module_chain:
await self.query_one(LocalsPanel).clear()
self.query_one(Tracer).clear()
if module.is_frozen:
if module.is_frozen and self._skip_frozen:
self.log_tracer(Text(f"Skipping frozen module {module}", style="green"))
continue
if module.to_reload:
if module.to_reload or not self._skip_frozen:
self.log_tracer(Text(f"Reloading module: {module}", style="yellow"))
await self._engine.reload_module(module)
self.log_tracer(Text(f"Running module: {module}", style="yellow"))
Expand Down Expand Up @@ -108,7 +111,6 @@ def compose(self) -> ComposeResult:
yield ftree
lcls = LocalsPanel(classes="box")
lcls.styles.border = ("solid", "gray")
lcls.border_title = "Frame locals"
yield lcls
yield Tracer(classes="box")
traceback = RichLog(
Expand All @@ -119,7 +121,7 @@ def compose(self) -> ComposeResult:
yield traceback
yield Footer()

def action_reload(self) -> None:
def _reload(self) -> None:
self.query_one(Tracer).clear()
self.log_tracer("Reloading hot code...")
self.query_one(CheckboxPanel).ready()
Expand All @@ -128,6 +130,14 @@ def action_reload(self) -> None:
self.query_one(CodeEditor).ready()
self.run_chain()

def action_reload(self) -> None:
self._skip_frozen = False
self._reload()

def action_forward_reload(self) -> None:
self._skip_frozen = True
self._reload()

def on_checkbox_changed(self, message: Checkbox.Changed):
assert message.checkbox.id is not None
for module in self._module_chain:
Expand Down

0 comments on commit cd226c7

Please sign in to comment.