Monthly Archives: December 2019

FreeCAD external editor with Code – OSS

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.git.

  1. Open your working folder in Code – OSS eg. :
    • macro folder : ~/.FreeCAD/Macro
    • your in progress workbench folder
  2. 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 ;)
  3. 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 :

  1. Embedding FreeCAD
  2. 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.

Video demo