I’m not a big fan of M$ but Code – OSS is quite good and is the one I managed to set up with FreeCAD with a working debugger. I am very open to try another documented way if you have one to suggest !
Set up
To allow auto-completion and your linter like pylint to work partially you need to reference FreeCAD libraries. Examples below shows path for Arch/Manjaro with freecad-git installed. To get better auto-completion you can also add reference to freecad-stubs folder below I cloned it in my home git folder with git clone https://github.com/CyrilWaechter/freecad-stubs.gi
t.
- Open your working folder in Code – OSS eg. :
- macro folder :
~/.FreeCAD/Macro
- your in progress workbench folder
- macro folder :
- Create an .env file referencing FreeCAD lib folder and optionally your stubs folder :
FREECAD_LIB=/usr/lib/freecad/lib
FREECAD_STUBS=/home/<user>/git/freecad-stubs/out
PYTHONPATH=${FREECAD_MOD}:${FREECAD_LIB}:${PYTHONPATH}
(Note that on windows you need to replace:
by;
) - If you use git, add .vscode and .env to gitignore to avoid dirtyness
.env file concept is explained in Code – OSS help : Environment variable definitions file.
Unfortunately auto-completion and linter do not work for everything eg. Part. Shall we generate stubs like Gui Talarico did for Revit API or is there a better way ?
Update: I have generated stubs with mypy stubgen. Still unperfect but far better than before. You might want to keep an eye on Vanuan freecad-python-stubs.
Use
Once set up you have multiple options :
- Embedding FreeCAD
- Use your script as a macro or as a full workbench
Embedding FreeCAD
As explained on the wiki page FreeCAD can be embedded in another application sharing the host event loop. Let’s take a very basic example of application with PySide2 on their website :
import sys from PySide2.QtWidgets import QApplication, QLabel if __name__ == "__main__": app = QApplication(sys.argv) label = QLabel("Hello World") label.show() sys.exit(app.exec_())
Let’s replace the hello world label with the two lines from FreeCAD wiki and create a box :
import FreeCAD import FreeCADGui import Part import sys from PySide2.QtWidgets import QApplication if __name__ == "__main__": app = QApplication(sys.argv) FreeCADGui.showMainWindow() doc = FreeCAD.newDocument() box = Part.makeBox(100, 100, 100) Part.show(box) sys.exit(app.exec_())
That’s it, nothing more. The sad thing is that I don’t know yet how to interact with an already running application like you do with eg. Libre Office. Maybe with QProcess ? I saw multiple reference to this on Stackoverflow : Read output from python script in C++ Qt app, Communicating with QProcess Python program). I saw on FreeCAD forum that some people are doing it using a webserver : Re: Remote editor possible ?, Animate – Server. But for good reason or not it seems weird to me to use a webserver to communicate between 2 local applications.
Macro / workbench
Nothing much to say here. As you modify you macro or workbench you can then use it in FreeCAD as usual.
Debugging
Embedding FreeCAD
As you embed FreeCAD in your own application you can use your usual debugger.
Macro / workbench
To debug a script running from FreeCAD check Debugging wiki page. I described the process for Code – OSS at Visual Studio Code (VS Code) paragraph. You need ptvsd
installed :
pip install ptvsd
Add a piece of code to your script :
import ptvsd print("Waiting for debugger attach") # 5678 is the default attach port in the VS Code debug configurations ptvsd.enable_attach(address=('localhost', 5678), redirect_output=True) ptvsd.wait_for_attach()
And add a new debug configuration : Debug → Add Configurations…
"configurations": [ { "name": "Python: Attacher", "type": "python", "request": "attach", "port": 5678, "host": "localhost", "pathMappings": [ { "localRoot": "${workspaceFolder}", "remoteRoot": "." } ] },
Then start your script from FreeCAD which freeze waiting for the debugger to start.