Start

How pyNavis works

The mental model behind every tool you will write: folders on disk become buttons on the ribbon, and a button runs a Python file.

pyNavis is a Python scripting host for Autodesk Navisworks. It loads a plugin into Navisworks at startup, scans folders on disk, and builds a ribbon tab from what it finds. Clicking a button executes a Python file. That is the heart of the system, and everything else, from event hooks to dock panels, hangs off the same folder scan.

If you have written pyRevit extensions, this will feel familiar and mostly transfers. If you have not, the important idea is that the folder structure is the configuration. There is no manifest listing your commands, no registration call, no project file, and no compile step. A folder named Export.pushbutton containing a file named script.py is a working button.

From disk to ribbon#

Each level of the folder tree maps to one level of the ribbon. The suffix on the folder name decides what it becomes, and the folder name itself becomes the visible label.

On disk MyTools.extension Survey.tab Export.panel 01_Points.pushbutton script.py icon.png 02_Mesh.pushbutton script.py icon.png tab panel buttons On the ribbon Home View Survey Export Points Mesh The folder name becomes the label. The leading “01_” orders the buttons and is stripped from the title.
Four folder levels, four ribbon levels. Nothing else registers a command: if the folders are right, the button exists.

What a button actually does#

When you click a button, the runtime picks an engine, creates a fresh scope, injects four variables into it, and executes script.py top to bottom. Your script talks to Navisworks through the pynavis library, which wraps the .NET API in something Pythonic. The library is organised by domain: selection, sets, props, viewpoints, clash, clashtest and export face the model, toast, forms and output face the user, and the API reference lists every function in all of them.

MyTools.extension/Survey.tab/Export.panel/01_Points.pushbutton/script.py
"""Exports the current selection to CSV."""
from pynavis import forms, selection, toast

items = selection.get_items()
if not items:
    toast.error('Nothing selected', 'Select something first, then run this again.')
else:
    path = forms.save_file(default_name='points.csv')
    if path:                                  # None means the user cancelled
        with open(path, 'w') as handle:
            for item in items:
                handle.write(item.DisplayName + '\n')
        toast.success('Exported %d items' % len(items), path)

That script is a complete, shippable tool. It has an icon-less button, a tooltip taken from its docstring, a title taken from its folder name, and it reports its result without opening a window.

The two engines#

Every bundle runs on one of two Python engines. The choice is a single line in bundle.yaml, and it matters more than it looks.

 IronPythonCPython
Engine idironpython (the default)cpython
Version3.4Whatever is installed, typically 3.11 or later
Runs in-processYes, on the Navisworks .NET runtimeYes, through pythonnet
Can subclass .NET and COM typesYesNo
Third-party wheels (numpy, pandas)NoYes
Needs Python installedNo, it ships with pyNavisYes
Use it whenAlmost alwaysYou need a compiled package or modern syntax
Rule of thumb

Start on IronPython. It is the default, it has no external dependency, and it is the only engine that can subclass the COM interfaces some parts of the Navisworks API require. Move a single bundle to CPython only when you hit a wall, such as needing numpy.

Beyond the plain button#

The pushbutton is one of twelve folder kinds a panel understands. Stacks and pulldowns pack more tools into the same ribbon space; toggles, smartbuttons and the two split buttons change how a button behaves; nobuttons, urlbuttons and linkbuttons cover the commands that are not really scripts. Two are not buttons at all: *.dockpane is a dockable Navisworks panel whose content is WPF from a pane.xaml, shown and hidden by a ribbon toggle, and *.slideout is a marker folder whose contents move into the flyout the panel title opens. Buttons, stacks and pulldowns walks through all twelve.

Code can also run without a click. An extension may carry hooks\<event>.py scripts that run themselves when one of fourteen Navisworks events fires, from doc-opened to camera-moved, and a startup.py at its root that runs at boot and on every Reload, before that extension's ribbon builds. Hooks covers the events and their rules; Anatomy of an extension covers startup.py and the shared *.lib library folders.

Where everything lives#

Everything pyNavis installs lands in your own user profile, which is why installing it needs no administrator rights. Two installations are possible and they differ only in where the runtime and your extensions sit. An ordinary install is what the setup program and tools/install.ps1 produce; a development install, from tools/deploy-dev.ps1, points the runtime back at a repository checkout.

WhatInstalledDevelopment
Loader plugin %APPDATA%\Autodesk\ApplicationPlugins\pyNavis.bundle\Contents\<year>\
Extensions %APPDATA%\pyNavis\extensions Any folder listed in config.json
Runtime and stdlib %APPDATA%\pyNavis\<year>\runtime bin\<year>\runtime in the checkout
pynavis library Beside the runtime pynavislib\ in the checkout
Your settings %APPDATA%\pyNavis\config.json
Per-tool settings %APPDATA%\pyNavis\settings\<tool>.json
Selection memory %APPDATA%\pyNavis\memory\
Logs %APPDATA%\pyNavis\logs\

The runtime scans every folder listed under "extensions" in config.json, plus two defaults: %APPDATA%\pyNavis\extensions, where the shipped extension lives, and %PROGRAMDATA%\pyNavis\extensions if that folder exists, which is how an IT department deploys extensions to a whole machine. All of them are scanned, so a development extension and an installed one can coexist.

Which loader Navisworks picks

The bundle folder holds one Contents\<year> folder per Navisworks release and a PackageContents.xml naming them, so a single install serves every release on the machine and Navisworks loads only the folder matching its own. The runtime the loader then hands over to is resolved in order: the PYNAVIS_RUNTIME environment variable, the runtime<year> key in config.json, %APPDATA%\pyNavis\<year>\runtime, then %PROGRAMDATA%\pyNavis\<year>\runtime. The first one that exists wins, and the log names the winner near the top.

The development loop#

The loop is short, which is the point of the whole system.

  1. Create or edit a file inside your extension folder.
  2. Click Reload on the pyNavis panel.
  3. Click your button.

Reload rescans every extension folder and rebuilds the ribbon without restarting Navisworks. It picks up new bundles, renamed folders, changed bundle.yaml values, new icons, and changed shortcuts. It also reruns each extension's startup.py, re-reads the hook scripts, and rebuilds the content of any dock panel that is open.

One exception

Edits to script.py and to modules inside your bundle or your extension's lib\ folder are picked up on every run, with no Reload needed, because the runtime drops those modules from the cache before each execution. Edits to the pynavis library itself, or to modules inside a shared *.lib folder, need a Reload. Changes to the C# runtime, adding or removing a whole *.lib folder, and new panel slots need a Navisworks restart.

What you cannot do#

Being honest about the boundaries saves time:

  • No background threads touching the model. The Navisworks API is not thread-safe. Your script runs on the UI thread and should stay there.
  • One script at a time. The runtime refuses a second run while one is in flight and toasts “still running”. Long jobs block the UI, so report progress.
  • No custom ribbon controls. The ribbon vocabulary is the twelve bundle kinds. There are no combo boxes, sliders or galleries on the ribbon itself; when a tool needs persistent controls, give it a *.dockpane panel instead.
  • No package installer. There is no requirements.txt handling. Vendor pure-Python dependencies into your extension's lib\ folder, or use CPython and its own site-packages.

Where to go next#