Do you like the prototyping pace of Jupyter notebooks? Do you wish you could have the same experience in your full code base, not just for a notebook? Are you infuriated by having to re-run your boot-up heavy program with slow data loading just so you can hit a breakpoint and debug?
Fever is here for you! Without changing a single line of code in your code base, fever lets you:
- Interactively re-run code traces from one arbitrary function to another, while keeping the state of your program warm in memory.
- Hot reload code changes anywhere in your code base, so you can iterate aggressively on the hot parts of your code and see the output instantly, without going through the slow, cold parts of your code.
- Drop in a debugger automatically when your code trace finishes, or on exceptions thrown, letting you investigate bugs and fix them by reviving your program instantly.
uv pip install --index-url https://test.pypi.org/simple/ fever
- Hot reload when a file changes on disk:
uv run fever watch <my_python_code.py> <my_arg1> <--my-arg-2=val> <...> - Interactive code replay TUI:
uv run fever replay <my_python_code.py> <my_arg1> <--my-arg-2=val> <...>
Fever is currently under heavy development and is still at the prototyping stage. We are working hard on bringing the robustness to the best standards.
Fever is at its core a hot code reloading engine, but on steroids. Hot reloading is proactive: fever analyzes your modules upon import and wraps functions to re-route calls to the latest compiled version. Here's the gist:
We first implement an import hook so that we can record module imports (and optionally a dependency graph). Then we build an AST of the code so that we can analyze all callables and keep track of: module-level functions, class methods, lambdas (well that's probably not gonna happen), etc.
Once we found all the callables in a module, we can wrap them in a proxy upon import, before returning the code to the user. With this mechanism in place, we are able to track which callable was changed on disk -- ie hash all callables in the dependency graph of the module and detect hash changes. Up to this point, everything that happened is fully invisible to the user.
Whenever the user calls for a reload (or when the file watcher does), each changed callable is reloaded, and only that, and re-executed in the registry's isolated namespace. Thanks to the proxy wrapper, every place where a function was previously imported and called will automatically call the new code. Pretty sweet, right?
- More advanced hot reloading mechanism: a. Instead of compiling the entire module to replace just one function in the registry, we compile that one function individually, saving unnecessary compute which can make a difference for larger modules. b. Handles new function, class, method definitions (even without recompiling the entire module).
- Smart caching of function calls for instant hot reloading:
- Only reload the code that was changed on disk.
- Only re-execute the code that was reloaded (reuse from cache for other functions).
- (TODO) Handle loops in a smart way! Aggregate results when possible.
- Live code replay à la Jupyter:
- Record program trace and allow selecting start and end nodes for replay.
- Allow to hang on exception or at the end of the trace subgraph.
- (TODO) Process-independent function execution for deterministic and mutation-free trace replay.
- (TODO) Handle multiprocessing for PyTorch dataloaders.
- (TODO) Handling GPU computation? (no idea what/how/why yet).
- (TODO) Keep a history of changes so that we can revert code changes (e.g. in case the new code causes a crash).
- v0.0.1: Basic proof of concept for hot code reloading only callables that changed on disk
- v0.0.2: Demonstrate the PoC on one of my complex projects (matchbox)
- v0.0.3: Implement a reliable and unit-tested import hook mechanism
- v0.0.4: Implement a reliable and unit-tested hot reloading mechanism
- v0.0.5: Add interface to file watcher to trigger reload events
- v0.0.6: Implement a reliable (and unit-tested) smart caching mechanism
- v0.0.7: Add a tool executable to wrap a script and launch the trace replay TUI
- v0.0.8: PDB++ TUI integration + flexible API
- v0.0.9: Live trace graph update for the TUI
- v0.1.0: Rewrite the architecture into a "process isolation" replay engine with IPC.
- v0.1.1: Handle all edge cases (decorated functions, methods, etc.) in hot reloading engine
