Hot reload
Hot reload updates the open window every time you save a file of your project. The app is not restarted: the same objects keep their data and start running the new code.
uv run pyzed dev main.pypyzed dev main.pypython3 -m pyzed dev main.pypy -m pyzed dev main.pyFrom code, use pz.run(MyApp, reload=True) or set the PYZED_RELOAD=1 environment variable. Forms update on
save too (see Running and the console); this page is
about apps written in Python.
What a save changes
Section titled “What a save changes”| You change | What happens in the open window |
|---|---|
view(), a method, a helper module, a style |
The new code runs from the next redraw. |
A method that something else keeps (self.on_done = self.save, a timer, a thread, functools.partial) |
That reference runs the new code too. |
A new attribute in __init__ (self.tags = []) |
The live object gets it right away, nothing else changes. |
The initial value of an attribute (self.step = 1 → self.step = 5) |
It takes the new value if the app has not changed it while running; otherwise the app’s value stays. |
A new pz.state(...) or a new attribute in a component’s setup() |
Every instance of the component gets it. |
A class attribute (size = (400, 300), title) |
It comes from the new class. |
Code that fails to import, or a view() that raises |
The error shows in the window until you save a fix. |
Each reload prints a line per class that changed, so you can see what was picked up:
pyzed: reloaded Notes: methods changed: add, view; new state: tagspyzed: reloaded Notes: updated state: stepAn example
Section titled “An example”Start this app with pyzed dev notes.py, add a few notes, then make the edits below one at a time and save:
import pyzed as pzfrom pyzed import ui
class Notes(pz.App): title = "Notes" size = (420, 320)
def __init__(self): self.notes = [] self.draft = ""
def type_draft(self, text): self.draft = text
def add(self): if self.draft.strip(): self.notes.append(self.draft.strip()) self.draft = ""
def view(self): return pz.column([ pz.row([ui.input(self.draft, self.type_draft, on_submit=self.add, placeholder="New note"), ui.button("Add", self.add)], spacing=8), *[pz.text(note) for note in self.notes], ], spacing=8, padding=16)
if __name__ == "__main__": pz.run(Notes)- A new attribute. Add
self.starred = set()to__init__and a star button per note inview(). The notes you typed are still there andself.starredexists at once. - A new method. Add
def clear(self): self.notes.clear()and a button that calls it. It works on the next click. - A new initial value. Add
self.limit = 10to__init__, save, then change it to5: the app sees5. If the app had changedlimititself in the meantime, its value would be kept.
How state is brought up to date
Section titled “How state is brought up to date”When a class changed, Pyzed runs its __init__ again on a scratch copy, with the arguments the object was
created with (for a component, setup() with its current props), and compares it with the live object:
- attributes the live object does not have are copied over;
- plain values (numbers, text, booleans, and small lists, tuples, sets and dicts of them) whose initial value changed in the code are updated, but only if the live value is still the old initial one;
- everything else is left alone. The scratch copy is then thrown away, and what its
__init__printed is hidden.
Classes whose code did not change are not touched, so saving an unrelated file never runs your __init__.
Objects of your own classes that Pyzed did not create (a Todo in a list, for example) get the new attributes
that only need self, globals or builtins: self.done = False works, self.label = text.upper() needs the
text argument and is skipped.
When __init__ has side effects
Section titled “When __init__ has side effects”If __init__ opens a file, a device, a socket or starts a thread, running it again on a scratch copy is
usually harmless, but you can turn it off for that class:
class Player(pz.App): reload_init = False # hot reload keeps the state as it is: no scratch copy
def __init__(self): self.stream = open_audio_device()Better yet, move that work to on_start(), which runs once when the window opens. If the scratch __init__
fails, the reload still applies and the console says why the state was not updated.
Migrating state by hand
Section titled “Migrating state by hand”For changes Pyzed cannot guess (renaming an attribute, changing its type), define on_reload() on the app or a
window. It runs after every reload and may return a Command:
class Notes(pz.App): def on_reload(self): if isinstance(self.notes, list) and self.notes and isinstance(self.notes[0], str): self.notes = [{"text": n, "done": False} for n in self.notes]Inspecting a reload
Section titled “Inspecting a reload”pz.hot_reload.current() returns the running Reloader. Its changes list has one Change per class that
changed in the last reload (changed, added and removed methods, new_state and updated_state), count
says how many reloads succeeded and error holds the traceback of a failed one. Set verbose = False to stop
the console lines.
Limits
Section titled “Limits”- A running
asynctask or generator keeps the code it started with until it ends. - Removing an attribute from
__init__does not delete it from the live object. - Code that already ran (the
if __name__ == "__main__":block,on_start()) does not run again. - A class with
__slots__that change cannot switch to the new version; restart the app in that case.