Ha, I'm just working on integrating the `pydev.debugger` code reloading into `debugpy` (so that the code reloading from the PyDev debugger will be available for Python-VSCode debugger users too).
The in-memory reloading (which may be seen at: https://github.com/fabioz/PyDev.Debugger/blob/main/_pydevd_b...) unfortunately doesn't work all the time (fixing the references at runtime in Python is difficult), but it works well enough for the cases where you have a simple function and change it (that file does explain some of the issues that the reloading faces).
One major issue is that after doing the reload, you need to get out of the function and then back into it to see the difference -- so, if you're stopped in the function in a breakpoint, it's not possible to simply drop the function and restart it as Python itself doesn't support that... maybe that's a good idea for a PEP ;)
Anyways, when it works, it's pretty nice in that you don't have to restart your whole debug session to see changes (the other approach, which webservers use in general is just restart the whole process, so, for instance, Django has an initial process just monitoring for changes and a 2nd process which is actually serving requests which is restarted when something changes -- not as good if you have a heavy startup or are working with something where you have to click through multiple things to get to the state which you want).
I always thought that this has a potential to greatly improve the development productivity.
I remember I saw live coding videos from Notch (Minecraft) on some gamejam where he intensively used hot code reloading for Java. About 90% of his development time, he had the game running, and tuned the logic of some game elements live, and immediately saw the result.
I know that Erlang also has such a feature, such that you don't need to shut down your production system, and that you can update it live while it keeps running.
That's a bit awkward, I'm currently working on a package[1] that does more or less the same thing in more or less the same way (I think), except you don't need to decorate anything. Just run
`python -m jurigged script.py` or `jurigged script.py` instead of `python script.py` and it will watch everything in the current working directory.
There's still some bugs I have to iron out, though, it should be better in a month or so. Still, you can pip install it if you want.
Seems fairly different. My tool does not restart the process, it hot patches functions and methods whenever they are modified in the source, like the OP.
Accellerates the dev process by removing a whole bunch of steps: terminating the running program, relaunching the running program, repeating any steps to get back to the code in question.
While these things only take maybe a few seconds each, thats a few seconds that you’ll perform maybe hundreds of times. Reducing context switches is always a good thing.
albertzeyer's example with Notch explains the issue pretty well:
When working on a video game, restarting the game every time you are tweaking the behaviour of an entity takes a lot of time. Hot code reloading while keeping the state of the game makes development much easier.
On the other hand, when the entire state is stored outside of the Python app (eg: a web app using a database), restarting the entire process and reloading the page is fast enough and more reliable.
Visual Studio seems to have "edit and continue" which I only knew from VB, but seems to be available in C# and C++ too. Not the same, but it shortens the development cycle in a similar fashion.
The feature in Python reminds me on hot code loading in Erlang which I found quite interesting when i first read (never used) about the feature.
I wondered which other languages provides (or didn't) an equivalent solution.
Back then it felt a bit scary, with not much more than RCS as VCS around :)
But I think Erlang implemented it for increased up-time, not for increased development cycle?
Edit and continue in C# is like magic. Paired with ability to move the execution-pointer or unwind the stack and rerun the function you can write a whole algorithm without ever stopping the debugger. Oops - something went wrong, just change the code, reassign the variable in the watch-window and drag up the execution pointer to previous line. Really powerful!
If only more environments had similar tools. Once you've worked with this other tools feel rather primitive.
Then in the ipython shell you can type r(module) to reload the entire thing.
So I'll often have the editor in one terminal window, and ipython in the other one, save the code and switch back the repl, and type r(t)
import mymodule as t
Now tie in some ipdb [1] and you have a pretty sweet setup. Also depending on your serving framework it might also have hot reloading as well, tornado, flask, etc.
I jest, but really I feel like we've made things so complicated it just gets in our way. Our Javascript pipeline is huge, complicated, and requires you to sit down and wrap your head around it every time you want to modify it.
If I get to greenfield another project, it's going to be so bloody simple.
I feel you, I have currently the chance to start a greendfield project,
* backend in php8 with symfony framework
* postgres
* frontend is only html+tailwind css and 2 lines of javascript here and there for a smooth transition effect (https://christopheraue.net/design/fading-pages-on-load-and-unload)
and I just got my PWA accepted by google store , and my 18 lines react-native app embedding the website in a page view for apple store is in review.
no javascript madness, and the app is so snappy that everybody ask me which kind of react optimization i'm using : "the one where you remove it completly"
PHP has to bootstrap everything on every single request. It is definitely great for reloadability and local development but terrible for production performance. Most teams that do not need PHP or love it (Laravel is great I know) have moved to using languages and frameworks that provide a long running application server.
The "run once and die" model of php applications however, it extremely clarifying and simplifying.
It is a bit like the unix philosophy of "simple apps, in sequence" -- in the sense that it clarifies what development should be.
PHP apps, at their best, were multiple "run once and die" endpoints -- the drive to "Front Controller" and "run long" apps throws away much of the value of this paradigm.
Part of the community problem, id say, is that this paradigm was never well-articulated; and always associated with "a mess".
People like rasmus tried: yes have your long-running apps (eg., in Java), but your front-end should be die-quickly.
I'm really sorry to say this but you're spreading FUD
1. slack backend is written in php and other big companies.
2. php is actually faster than python/ruby
3. opcache in production (which is both simple to activate AND a well-known best practices among people doing php professionally) eliminate the performance hit you will get.
4. your backend language performance is often far from being the bottleneck in most endpoint where performance do matters , it's often either a database optimization problem, an algorithm problem or a really CPU intensive tasks that you will offload to a dedicated library written in C.
I perfectly understand PHP does have a lot of flaws, but production performance is not one.
PHP isn't that bad for production performance, if you have the right mindset.
Another way of saying PHP has to bootstrap everything on each request (which is a bit of an overreach; it doesn't reload C libraries, and you can do opcode caching and data caching, etc), is that PHP throws away everything you've done after each request.
That means everything that you build that isn't output somewhere is garbage.
If you spend a lot of time making a sculpture out of garbage, only to throw it away, you'll have poor performance. If you use the minimum of scaffolding to send out the bytes you want to send, you can get pages (or api responses, whatever) with a few ms of overhead in addition to your underlying data fetches. You could certainly go faster with something else, but PHP can be decently fast.
On the other hand, your code won't look at all like what people think of as 'modern' PHP.
I agree things grow to be complicated, and that's somewhat unavoidable (accepting usual constraints), but they don't have to start out complex. I think that's the same point GP is making.
I'm writing applications for people to manage fleets of thousands of robots in real-time from the other side of the planet. There's no room for "bloody simple" =D
They don't resemble traditional websites/CRUD apps a whole lot. Much closer to Sim City + Factorio.
When it comes to making your standard issue website/webapp, I think some of them could stand to be simpler.
My project, hupper [1], isn't hot reloading but it's worth mentioning in this thread alongside other code reloaders. It is a general purpose tool to monitor python code and reload the process when code changes. You can use it with any script that you're working on via `hupper -m foo` and your `foo.py` is then reloaded/re-executed everytime you change it. It's used under the hood in other tools to implement things like `pserve --reload` in Pyramid and is used in Warehouse (the codebase for PyPI) to ease development workflows.
It's an improvement on some previous attempts at the solution that would crash when reloading invalid code. Hupper does not have this problem due to its multi process design.
Few years back, I did something similar to this with PHP.
I was always marveled at the capacities of xDebug, and never stopped using it since I found it (Some 10+ years), and honestly, coupling it with PHPStorm is another level.
But still, hitting reload on the browser, or running a script from the CLI gets tiring after the 20th time; so I made this little class where you would call a method, and the method will reload the script where the code was located continuously until I managed to get it to do what I wanted.
Wrote a similar thing [1]. It can also load loop bodies from source before each iteration. Can be helpful for long running loops like when downloading or training deep learning models.
It's great to see I am not the only one interested in this way of coding. I will have a look at all the alternatives your posted about, let's get hot code reloading in Python awesome!
Join the conversation on FOSDEM's Matrix channel tomorrow to discuss the subject further:
#python-python_reloading:fosdem.org
I'm slightly confused by this wording in the docs: "This allows it to reload code that is followed by blocking instructions such as the infinite loops you can find in the examples."
The examples just have loops where the reloaded function is called in a loop. Is this just updating the definition of the function between calls?
Not a user of Reloadr, but hot code reloading is a big thing on my Java development process. There are servers and use cases that take a long time to start or setup, and having the possibility to debug -> edit code -> re-execute a specific method using the same context goes a long way.
For production usage, maybe that wouldn't be considered safe, but there are companies that provide services with this purpose (e.g. JRebel).
JRebel literally saved our ** years ago. Compile, restart cycles would have killed us, with JRebel we were able to stay in the zone and iterate way way faster. The difference between rage quitting and going home at 430.
I imagine it can be very useful if you want to debug and fix a problem in a contained area of the code where it can take a significant effort to get the program in a state which can trigger the bug, but once in that state it's easy to trigger repeatedly.
Say you have to load a lot of data, but once loaded you can trigger the issue by just hitting a button.
With hot code reloading you could incrementally add debugging code and try your fix, without having to restart the program and wait for the data to reload each time.
Well, the main benefit is going to be for complex things where you don't want to restart a large program in order to test a small change, but in terms of simple things, programs with event loops (like games or interactive tools) are a good candidate.
I wrote a (worse) version of this at my first job, because loading and initial manipulation of the data I was doing analysis on took tens of minutes, and I kept wanting to make changes to what I was doing. Saved me a couple hours.
In Julia, this can be done with even less efforts on the user-side by loading Revise (https://github.com/timholy/Revise.jl) before any other package you load.
does this patch existing class instances, if you modify a method for example?
I cobbled together something similar a few years back using the reload stuff from ipython and a script I think GuidoVR wrote that I stumbled on. I like to debug on the cli (pdb++), I made it autodetect changed modules and reload those whenever i entered the 'reload' command. For me having to decorate things first would be a no-no.
My helper worked really nicely for some projects but broke with others. Well done on getting something out there.
The idea is to use virtual functions, and recompile new classes into a shared library. The shared lib is linked into the running program, and old instances of the classes are deleted and replaced by new instances constructed from the shared library.
I am working on a library called hscpp using the same (stolen) idea here:
hscpp is still very alpha, and I’m sure I’ll find lots of bugs as I work on a “real” demo. In contrast, Runtime Compiled C++ is quite mature and is used in real game projects.
Note that this approach very much limits your architecture. For example, you won’t be able to use statics, as the newly compiled shared libraries won’t see them.
It’s a finicky thing, worth it to me, but not something you can just plop in to an established project.
For what it's worth, I'm working on my own reloader which does not require decorating anything: https://github.com/breuleux/jurigged (still a WIP, but it works well enough).
I thing that xreload from Guido and the code inside ipython both provide the best hot-patching. But both projects miss the feature to watch for changed files.
The in-memory reloading (which may be seen at: https://github.com/fabioz/PyDev.Debugger/blob/main/_pydevd_b...) unfortunately doesn't work all the time (fixing the references at runtime in Python is difficult), but it works well enough for the cases where you have a simple function and change it (that file does explain some of the issues that the reloading faces).
One major issue is that after doing the reload, you need to get out of the function and then back into it to see the difference -- so, if you're stopped in the function in a breakpoint, it's not possible to simply drop the function and restart it as Python itself doesn't support that... maybe that's a good idea for a PEP ;)
Anyways, when it works, it's pretty nice in that you don't have to restart your whole debug session to see changes (the other approach, which webservers use in general is just restart the whole process, so, for instance, Django has an initial process just monitoring for changes and a 2nd process which is actually serving requests which is restarted when something changes -- not as good if you have a heavy startup or are working with something where you have to click through multiple things to get to the state which you want).