Autodesk Revit
This guide provides the basic information about our Revit integration.
If this is your first time setting up an integration, we recommend to follow one of the Intermediate tutorials.
System requirements:
- 💻 Windows PC
- 🐍 Python =< 3.10
- A version of Revit (we use 2024 in this guide)
To integrate Revit into a VIKTOR application, you will require some additional software.
Download and install pyRevit
In order to use Revit with Python, you will need to download and install the pyRevit extension for Revit. You can find all the information you need to install pyRevit and connect it to your version of Revit in the pyRevit documentation. After following the steps of the installer, continue to the next section.
Additional information
You may want to consult some additional information about the software we are using, below you can find some useful links:
Setup work environment
Before you can start building your VIKTOR - Revit apps, you will need to complete some steps for the setup.
Step 1: Start a VIKTOR app
You will need to create, install and start an empty app. If you would like a quick reminder on how to do this, you can follow the steps here.
Step 2: Make/Choose a folder for the generic worker
The generic worker will require a folder which will be used to send information to the worker. This directory will also be where the results from the worker will be stored.
Step 3: Configure the generic worker
VIKTOR does not provide a dedicated worker for Revit, the generic worker can be combined with the Revit API and pyRevit hence we will need to set-up this generic worker with python. You can download the generic worker here.
In order to use the generic worker for Revit, you will need to copy the following information into your configuration. The file should look something like this:
executables:
revit:
path: 'C:\YOUR\PATH\TO\python.exe
arguments:
- 'command.py'
- etc
workingDirectoryPath: 'C:\PATH\TO\FOLDER\FROM\STEP\2'
maxParallelProcesses: 1 #must be one, please do not change
Make sure to add the command.py
file, you may also add other arguments such as a model.rvt
if you plan on uploading
models via the app.
Should you not have access to the worker but you do require access to the code that will be executed in Revit, then it
is possible to add another file script.py
to the arguments. This will let you send the instructions to the worker
instead of already having them on the worker. This does however have two drawbacks, debugging is difficult (unless you
have access to the worker logs) and it will cost some memory on your application.
Step 4: Test the worker
Test the worker by starting it as an administrator, the worker should tell you that it is active and you can also check it in your browser. For more information on the worker status, check out software integrations.
Step 5: Add a script.py to the step 2 folder
script.py
will have all the instructions for pyRevit to perform within Revit.
It is also possible to add this to the arguments if you do not have Revit on your machine, this may be desirable if you
want to be able to edit the script later.
Step 6: Add a command.py file to the VIKTOR app
In the folder of the VIKTOR app, copy the code below into a Python file. This code will let the worker's operating system know which script to run.
import os
#command to run:
command = 'pyrevit run "C:\\PATH\\TO\\SCRIPT.PY\\FROM\\STEP\\FIVE" "C:\\PATH\\TO\\MODEL.RVT\\IF\\APPLICABLE"
if __name__ == '__main__':
#get file path from command line
#run the command
os.system(command)
Step 7: Activate the scripts on the worker
The next step is to connect the VIKTOR app to the worker via a Generic Analysis, feel free to copy the example function below, into your VIKTOR app. Depending on the view you are using for your output, you may need to replace the output files with an output that can be processed by python or your chosen view.
from pathlib import Path
from io import BytesIO
def run_pyrevit(params):
command_path = Path(__file__).parent / "command.py"
command = File.from_path(command_path).getvalue_binary()
#If you added script.py to your arguments:
# instructions_path = Path(__file__).parent / "script.py"
# instructions = File.from_path(instructions_path).getvalue_binary()
files=[('input.py', BytesIO(command))
# If you are adding a model as input: ('model.rvt', BytesIO(params.model.file.getvalue_binary()))
# If you added script.py to your arguments: ('script.py', BytesIO(instructions))
]
generic_analysis = GenericAnalysis(files=files, executable_key="revit", output_filenames = ["output.pdf"])
generic_analysis.execute(timeout=600)
pdf_plans = generic_analysis.get_output_file("output.pdf", as_file=True)
return pdf_plans
You are now ready to build a GUI in the VIKTOR app and you can write your instructions for the worker in the 'script.py' file.
In this example, the script.py
will get some data, here in the form of a pdf, from the worker. For your application,
make sure to allign the output_filenames with the output of your script.py
instructions.
Usefull tips and tricks
Before setting up a worker on another machine, it is recommended to try it on your computer first. That way you will be able to test and debug your pyRevit code before it is placed on an external machine.
As you may have noticed, there are quite a few filepaths that need to be taken into account. There is definetly some bookkeeping required to make sure all goes well. The easiest way to keep track of the filepaths is to keep a note (possibly in your VIKTOR app) in which you can keep the filepaths of the worker.
The documentation for the Revit API is quite generic and may not seem to be for Python and you would be correct, it is for C#. However, the names and conventions are all the same in pyRevit and because the Revit API is well documented, you can use it just like any other API you would use for python. In the documentation, you can find out more and some examples to help you on your way.
Would you like to see an example?
VIKTOR offers a wide variety of sample repositories on GitHub, one of which is the pyRevit integration app. If you have a version of Revit installed on your computer, you can try out the proof-of-concept app to get an idea of how such an app works and behaves.
Testing
mock_GenericAnalysis
decorator for easier testing of GenericAnalysis
GenericAnalysis.execute
needs to be mocked within
the context of (automated) testing.
The viktor.testing
module provides the mock_GenericAnalysis
decorator that facilitate mocking of workers:
import unittest
from viktor import File
from viktor.testing import mock_GenericAnalysis
from app.my_entity_type.controller import MyEntityTypeController
class TestMyEntityTypeController(unittest.TestCase):
@mock_GenericAnalysis(get_output_file={
'result.xml': File.from_path('test_file.xml'), # <name>: <File>
'result.json': File.from_path('test_file.json'),
...
})
def test_generic_analysis(self):
MyEntityTypeController().generic_analysis()
For the decorator's input parameters the following holds:
- If a Sequence type is provided, the next entry is returned for each corresponding method call. When a call is performed on a depleted iterable, an Exception is raised.
- If a single object is provided, the object is returned each time the corresponding method is called (endlessly).
- If None is provided (default), a default File/BytesIO object (with empty content) is returned each time the corresponding method is called (endlessly).