A Python utility to reload a function or loop body from source on each iteration without losing state.
This fork of reloading is not available on PyPi. Install it from Github:
$ pip install https://github.com/nneskildsf/reloading/archive/refs/heads/master.zip
This fork of reloading supports Python 3.6+.
- Reload functions,
for
loops andwhile
loops - Works in Jupyter Notebook
break
andcontinue
in loops- Multiple reloading functions and loops in one file
- Reloaded functions preserve their original call signature
- Only reload source code when changed for faster performance
- Comprehensive exceptions and logging
- Exports locals of reloaded loops to parent locals (Python 3.13 and newer)
To reload the body of a for
loop from source before each iteration, wrap the iterator with reloading
:
from reloading import reloading
for i in reloading(range(10)):
# This code will be reloaded before each iteration
print(i)
To reload the body and condition of a while
loop from source before each iteration, wrap the condition with reloading
:
from reloading import reloading
i = 0
while reloading(i<10):
# This code and the condition (i<10) will be reloaded before each iteration
print(i)
i += 1
To reload a function from source before each execution, decorate the function
definition with @reloading
:
from reloading import reloading
@reloading
def function():
# This code will be reloaded before each function call
pass
It is also possible to mark a function for reload after defining it:
from reloading import reloading
def function():
# This function will be reloaded before each function call
pass
function = reloading(function)
Exceptions are handled interactively by default to avoid losing state.
When an exception occurs you will be notified and have the opportunity
to rectify the issue and continue. However, if reloading is
used in a setting where exceptions are better handled in the application
using reloading then it can be disabled by setting interactive_exception
to False
. Example:
from reloading import reloading
@reloading(interactive_exception=False)
def reloading_function():
pass
for i in reloading(range(10), interactive_exception=False):
pass
j = 0
while reloading(j<10, interactive_exception=False):
j += 1
To iterate forever in a for
loop you can omit the argument:
from reloading import reloading
for _ in reloading():
# This code will loop forever and reload from source before each iteration
pass
On Python 3.9 and newer, a diff is logged when the source code is updated. Consider the following code as an example.
from reloading import reloading
from time import sleep
import logging
log = logging.getLogger("reloading")
log.setLevel(logging.DEBUG)
for i in reloading(range(100)):
print(i)
sleep(1.0)
After some time the code is edited. i = 2*i
is added before print(i)
,
resulting in the following log output:
INFO:reloading:For loop at line 10 of file "../example.py" has been reloaded.
DEBUG:reloading:Code changes:
+i = i * 2
print(i)
sleep(1.0)
On Python version less than 3.13 it is not possible to properly export the local variables from a loop to parent locals. The following example demonstrates this:
from reloading import reloading
def function():
i = 0
while reloading(i < 10):
i += 1
print(i)
function() # Prints 0. Not 10 as expected. Fixed in Python 3.13.
A warning is emitted when the issue arises:
WARNING:reloading:Variable(s) "i" in reloaded loop were not exported to the scope which called the reloaded loop at line...
Run:
$ pip install -e ".[development]"
$ ruff check .
$ flake8
$ pyright
$ mypy .
$ python -m unittest