solidcam-api
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.
Table of Contents
- Requirements
- Installation
- Quick start
- Usage examples
- API overview
- Error handling
- Testing without SolidCAM
- Contributing
- License
Requirements
| 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.
Installation
pip install solidcam-api
With development tools (linting, type checking, tests):
pip install "solidcam-api[dev]"
With documentation build dependencies:
pip install "solidcam-api[docs]"
Quick start
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()
Usage examples
Open a part and generate G-code
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()
Change the reference model and recalculate
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()
List machines, operations, and tools
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()
Create stock and target geometry
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()
Apply a process template
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()
Generate a tool sheet
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()
API overview
All methods and properties are available directly on SolidCAMClient.
Connection lifecycle
| 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 |
General
| 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) |
CAD
| 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 |
CAM
| 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 |
Machine
| 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 |
Part
| 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 |
Operation
| 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 |
Tool
| 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 |
Geometry
| 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 |
Templates
| 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 |
Error handling
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}")
Exception hierarchy
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
Testing without SolidCAM
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)
Contributing
- 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.
Project structure
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
License
MIT © 0ndrec
Metadata
Release files for solidcam-api 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| solidcam_api-0.2.0.tar.gz | 27.5 kB | Without provenance | Details for solidcam_api-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| solidcam_api-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for solidcam_api-0.2.0-py3-none-any.whl |
Total release size: 67.2 kB
Release files / solidcam_api-0.2.0.tar.gz
| Download URL | solidcam_api-0.2.0.tar.gz |
|---|---|
| Size | 27.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
527f0d25e066840c01f12afba38598fcfd3314e1a4cbe2727ac5674953e82def
|
|
BLAKE2b-256 checksum How to use checksums |
04a16c9230895e0d5f7ec31ac5d1c3a183f3fd4450247d7ee90b81dd35fae844
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / solidcam_api-0.2.0-py3-none-any.whl
| Download URL | solidcam_api-0.2.0-py3-none-any.whl |
|---|---|
| Size | 39.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2ee77fea4e20eb21a945fec662dcdd7edeb4085279a477b0f1187dbf6b6c0ddf
|
|
BLAKE2b-256 checksum How to use checksums |
f1583eb4ed13de828261e1a2ba58fc1cb3d7b22ed5f456f50ca758a375d900bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for solidcam-api 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.