Skip to content

FreeCAD/freecad.workbench_starterkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FreeCAD Workbench-Starterkit

Compatibility (important)

Don't use this repo if you care about py2-support and support of freecad < 0.18. If so please have a look at the traditional workbench structure.

Motivation and usage

This is a template for a FreeCAD workbench / module. As python-packaging and packaging for FreeCAD is not an easy task, this repository should give an overview of the things learned so far. If all you want is to create an extension for FreeCAD (module, additional gui-stuff, workbench), simple copy this repo and start replacing things.

To try the latest release of this template:

# Install this template
pip install freecad.workbench_starterkit

# Uninstall (to remove this template)
pip uninstall freecad.workbench_starterkit 

Note: There are currently two FreeCAD workbench styles. The origin workbench type is called "legacy-workbench". In addition the "namespace-workbench" is now an optional (and preffered) way to extend the FreeCAD. (See Glossary terms used in this discussion). For more discussion about the motivation behind the "namespace-workbench" see Motivation for namespace-workbenches.

Changing variables and strings

When using this workbench as template a few replacements need to be made in order to prepare the code for the new workbench. To agilize this task there is a Makefile ready with some substitutions commands using sed.

  • Change the content of the variables at the start of the Makefile with your data
  • Execute make on the command line, this replaces strings and rename file/directory
  • With the help of git status and git diff you can verify the changes, if you don't like them use git restore .

Structure of a namespace-workbench:

Initialization Files

  • init_gui.py: mandatory for modules adding new functionality to the GUI.
  • __init__.py: entry function for non-gui FreeCAD and python. Called when you import your package: from freecad import my_package

Both of these initialization files are called when the FreeCAD-gui is launched. Launching freecadcmd or importing FreeCAD (import freecad) will call the __init__.py file. (The python import will not yet work on every system, but we are working towards a standardization).

Structure

This is the minimal structure of a namespace-package to add a workbench to FreeCAD.

freecad/
└── workbench_starterkit/
    ├── __init__.py
    └── init_gui.py

Note: init_gui.py are called at startup of FreeCAD.
Do not put very time-intensive code in these files to reduce the start-up time.

Naming of FreeCAD modules

Several names are needed:

  • repository-name
    The name of the repository AKA freecad.repository_name
    eg.: freecad.workbench_starterkit

  • distribution-name
    This name is set in the setup.py
    eg.: name='freecad.workbench_starterkit'

  • package-name
    The name of the package which can be imported from python.
    Notes: it's possible that there are several packages in one repository with only one setup.py. You simply specify all packages and modules in the packages section of the setup.py.
    This name must not contain any python operator symbols like "-".
    If the repository contains only one pthon-package it makes sense to choose the same names for the repository-name, python-package and the pypi-package.
    eg.: freecad.workbench_starterkit

Rules

The "freecad" namespace is not allowed to be used directly.
This means it is not allowed to set any variables in the __init__.py of freecad. (But as with python3 this __init__.py should not exist anyway, this isn't a problem.) Further it's not allowed to add variables to the freecad-namespace directly. This can introduce name-clashes.

Examples:
freecad.myVariable = 10
👍 freecad.app.myVariable = 10

Testing your module/workbench

If you want to work on your extension you have the following options:

  • Start FreeCAD from the root-directory you are working in (eg. freecad.workbench_starterkit)
  • Simply link the extension to a location where python can find it.
  • pip install -e . adds the root-directory to easy_install.path.

Using pip (setuptool or distutlis)

Currently FreeCAD has several ways to install packages:

  1. Freecad Addon Manager
  2. freecad-pluginloader

With pip and pypi a third option is introduced. In addition, utilizing pip also provides powerful possibilities to install third party dependencies.

setup file

The setup.py file located in the main directory is a minimal example to get an extension installed. There we are using setuptools. If you need advanced options to install your package, please have a look at the setuptools docs.

versions

It's common practice to include a version-string in the python-package. The version should then be imported to the root-__init__.py to use it like this:

import freecad.workbench_starterkit
freecad.workbench_starterkit.__version__

In the setup.py we do not have access to the library itself, so the __version__ must be imported without the assumption that the package is installed. This can be done by running the file directly with exec.

TODO: Is there any better way to do this?

resources

In addition to the setup.py there is often the need for a MANIFEST.in With this file it's possible to install data like icons, documentation files, ... (everything not directly connected to python).
To tell setuptools to use the MANIFEST.in add this line to the setup function in the setup.py:

setup(..., include_package_data=True)

dependencies

you can specify required packages by setting the install_requires in the setup-function of the setup.py

setup(..., install_requires=['required_package'], ...)

install local

To install your extension locally with pip, do the following from a cmd (windows) or terminal (unix):

cd <path_to_your_package>
pip install .

uploading your package to pypi

Please have a look at this pypi twine tutorial.

Be careful with version-numbering. It seems pypi doesn't allow to upload a package with a version smaller then the biggest version of the package uploaded. This seems to be true also for deleted packages and deleted versions.

Once uploaded, the package can be installed with:

pip install <package-name>

Additional Information

Projects using this structure

Glossary

  • module : a Python source file, which can expose classes, functions and global variables
  • package : a directory containing Python modules.
  • distribution : the artifacts which are created by running the setup.py. Can contain multiple packages.
  • workbench : a graphical space inside the FreeCAD-Gui which adds functionality related to a specific task
  • namespace-package : a package which adds functionality to a specific namespace. For FreeCAD we are talking about packages which are importable with from freecad import my_package. (Sometimes also called new-style-module)
  • namespace-workbench: a namespace-package containing the freecad-initialization files.
  • extension-module: a library (.so or .dll) written in C/C++ which adds the possibility to import this library with python.

Glossary terms used in this discussion (that may lead to confusion)

  • freecad-module: It's anything available through FreeCAD's python interpreter and placed in FreeCADs directory structure.
    This can be a module, package, workbench, namespace-package, extension-module.
  • new_style_module: This refers to packages which are added to FreeCAD as namespace-packages
  • old_style_module: A package which is plugged into FreeCAD by adding it's base-directory to sys.path and uses Init.py and InitGui.py to get initialized by FreeCAD.

Motivation for Namespace Workbenches

There are several reasons why you might consider using the namespace-workbenche proposed in this template, and upgrade existing workbenches using the "old style".

  1. The ability to execute your module using a regular python interpreter and have it "just work" (See related forum discussion).

  2. Name-spaced packages (namespace-workbenches) avoid namespace collisions and the need to have a common prefix on all classes and files to ensure uniqueness (See related forum discussion).

  3. Integrating with PyPI / pip. The ability to pip install freecad.myworkbench (See related forum discussion).

  4. InitGui.py and Init.py (legacy-workbenches) do not behave like expected because these files are called with exec and are not properly imported. This leads to problems like:

    • __file__ not useable to get the path to the python file
    • predefined variables

Tip

Due to the fact we are now using the pktutil-module to find extensions of FreeCAD, it's possible to use standard-python-paths to place the extension. This is any location which is included in the sys.path.

To get a list of all the locations simple run this code in the FreeCAD-console:

import sys
sys.path

About

template for a FreeCAD workbench / module

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published