Repository navigation
Developer Guide
This page is for people who change the source code of FlatCAM Evo. It describes the structure of the code, how to run it from source, how the tests work, and how to write a plugin, a Tcl command, or a preprocessor.
- The entry point is
flatcam.py. It starts theAppclass inappMain.py. The architecture is described in the sections below. - Most changes touch one of these folders:
appPlugins/(tools),appEditors/(editors),appObjects/(project objects),appParsers/(file formats),appGUI/(widgets and preferences),tclCommands/(scripting),preprocessors/(G-code output).
flatcam.py (entry) -> App (appMain.py) -> MainGUI + Objects + Editors + Plugins + Parsers
-
App(appMain.py) is the central class. It holds the GUI, the object collection, the editors, the tools, the parsers, the handlers, and the preferences. Each component gets anappreference. -
camlib.pyholds the geometry and CNC library: the base classesGerber,Excellon,Geometry, andCNCjob, and the geometry helpers.
FlatCAMObj (appObjects/AppObjectTemplate.py) - base of all project objects
GerberObject, ExcellonObject, GeometryObject, CNCJobObject, ScriptObject, DocumentObject
- Objects are created by the
new_object()factory. They are registered inObjectCollection(the project tree) and drawn on the VisPy canvas. - File import is in
appHandlers/appIO.py. It calls the parsers inappParsers/and creates the objects.
- Every tool inherits
AppTool(appTool.py). - The lifecycle is:
__init__(app), theninstall()(adds the menu entry and the shortcut), thenrun()(opens the tool), thenconnect_signals()orset_tool_ui(). - Connect and disconnect the widgets with
ui_connect()andui_disconnect(), so that a signal is not connected twice. - Two layouts exist in
appPlugins/:-
Single-file plugins: one file with the tool class and the UI class (for example
appPlugins/ToolDrilling/Drilling.py). -
Split plugins: one folder with the controller, the UI, the model, and the generator. The file names carry the tool name. ToolNCC and ToolPaint use
Ncc.py,NccUI.py,NccModel.py, andNccGen.py(andPaint.py,PaintUI.py,PaintModel.py,PaintGen.py).
-
Single-file plugins: one file with the tool class and the UI class (for example
- The plugins are imported in
appPlugins/__init__.py.appMain.pycreates each tool (for exampleself.ncclear_tool = ToolNcc(self)) and callsinstall().
- Three editors with their own plugin folders:
appEditors/appGerberEditor.pywithgrb_plugins/,appGeoEditor.pywithgeo_plugins/, andappExcEditor.pywithexc_plugins/. - Editor plugins inherit
AppToolEditorand use theEditorToolandEditorUIpattern.
- The files in
preprocessors/are loaded byappPreProcessor.pyat start-up. Each class registers itself by its class name. See Preprocessors.
-
tclCommands/has one class for each command, for exampleTclCommandDelete. The base class isTclCommand(tclCommands/TclCommand.py).TclCommandSignaledadds asynchronous execution with a signal that blocks until the work is done. - See Tcl Scripting for the use of the commands.
-
defaults.pyholds the factory values (AppDefaults).AppOptionsholds the values in use. - The preferences UI is in
appGUI/preferences/, one folder for each section.PreferencesUIManager.pylinks the widgets to the option keys and saves them. - A tool syncs its own widgets with the preferences (
storage_to_form()andform_to_storage()).
- The Tools Database is
appDatabase.py(the UI) andappCommon/ToolDatabase.py(the SQLite storage). See Tools Database.
- Python 3.11 or newer.
- PyQt6, VisPy, Shapely, NumPy, rtree, ezdxf, lxml, svglib, reportlab, and the other packages in
requirements.txt. - Optional:
requirements-optional.txt(OR-Tools for the path optimization, and other extras). - A conda or mamba environment is also possible:
environment.yml.
Windows (PowerShell, in the repository folder):
python -m venv .venv
.venv\Scripts\python.exe -m pip install --upgrade pip
.venv\Scripts\python.exe -m pip install -r requirements.txt
.venv\Scripts\python.exe flatcam.py
Linux or macOS:
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
.venv/bin/python flatcam.py
- On Linux, GDAL may need the system library. The README gives the exact steps.
- A file can be given on the command line:
python flatcam.py board.FlatPrj. - Headless mode runs without a window:
python flatcam.py --headless --command="..."(see Command Line and Headless). - The user data (preferences, the Tools Database, the logs, and your own preprocessors) is in the data folder. See Preferences Overview.
The tests are in tests/ and use pytest. They run without a display. Never start the GUI for a test run.
Run these from the repository root, with the .venv interpreter (PowerShell on Windows).
| When | Command | Time |
|---|---|---|
| While you work on an area | .venv\Scripts\python.exe -m pytest tests\test_<area>.py -q -p no:cacheprovider |
seconds |
| Before each commit | .venv\Scripts\python.exe tests\gates\run_core.py |
about 35 to 60 s |
| Before each push | .venv\Scripts\python.exe tests\gates\run_gate.py |
about 1 to 2 minutes |
| After a change of test files | .venv\Scripts\python.exe tests\gates\check_gate.py |
seconds |
-
run_core.pyruns every test file except the slow ones listed intests/gates/slow_files.txt. It compares the outcomes withtests/gates/outcome_baseline.json. A new test file is in the core by default. -
run_gate.pyruns the whole suite and compares it with the baseline. -
--workers 0runs one serial process. Use it to find a test that leaves a global state for the next test. - The test budget is in
tests/gates/test_budget.json. Above the budget the gate prints a warning and does not fail. - The README of the tests folder is
tests/README_gates.md.
| Marker or variable | Effect |
|---|---|
@pytest.mark.hardware and FLATCAM_TEST_HARDWARE=1
|
Tests that need a real machine. Off by default. |
@pytest.mark.timing and FLATCAM_TEST_TIMING=1
|
Tests that measure time on the GUI thread. Off by default. |
@pytest.mark.diptrace and FLATCAM_TEST_DIPTRACE=1
|
Slow DipTrace importer tests. Off by default. |
- Put a test in the topical file of its area (
tests/test_<area>.py). Do not create a new file for each ticket. - Test what the user sees: the wrong output, the wrong geometry, a lost undo step, a corrupt file, an unsafe machine move.
- Do not test private attributes, the order of calls, the source text, or the exact text of a log.
- Wait for a state in a GUI test (a loop with
qWaitand a limit), not for a fixed time.
- Create a folder in
appPlugins/, or one file (for a small tool). Use the tool name as the prefix of the files. - Write the controller class. Inherit
AppTool:
from appTool import AppTool
class ToolMyTool(AppTool):
def __init__(self, app):
AppTool.__init__(self, app)
self.app = app
def install(self, icon=None, separator=None, **kwargs):
# adds the menu entry; see appTool.py for the arguments (icon, separator, shortcut, pos)
AppTool.install(self, icon=icon, separator=separator, **kwargs)
def run(self, toggle=True):
AppTool.run(self)
self.set_tool_ui()
self.connect_signals()
def connect_signals(self):
self.ui_connect()
def ui_connect(self):
# connect the widget signals here; pair each one with a disconnect in ui_disconnect()
pass
def ui_disconnect(self):
pass
def set_tool_ui(self):
# build or refresh the widgets of the tool
passThe arguments and the base behavior of each method are in appTool.py. Look at appPlugins/ToolNCC/Ncc.py for a complete example.
- Write the UI class (the widgets, with
_()around each text that the user reads). - Write the generator (the algorithm) in a separate file with no widgets. It can then be tested without the GUI.
- Import the plugin in
appPlugins/__init__.py. - Create it in
appMain.pynext to the other tools, and callinstall(). - Add the preferences in
defaults.pyand in the preferences UI. - Add the tests (see above).
Rules from the repository:
- Use
ui_connect()andui_disconnect()pairs. - Do not use mixins.
- Use
quad_segs = steps // 4for the circle segments. - Use
history_of(app)for an undo step.
- Create
tclCommands/TclCommandMyCommand.py. The module name must start withTclCommandand the class name must be the same as the module name. - Inherit
TclCommand(orTclCommandSignaledfor a long task). - Set the attributes and the
executemethod:
import collections
from tclCommands.TclCommand import TclCommand
class TclCommandMyCommand(TclCommand):
aliases = ['my_command']
description = '%s %s' % ("--", "Does something with the object.")
arg_names = collections.OrderedDict([
('name', str),
])
option_types = collections.OrderedDict([
('outname', str),
])
required = ['name']
def execute(self, args, unnamed_args):
# the object is found by its name in the project; see tclCommands/TclCommandDelete.py for a full example
return 'OK'-
aliasesare the command names.arg_namesare the positional arguments.option_typesare the options (-name value).requiredlists the mandatory names. -
tclCommands/__init__.pyloads every module of the folder withpkgutil, so a new file is found without an import line. - The Tcl commands do not plot. Keep the work in the object, not in the command.
- Add a test in the tcl test file of the area.
See Preprocessors for the methods, the variables, and the folders. A preprocessor is a Python class that inherits PreProc (milling) or AppPreProcTools (solder paste) and implements all abstract methods.
- Report bugs and ask for features in the GitHub issues. Attach the Gerber, Excellon, or project file, and the
log.txtfrom the data folder. - Pull requests are welcome. Make them against the development branch
1.0, and add tests for the changes. - Run
run_core.pybefore each commit andrun_gate.pybefore a push. - Keep the changes small and focused. One commit for one change.
- Translations are in the
localefolder. See Translating.
FlatCAM Evo Manual · Source code · Report a problem · MIT license
Start here
- Installation
- Getting Started
- Tutorial: Single-Sided PCB
- Tutorial: Double-Sided PCB
- User Interface
- Keyboard Shortcuts
- Glossary
- FAQ and Troubleshooting
Files and projects
Objects
Editors
PCB operations
- Isolation Routing
- Non-Copper Clearing
- Paint
- Cutout
- Drilling
- Milling
- Follow
- Double-Sided
- Solder Paste
- Film
- Panelize
- Copper Thieving
- Fiducials
- Markers
- Punch Gerber
- Invert Gerber
- Etch Compensation
- Extract
- Rules Check
- QR Code
Utility plugins
- Align Objects
- Calculators
- Distance · Object Distance
- Optimal
- Move · Transform
- Subtract
- Image Import · PDF Import
- PCB Wizard
- Report
- Tcl Shell
Machine control (in development)
Advanced
- Tools Database
- Preprocessors
- Path Optimization
- Tcl Scripting
- Tcl Command Reference
- Developer Guide
- Translating
Preferences