Also, Python workbenches debugging is strictly related also to Python workbenches reloading. So I'm summarizing here my understanding about that as well.
Let's start with debugging. Python debugging is actually described in two WIki pages:
- https://www.freecadweb.org/wiki/Debugging , in the Python section, that also re-directs to a Forum post: https://forum.freecadweb.org/viewtopic.php?f=22&t=28901 . This is possibly the most up-to-date information, still I believe it is not complete.
- https://www.freecadweb.org/wiki/Python_ ... nvironment -> this I find quite obsolete, as it basically describes how you can debug Python code using 'print' statements or slightly more elaborated versions of the same concept. Interesting, but not exactly user-friendly
So here's my summary:
Method 1: Using pdb
This is my preferred, as it works out of the box (requires no installation of anything beyond the standard FreeCAD release), it is the same for Windows and Linux, and can debug pretty much everything Python.
Basic usage for pdb in FreeCAD is discussed in https://forum.freecadweb.org/viewtopic.php?f=10&t=28256
However, the suggestion is to insert the statement
Code: Select all
import pdb; pdb.set_trace()
Instead, as we have the Python console available, from the console you just:
- break into pdb with
Code: Select all
import pdb; pdb.set_trace()
- set a breakpoint as below, where <yourpythonmodule> is the module name as you would import it (i.e. import <yourpythonmodule>)
Code: Select all
b <yourpythonmodule>:<yourlinenumber>
- resume execution typing
Code: Select all
c
Another advantage of pdb is that it allows you post-mortem analysis. If you hit an exception, you can run from the Python console
Code: Select all
pdb.pm()
Cons of this approach:
- It is textual only (well, for me this is not necessarily a cons)
- FreeCAD mess up a bit the prompt (pdb) when debugging on a breakpoint, the prompt appears sometimes in the report window, so it might be a bit confusing
As the name implies, this is a GUI version of pdb (not a Windows-only version, mind you! win=GUI here). However, to make it work, you need some configuration, which is different for Windows and Linux, as of course you need to install winpdb, and the debug is done attaching winpdb to a remote target (is not embedded within FreeCAD; FreeCAD is the remote target to debug).
This is the method described by Werner in many posts (I believe this is his preferred?), see:
https://forum.freecadweb.org/viewtopic. ... 80&p=26446
https://forum.freecadweb.org/viewtopic.php?f=10&t=3884
and ultimately appearing in the Wiki in the post I already cited:
https://www.freecadweb.org/wiki/Debugging
Again all the discussion is mainly for debugging Macros, and the example in the Wiki page tells you to run a script. Actually this is not needed, again you can just insert a breakpoint in your code and work in FreeCAD until that part of the code is reached.
Linux version:
- install winpdb from a terminal with
Code: Select all
sudo apt-get install winpdb
- start winpdb. Go to menu File->Password" and set the password to e.g. "test"
- from the Python console in FreeCAD type:
Code: Select all
import rpdb2 rpdb2.start_embedded_debugger("test")
- in winpdb, pause the execution (FreeCAD becomes unresponsive)
- in winpdb, open your source file, and set the breakpoint
- in winpdb, resume execution
Windows version:
The problem under Windows is that Python for FreeCAD is installed bundled with FreeCAD, and separately from any other Python installation you may have.
So when you need to install Python extensions, you need to do that in a way that FreeCAD sees it.
However, you don't need winpdb to be installed into FreeCAD; this application opens a socket for remote debugging, so you can launch it in any other way. In my case, as I have Python installed under Win, I just installed it from the DOS shell using:
Code: Select all
pip install winpdb-reborn
Code: Select all
import pip
pip.main(['install'] + ['winpdb']
Now you are all set, and you can follow similar steps as in Linux case:
- start winpdb. Go to menu File->Password" and set the password to e.g. "test"
- from the Python console in FreeCAD type:
Code: Select all
import rpdb2 rpdb2.start_embedded_debugger("test")
- in winpdb, pause the execution (FreeCAD becomes unresponsive)
- in winpdb, open your source file, and set the breakpoint
- in winpdb, resume execution
The obvious advantage of winpdb is the availability of a GUI, so it is more user-friendly than pdb alone. However, I find it more tricky to start (as you need to work on two different windows, coordinating the actions) and the author of winpdb says
Cons of this approach:
- Needs a more complex set-up (at least under Windows)
- More complex to start than pdb (as you need to work on two different windows, coordinating the actions)
- winpdb is not fully stable under Python 3:
Method 3: using Visual Studio
This is described in detail in the thread https://forum.freecadweb.org/viewtopic.php?f=22&t=28901
However, I admit I was not able to make it works, possibly because (for some reasons not relevant here) I have only VS2015 installed.
But besides that:
Cons of this approach:
- Only Windows
- Tied to Visual Studio, that is fully proprietary (I know that FreeCAD under Win compiles under VS, but whenever I can, I prefer open tools)
This would be the preferred method, but actually the debugger is not documented (or at least I could not find the relevant Wiki page), and I could find no way to make it work for debugging a workbench.
So your option here is creating a stub i.e. a Macro that calls the functions of your workbench that you need to debug, so that you can load the macro in the editor, set breakpoints and run it.
Cons of this approach:
- Not really suited to debug workbenches, only macros
Ok, so now you debugged your code, found the issue and fixed it. How can you reload your workbench without closing/re-opening FreeCAD?
There are two main posts that deal with the topic:
https://forum.freecadweb.org/viewtopic.php?t=320
https://forum.freecadweb.org/viewtopic. ... 5&p=296289
First of all a note: as far as my understanding and my experience goes, you cannot really reload a full workbench, as there are some functions that loaded by C/C++ code. In particular:
- the Workbench description class is transfered to FreeCAD while start
- FreeCADGui.addCommand('MyModule', MyModule())
Code: Select all
import someModule
reload(someModule)
Code: Select all
import someModule
from importlib import reload
reload(someModule)
Code: Select all
from someTool import *
So while in general you can import * and even reload it, with
Code: Select all
import someTool
reload( someTool )
from someTool import *
(note: hint available at last row of the text appearing when typing import this, but probably you all already know that).
What you can do (this was suggested by Microelly I believe) is to tweak your someModule to contain, instead of the plain from someTool import *, the full code above.
Then you just need to import someModule and then reload someModule and the trick is done.
I'm not sure about the performance impact of leaving the full reload code in someModule in a production release of the workbench, but at least you can leave it there until you are done with your testing.
I realize I made an extra-long post, sorry about that and thanks for reading so far. I would welcome everybody's comments, as soon as this is cleared up I will translate the post into the Wiki pages, ideally marking https://www.freecadweb.org/wiki/Python_ ... nvironment as old, while improving https://www.freecadweb.org/wiki/Debugging .
Of course debugging Macros, and not workbenches, is a subset of workbench debugging, and considerably easier.
Ciao!
Enrico