Overview#
Every Fusion API program navigates a tree of objects. If you understand the shape of that tree and a handful of conventions, the several thousand classes in the reference stop looking intimidating, because they follow the same patterns repeatedly. This page covers the top of the tree: Application, Document, Product, Design, Component, Occurrence, and the collections hanging below them, plus the conventions (cast, isValid, collections, createInput) used throughout.
Where to find it#
You do not open anything in the Fusion interface for this; you read the API Reference Manual in the online help. In the reference, the left-hand tree lists classes by module (adsk.core, adsk.fusion, adsk.cam). The most useful pages for this topic are Application, Document, Product, Design, Component, Occurrence, Sketch, and Features. There is also an Object Model diagram page in the help (search for "Fusion Object Model"). Open it in a tab and keep it there.
The big picture#
Application
|- userInterface (UserInterface)
|- documents (Documents)
| `- Document
| |- products (Products)
| | |- Design (Design workspace data)
| | |- CAM (Manufacture workspace data)
| | `- others (e.g. drawing data in recent versions)
| `- dataFile (DataFile) -> cloud identity
|- activeDocument
|- activeProduct (the Product currently shown)
`- preferences, importManager, ...
Design
|- rootComponent (Component)
|- allComponents
|- userParameters, allParameters
|- exportManager
|- unitsManager
|- timeline
`- designType (Parametric or Direct)
Component
|- sketches, bRepBodies, meshBodies
|- features (extrudeFeatures, revolveFeatures, filletFeatures, ...)
|- constructionPlanes, constructionAxes, constructionPoints
|- occurrences (child components) -> Occurrence -> component
|- joints, asBuiltJoints, rigidGroups
`- modelParameters
Application#
adsk.core.Application.get() returns the singleton. Useful members:
| Member | Meaning |
|---|---|
userInterface | Access to dialogs, palettes, command definitions, workspaces |
activeDocument | The document in the front tab |
activeProduct | The product of the active document that the user is looking at |
documents | All open documents, plus documents.add(...) and documents.open(...) |
userName, version, currentUser | Account user name, Fusion version string, and the logged-in User |
scripts | The Scripts object that manages scripts and add-ins |
data | The Data object for hubs, projects, folders and files |
log(message) | Writes to the Text Commands window |
executeTextCommand(cmd) | Runs a text command, which can reach behaviour not otherwise exposed |
preferences | The user's preferences, such as default units |
Document and Product#
A Document corresponds to a tab. It holds one or more Products, which are the data behind the workspaces. The Design product is the geometry; the CAM product holds Manufacture data. To get the design of a specific document rather than the active product:
import adsk.core, adsk.fusion
app = adsk.core.Application.get()
doc = app.activeDocument
design = doc.products.itemByProductType('DesignProductType')
design = adsk.fusion.Design.cast(design)
itemByProductType takes a string identifier. 'DesignProductType' and 'CAMProductType' appear in Autodesk's samples; Application.supportedProductTypes returns the names your Fusion supports (the reference says "DesignProductType" is the name for Fusion).
doc.dataFile returns the DataFile that "represents this document in A360", with the file name, id, version number, extension and parent folder. > Note: not confirmed in Autodesk's documentation: what dataFile returns for a document that has never been saved; test for None before use.
Design#
adsk.fusion.Design is the root of the modeling data. Beyond rootComponent, note:
design.designTypereturnsDirectDesignTypeorParametricDesignType; changing parametric to direct deletes the timeline and history.design.activeComponentis the component the user is currently editing in the browser, useful when a script should act "where the user is".design.activeEditObjectis the object being edited (a sketch, or a component).design.timelinegives access to the timeline items and the marker, so you can roll back and forward.design.snapshotsgives access to design snapshots.design.unitsManageris theUnitsManager;design.fusionUnitsManageris a specialized one that can set default length units and work with parameters.design.userParametersanddesign.allParametersare covered on the parameters page.
Component, Occurrence, and the instance model#
A Component is a definition: a container for sketches, features, bodies, and other components. An Occurrence is an instance of a component placed inside another, carrying a transform. The root component of the design is a special component with no occurrence.
This split matters. If you copy the same bracket four times in an assembly, there is one Component with four Occurrences. Editing the Component edits all four.
def walk(component, depth=0):
indent = ' ' * depth
app = adsk.core.Application.get()
app.log(f'{indent}{component.name} (bodies: {component.bRepBodies.count})')
for occ in component.occurrences:
walk(occ.component, depth + 1)
Note that occ.component may be visited more than once if the definition is instanced several times. If you want each definition once, use design.allComponents.
Very important: geometry in an occurrence has two forms (Autodesk's reference says Occurrence.bRepBodies returns body proxies that report information "in the context of the root component"). occ.component.bRepBodies returns the bodies in the definition's own space. occ.bRepBodies returns proxies that carry the occurrence transform. For anything that depends on where the part sits in the assembly (bounding boxes, exporting positioned geometry, measuring between parts) use the proxy objects (occurrence.bRepBodies), or call body.createForAssemblyContext(occurrence) to produce one.
Entity and attributes#
Most objects derive from Base, and many geometric objects derive from Entity. Entities have entityToken, a string that identifies them persistently within the document, handy for storing a reference between runs:
token = body.entityToken
found = design.findEntityByToken(token) # returns an array of matching entities
Design.findEntityByToken returns an array: usually one entity, but more than one when, for example, a face was split by later operations (the first is the most logical match). Check its length.
You can also tag objects with attributes: key-value pairs stored in the document. entity.attributes.add('MyGroup', 'MyName', 'value') writes one; design.findAttributes('MyGroup','MyName') retrieves all. Attributes survive save and reopen, making them the proper way to remember what your tool did to a design.
Conventions#
Collections#
Collections like Sketches, BRepBodies, Occurrences support (all collections support count and item, zero based):
.count,.item(index)and, in Python,len(collection),collection[i], negative indexes, slices such ascollection[:2](which return lists) and iteration withfor x in collection..itemByName(name)or.itemById(id)on many of them. (A missing item is documented to return null for these.).add(...)or.createInput(...)followed by.add(input).
Example of a lookup:
sketch = root.sketches.itemByName('Profile')
if sketch is None:
sketch = root.sketches.add(root.xYConstructionPlane)
sketch.name = 'Profile'
Input objects#
For features, Fusion uses an input object pattern: you ask the collection to create an input, you fill in its properties, and you pass it back to create the feature. The input is a transient object, not part of the document.
ext_input = root.features.extrudeFeatures.createInput(profile, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
ext_input.setDistanceExtent(False, adsk.core.ValueInput.createByString('10 mm'))
ext = root.features.extrudeFeatures.add(ext_input)
ValueInput wraps a number or an expression. createByReal(2.5) takes a value in internal units (cm or radians); createByString('10 mm') takes an expression evaluated by the parameter system, and so can reference named parameters like 'width / 2'. Strings preserve the parametric link; reals do not.
Casting#
Many properties return a base type (activeProduct is typed as Product; Selection.entity as Base). .cast() is a static method on every class: adsk.fusion.Design.cast(product) returns the object as a Design if it is one, else None. Autodesk's Python topic offers three ways to test types: type(obj) is adsk.fusion.SketchLine for the exact type, isinstance(obj, adsk.fusion.SketchEntity) for any derived type (SketchLine derives from SketchCurve, which derives from SketchEntity), and cast. Type hints (des: adsk.fusion.Design = app.activeProduct) only help the editor; they do not check anything at run time. To compare two API objects use ==, not is.
Validity#
Objects can go stale. Every object has isValid, which returns False when the reference "has been deleted or some other action done to invalidate" it. When you hold objects across a long operation or between event firings, re-fetch them, or test isValid.
Naming#
Properties are lower-camel-case (rootComponent, bRepBodies). Classes are upper-camel (BRepBody). Enumerations live on the module (adsk.fusion.FeatureOperations.NewBodyFeatureOperation). Boolean properties usually start with is or has. Input objects hold settings, and definition objects are their editing counterpart: on a definition the properties that took a ValueInput become read-only and return a Parameter. Collections are plural. Python wrappers return out arguments as a tuple, for example (ok, x, y, z) = point.getData(), and returned "arrays" are API vector objects that you can wrap with list(...).
Step by step#
A traversal script that prints a summary of the whole design:
- Create a new script
DesignSummary. - Use this body for
run:
import adsk.core, adsk.fusion, traceback
def run(context):
ui = None
try:
app = adsk.core.Application.get()
ui = app.userInterface
design = adsk.fusion.Design.cast(app.activeProduct)
if not design:
ui.messageBox('No active design')
return
lines = []
lines.append(f'Document: {app.activeDocument.name}')
lines.append('Type: ' + ('Parametric' if design.designType == adsk.fusion.DesignTypes.ParametricDesignType else 'Direct'))
lines.append(f'Components: {design.allComponents.count}')
for comp in design.allComponents:
lines.append(
f'- {comp.name}: {comp.sketches.count} sketches, '
f'{comp.bRepBodies.count} bodies, '
f'{comp.features.count} features, '
f'{comp.occurrences.count} child occurrences'
)
lines.append(f'User parameters: {design.userParameters.count}')
lines.append(f'Timeline items: {design.timeline.count}')
ui.messageBox('\n'.join(lines), 'Design summary')
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
- Run it on a multi-component assembly and compare with the browser.
comp.features.count counts items in the combined Features collection for that component. The design.timeline.count property is the number of timeline items, which may differ from feature counts because sketches and other items also appear.
Options reference#
Key classes and their purpose.
| Class | Module | Purpose | Notes |
|---|---|---|---|
Application | core | Entry point | Singleton |
UserInterface | core | Dialogs, commands, workspaces, palettes | app.userInterface |
Document | core | An open file/tab | .dataFile, .save(), .close() |
Product | core | A workspace's data | Cast to Design or CAM |
Design | fusion | Modeling data | .rootComponent, parameters |
Component | fusion | Definition container | Sketches, bodies, features |
Occurrence | fusion | Instance with transform | .component, .transform2 (.transform is retired) |
Sketch | fusion | 2D profile container | .sketchCurves, .profiles |
BRepBody | fusion | Solid or surface body | Faces, edges, vertices |
Features | fusion | Collection of feature collections | extrudeFeatures, etc. |
Parameter / UserParameter | fusion | Named values | Expression and unit |
Matrix3D, Point3D, Vector3D | core | Geometry helpers | Point3D.create(x,y,z) |
ObjectCollection | core | Generic list for API calls | ObjectCollection.create() |
ValueInput | core | Number or expression | createByReal, createByString |
Tips and pitfalls#
Tip:
adsk.core.ObjectCollection.create()is how the API receives a group of objects (for example the edges for a fillet edge set); Autodesk's samples build one with.add(...). Where a method is documented to take an "array", a Python list or tuple works.
Tip: When exploring unknown objects, use
dir(obj)in a debugger session to list members, or hover over a variable in VS Code. The reference remains the source of truth.
Warning:
Occurrence.transformis retired: the reference says it "returns incorrect results in some cases" and recommendstransform2. Usetransform2in new code.
Warning: Collections are zero-based: the first item is index 0 and the last is
count - 1.
Practice exercise#
Write a script that finds every occurrence in the active design that is currently hidden (occurrence.isLightBulbOn == False) and lists their names, including their full path (occurrence.fullPathName). Test it on a model where you have turned off a couple of components with the light bulb icon.
Expected result: a message box listing only the hidden occurrences, with a path such as Frame:1+Bracket:2.
Related#
- Sketches and features
- Parameters
- UI, commands, and palettes
- Event handlers