A fully-typed Python library for the SolidCAM Automation COM API (scautom.dll).
solidcam-api wraps every section of the SolidCAM Automation API — General, CAD, CAM, Machine,
Part, Operation, Tool, Geometry, and Templates — in a clean, Pythonic interface with:
- Full type annotations and a
py.typedmarker (PEP 561) - Frozen dataclasses for all result objects
IntEnumconstants for all integer codes- A context-manager-friendly client
- Dependency injection / mock support for unit testing without SolidCAM
Platform note — SolidCAM is a Windows application.
The COM layer is only active on Windows; the package can be imported on any OS for documentation builds, static analysis, and testing with mocks.
- Requirements
- Installation
- Quick start
- Usage examples
- API overview
- Error handling
- Testing without SolidCAM
- Contributing
- License
| Requirement | Version |
|---|---|
| Python | ≥ 3.13 |
| pywin32 | ≥ 307 (Windows only) |
| SolidCAM | any version with scautom.dll registered |
Before using the library, the SolidCAM COM server must be registered:
regsvr32 "C:\Program Files\SolidCAM\scautom.dll"This is done automatically by the SolidCAM installer.
pip install solidcam-apiWith development tools (linting, type checking, tests):
pip install "solidcam-api[dev]"With documentation build dependencies:
pip install "solidcam-api[docs]"from solidcam_api import SolidCAMClient
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"C:\CAM\my_part.prz")
sc.calculate()
sc.generate_gcode()
sc.close()from solidcam_api import SolidCAMClient
with SolidCAMClient() as sc:
# Start host CAD (SolidWorks) — wait for plugin to initialise
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
# Open a CAM part (no reference-model replacement)
sc.open(r"D:\jobs\bracket.prz")
# Check current part info
print(sc.part_path) # D:\jobs\bracket.prz
print(sc.part_type) # PartType.MILLING
print(sc.reference_model) # D:\cad\bracket_v3.sldprt
# Synchronise, calculate all operations, write G-code
sc.synchronize()
sc.calculate()
sc.generate_gcode()
# Save to a delivery folder
saved_path = sc.save(r"D:\output")
print(f"Saved to {saved_path}")
sc.close()from solidcam_api import SolidCAMClient
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"D:\jobs\bracket.prz")
# Swap in the new revision of the CAD model
sc.change_reference_model(r"D:\cad\bracket_v4.sldprt")
sc.synchronize()
sc.calculate()
sc.generate_gcode()
sc.close()from solidcam_api import SolidCAMClient
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"D:\jobs\bracket.prz")
# --- Machines ---
print(f"Available machines ({sc.machine_count}):")
for machine in sc.list_machines():
print(f" [{machine.index}] {machine.name}")
print(f"Current machine: {sc.current_machine_name}")
# --- Operations ---
print(f"\nOperations ({sc.operation_count}):")
for op in sc.list_operations():
print(f" [{op.index}] {op.name!r:30s} type={op.type}")
# Suppress a roughing pass for a quick finish-only run
sc.suppress_operation("Roughing_1", suppress=True)
# --- Tools ---
print(f"\nTools ({sc.tool_count}):")
for tool in sc.list_tools():
print(f" [{tool.index}] {tool.name!r:25s} type={tool.type}")
sc.close()from solidcam_api import SolidCAMClient, StockDefineBy, TargetDefineBy
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"D:\jobs\new_part.prz")
# Create a box stock with 2 mm offsets on every face
sc.create_stock_box(
name="Stock_Box",
x_plus=2.0, x_minus=2.0,
y_plus=2.0, y_minus=2.0,
z_plus=2.0, z_minus=0.0, # no offset on the bottom face
define_by=StockDefineBy.SOLID,
generate_stock_envelope=True,
)
# Create a cylindrical stock for a turning part
sc.create_stock_cylinder(
name="Bar_Stock",
right=3.0,
left=3.0,
external_diameter=2.0,
define_by=StockDefineBy.SOLID,
)
# Create a target from the finished solid
sc.create_target(
name="Finished_Part",
define_by=TargetDefineBy.SOLID,
generate_envelope=True,
)
# Inspect resulting geometry entries
for geom in sc.list_geometries():
print(geom.name)
sc.close()from solidcam_api import SolidCAMClient
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"D:\jobs\new_part.prz")
# List available process templates
for pt in sc.list_process_templates():
print(pt.name)
# Instantiate a process template against an existing geometry
sc.create_jobs_from_process_template(
process_template_name="Finish_Profile_Template",
geometry_name="Finished_Part",
sub_machine_index=1,
)
sc.calculate()
sc.generate_gcode()
sc.close()from solidcam_api import SolidCAMClient
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"D:\jobs\bracket.prz")
# Discover available templates
print(sc.list_tool_sheet_names())
# e.g. ['Sheet_Full_HTML', 'Sheet_Full_RTF', ...]
sc.generate_tool_sheet("Sheet_Full_HTML")
sc.close()All methods and properties are available directly on SolidCAMClient.
| Member | Description |
|---|---|
SolidCAMClient(prog_id, *, com_object) |
Initialise (no COM connection yet) |
.connect() |
Create the COM dispatch object |
.disconnect() |
Release the COM dispatch object |
.is_connected |
True if the COM object is held |
with SolidCAMClient() as sc: |
Preferred: auto connect/disconnect |
| Member | Description |
|---|---|
.last_error |
Last error code (0 = no error) |
.last_error_description |
Human-readable last error message |
.log_file |
Path to the API log file (get/set) |
.pid |
Process ID of the target SolidCAM instance (get/set) |
.is_solidcam_running() |
True if SolidCAM process is active |
.start_application(path, wait_for_plugin) |
Start SolidWorks or standalone SolidCAM |
.start_solidcam() |
Start SolidCAM plugin (SolidWorks must be running) |
| Member | Description |
|---|---|
.open_host_file(path) |
Open a CAD file in the host |
.is_active_doc_cam_part |
True if the active document is a CAM part |
.render_preview(path) |
Generate a PDM preview image |
| Member | Description |
|---|---|
.open(part_path, model_path) |
Open a CAM part; optionally replace reference model |
.check_synchronization() |
Check sync status |
.synchronize() |
Synchronise the CAM part with its reference model |
.calculate(only_not_calculated) |
Calculate all (or only outdated) operations |
.calculate_operations(operations, only_not_calculated) |
Calculate a list of named operations |
.calculate_single_operation(number) |
Calculate one operation by number |
.change_post_processor_directory(path) |
Change the post-processor directory |
.generate_gcode() |
Generate G-code for the entire part |
.save(folder) |
Save to folder; returns the saved file path |
.save_as(path) |
Save to a new file path |
.save_to_folder(folder) |
Save to folder; returns the saved file path |
.close() |
Close the currently open CAM part |
.exit() |
Close SolidCAM entirely |
| Member | Description |
|---|---|
.machine_count |
Number of available machines |
.current_machine |
Index of the active machine (get/set) |
.current_machine_name |
Name of the active machine |
.get_machine_name(index) |
Name of machine at index |
.list_machines() |
list[Machine] of all machines |
| Member | Description |
|---|---|
.part_path |
Path to the currently open CAM part |
.part_type |
PartType of the open part |
.reference_model |
Path to the reference CAD model |
.change_reference_model(model_path) |
Replace the reference model |
.create_new_part(name, path, part_type, machine_index, home_origin_position, inch) |
Create a new CAM part |
| Member | Description |
|---|---|
.operation_count |
Number of NC operations |
.number_of_jobs_with_exclamation_sign |
Count of operations with warnings |
.get_operation_name(index) |
Name of operation at index |
.get_operation_type(index) |
Raw type code of operation at index |
.get_operation(index) |
Operation dataclass at index |
.list_operations() |
list[Operation] of all operations |
.suppress_operation(name, suppress) |
Suppress or unsuppress a named operation |
.generate_gcode_for_operation(name, file_name) |
G-code for one operation |
| Member | Description |
|---|---|
.tool_count |
Number of tools in the tool table |
.tool_sheet_count |
Number of tool-sheet templates |
.get_tool_name(index) |
Name of tool at index |
.get_tool_type(index) |
Raw type code of tool at index |
.get_tool_tag(number, position, station, turret) |
Unique tool tag by address |
.get_tool(index) |
Tool dataclass at index |
.list_tools() |
list[Tool] of all tools |
.set_operation_tool(operation_name, tool_tag) |
Assign a tool to an operation |
.get_operation_tool_tag(operation_name) |
Tag of the tool used by an operation |
.get_tool_sheet_name(index) |
Name of tool-sheet template at index |
.list_tool_sheet_names() |
list[str] of all template names |
.generate_tool_sheet(template_name) |
Generate a tool sheet |
| Member | Description |
|---|---|
.cad_coord_sys_count |
Number of CAD coordinate systems |
.get_cad_coord_sys_name(index) |
Name of CAD coord sys at index |
.get_cad_coord_sys(index) |
CoordSys at index |
.list_cad_coord_sys() |
list[CoordSys] |
.home_count |
Number of home positions |
.get_home_name(index) |
Name of home at index |
.get_home(index) |
HomeEntry at index |
.list_home_positions() |
list[HomeEntry] |
.create_home(home_origin_position) |
Create a home at a given origin |
.create_home_by_cad(cad_home_name) |
Create a home from a CAD coord sys |
.geom_count |
Number of geometry entries |
.get_geom_name(index) |
Name of geometry entry at index |
.get_geom(index) |
GeomEntry at index |
.list_geometries() |
list[GeomEntry] |
.create_target(...) |
Create a target solid geometry |
.create_stock_box(...) |
Create a box stock geometry |
.create_stock_cylinder(...) |
Create a cylindrical stock geometry |
| Member | Description |
|---|---|
.template_count |
Number of operation templates |
.get_template_name(index) |
Name of template at index |
.get_template(index) |
TemplateEntry at index |
.list_templates() |
list[TemplateEntry] |
.create_job_from_template(name, geometry, sub_machine, index) |
Instantiate one operation |
.process_template_count |
Number of process templates |
.get_process_template_name(index) |
Name of process template at index |
.get_process_template(index) |
ProcessTemplateEntry at index |
.list_process_templates() |
list[ProcessTemplateEntry] |
.create_jobs_from_process_template(name, geometry, sub_machine, index) |
Instantiate all operations |
All API methods raise SolidCAMAPIError on failure. The exception carries three
attributes: method (the API call that failed), code (the integer error code from
LastError), and description (the human-readable description from LastErrorDescription).
from solidcam_api import SolidCAMClient, SolidCAMAPIError, SolidCAMConnectionError
try:
with SolidCAMClient() as sc:
sc.start_application(r"C:\Program Files\SolidWorks\SLDWORKS.exe")
sc.open(r"D:\jobs\bracket.prz")
sc.calculate()
sc.generate_gcode()
sc.close()
except SolidCAMConnectionError as exc:
print(f"Could not connect to SolidCAM: {exc}")
except SolidCAMAPIError as exc:
print(f"API call '{exc.method}' failed (code {exc.code}): {exc.description}")SolidCAMError
├── SolidCAMConnectionError # COM object could not be created
├── SolidCAMNotRunningError # SolidCAM process not detected
├── SolidCAMNotOpenError # No CAM part is currently open
└── SolidCAMAPIError # A specific API call returned failure
.method – str
.code – int
.description – str
SolidCAMClient accepts a com_object keyword argument so you can inject a mock and test
automation scripts without a SolidCAM installation.
import unittest.mock as mock
from solidcam_api import SolidCAMClient, PartType
def test_calculate_called_after_open():
fake_com = mock.MagicMock()
fake_com.LastError = 0
fake_com.Open.return_value = 1
fake_com.Type = int(PartType.MILLING)
sc = SolidCAMClient(com_object=fake_com)
assert sc.is_connected
sc.open(r"C:\parts\test.prz")
sc.calculate()
fake_com.Open.assert_called_once_with(r"C:\parts\test.prz", "")
fake_com.Calculate.assert_called_once_with(False)- Fork the repository and create a feature branch.
- Install development dependencies:
pip install -e ".[dev]" - Make your changes and add tests under
tests/. - Lint and format:
ruff check src tests ruff format src tests
- Type-check:
mypy src
- Run tests:
pytest --cov=solidcam_api --cov-report=term-missing
- Open a pull request describing the change.
solidcam-api/
├── src/
│ └── solidcam_api/
│ ├── __init__.py # Public API surface
│ ├── py.typed # PEP 561 marker
│ ├── _com.py # Internal COM wrapper (win32com)
│ ├── client.py # SolidCAMClient — assembles all sections
│ ├── exceptions.py # Exception hierarchy
│ ├── enums.py # IntEnum constants (PartType, OperationType, …)
│ ├── models/ # Frozen dataclasses for result objects
│ │ ├── machine.py
│ │ ├── operation.py
│ │ ├── tool.py
│ │ ├── geometry.py
│ │ └── template.py
│ └── sections/ # Section mixins (one per API section)
│ ├── _base.py
│ ├── general.py
│ ├── cad.py
│ ├── cam.py
│ ├── machine.py
│ ├── part.py
│ ├── operation.py
│ ├── tool.py
│ ├── geometry.py
│ └── template.py
├── tests/
├── pyproject.toml
└── README.md
MIT © 0ndrec