pyRevit: ставим и делаем свои кнопки за вечер
Установка pyRevit, структура расширения из папок, первый скрипт на Python и раздача кнопок команде через сетевую папку или git. С граблями по дороге и без C#.
Скриптов в Dynamo набралось два десятка. Половину запускают через Player, половину не запускают вообще, потому что искать их дольше, чем сделать руками. Хочется кнопку на ленте: нажал, отработало, поехали дальше.
pyRevit ровно про это. Бесплатный, открытый, ставится за 10 минут, кнопки делаются папками и файлами. Компилировать ничего не нужно, Visual Studio не нужен, C# не нужен. Вечера хватает на установку, три рабочие кнопки и раздачу их команде.
Установка
Идём на github.com/pyrevitlabs/pyRevit, в разделе Releases берём подписанный установщик последней стабильной версии ветки 4.8. Он поддерживает Revit с 2019 по 2025, включая нужные нам 2022, 2023 и 2024.
Ставится в две минуты. Установщик сам находит установленные Revit и подцепляется к ним. Открываем Revit: на ленте появилась вкладка pyRevit с полусотней готовых инструментов от сообщества. Уже ради них стоит поставить: там и поиск элементов по id, и сравнение моделей, и массовое переименование видов.
Что проверить сразу:
- вкладка не появилась - смотрите «Надстройки» в настройках Revit, надстройка могла быть заблокирована политикой безопасности;
- Revit LT в пролёте, у него нет API для надстроек, и это не лечится;
- корпоративный антивирус иногда съедает файлы расширений на сетевом диске, договоритесь об исключении заранее;
- после обновления Revit до новой версии установщик нужно прогнать снова, иначе кнопки не появятся.
Ставить лучше «для текущего пользователя», без прав администратора. На машинах в организациях это обычно единственный способ поставить что-то самому.
Как устроено расширение
Вся структура интерфейса - это папки с говорящими окончаниями. Никакого XML, никакой регистрации.
MyTools.extension\
Отдел.tab\
Проверки.panel\
Пустые номера.pushbutton\
script.py
icon.png
Дубли марок.pushbutton\
script.py
icon.png
Выгрузки.panel\
Ведомость дверей.pushbutton\
script.py
Читается так: расширение → вкладка на ленте → панель внутри вкладки → кнопка внутри панели. Имя папки становится подписью, script.py - тем, что выполнится по нажатию, icon.png - картинкой (png 96 на 96, прозрачный фон).
Кроме pushbutton есть pulldown (выпадающий список кнопок), splitbutton, stack (три мелкие кнопки в столбик), smartbutton. На первом вечере они не нужны.
Папку расширения кладём куда-нибудь, где её не снесёт: C:\pyRevitExt\ или сразу на сетевой диск. Дальше в Revit: вкладка pyRevit → Settings → Custom Extension Directories → добавляем путь. Reload, и ваша вкладка на ленте.
Первый скрипт
Классическая первая задача: найти помещения с пустым номером и показать их списком, по которому можно кликнуть.
# -*- coding: utf-8 -*-
__title__ = "Пустые\nномера"
__doc__ = "Показывает помещения без заполненного номера. Модель не меняет."
from pyrevit import revit, DB, script
doc = revit.doc
out = script.get_output()
rooms = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Rooms) \
.WhereElementIsNotElementType() \
.ToElements()
pustye = []
for r in rooms:
nomer = r.get_Parameter(DB.BuiltInParameter.ROOM_NUMBER).AsString()
if not nomer or not nomer.strip():
pustye.append(r)
out.print_md("## Помещений без номера: {}".format(len(pustye)))
for r in pustye:
imya = r.get_Parameter(DB.BuiltInParameter.ROOM_NAME).AsString()
out.print_md("- {} {}".format(imya, out.linkify(r.Id)))
Сохранили, нажали Reload на вкладке pyRevit, нажали свою кнопку. В окне вывода список помещений, и каждая строка кликабельна: клик выделяет элемент в модели. Это linkify, одна из вещей, ради которых стоит писать на pyRevit, а не собирать граф.
Разбор по строчкам:
__title__с\nпереносит подпись на две строки, иначе кнопка растянется на пол-панели;__doc__становится всплывающей подсказкой, туда пишите, меняет ли скрипт модель;revit.doc- текущий документ, не надо доставать его из uiapp вручную;FilteredElementCollector- штатный способ собрать элементы через Revit API, работает быстрее переборов;script.get_output()даёт окно с поддержкой markdown, таблиц и ссылок.
Запись в модель оборачивается в транзакцию:
with revit.Transaction("Заполнить номера"):
for r in pustye:
r.get_Parameter(DB.BuiltInParameter.ROOM_NUMBER).Set("б/н")
Забыли транзакцию - Revit выбросит исключение о запрете модификации вне транзакции. Открыли и не закрыли - получите повисшую транзакцию и «залипшую» модель. Конструкция with закрывает её сама, в том числе при ошибке.
Диалоги за две строки
Модуль forms закрывает всё, ради чего в Dynamo приходится изворачиваться.
from pyrevit import forms
variant = forms.SelectFromList.show(
["Все помещения", "Только активный вид"],
title="Что обрабатываем",
button_name="Поехали")
if not variant:
script.exit() # пользователь закрыл окно - выходим тихо
Есть готовые окна выбора уровней, видов, семейств, файлов, прогресс-бар и forms.alert с кнопками. На такое в Dynamo Player рассчитывать нельзя, там сценарий линейный.
Раздача команде
Два маршрута, выбирайте по размеру команды.
Сетевая папка. Кладёте MyTools.extension на \\server\BIM\pyrevit\, каждый добавляет путь в Settings. Пять минут на человека, обновления прилетают всем сразу при следующем Reload. Минус: Revit стартует медленнее, а при недоступной сети кнопки просто исчезают.
Git-репозиторий. pyRevit умеет подключать расширение как клон репозитория и обновлять его кнопкой Update. Правки катятся коммитами, история видна, откат в одну команду. Настраивается дольше, но на команде от пяти человек окупается за месяц.
| Сколько людей | Что выбрать | Почему |
|---|---|---|
| 1-3 | локальная папка | обновлять некого |
| 4-10 | сетевая папка | скорость важнее истории |
| 10+ | git-репозиторий | нужны версии и откат |
Отдельно про доверие. Первую кнопку команде давайте такую, которая ничего не меняет в модели: проверка, поиск, отчёт. Человек нажимает, видит пользу, ничем не рискует. После двух-трёх таких кнопок к пишущим относятся спокойно. В обратном порядке это не работает: одна испорченная модель, и к вашей вкладке больше не подойдут.
Грабли
IronPython против CPython. По умолчанию скрипты идут на IronPython 2.7. Кириллица в нём требует # -- coding: utf-8 -- в первой строке, иначе получите ошибку при первом же русском тексте. Нужен Python 3 с его библиотеками (requests, pandas) - первой строкой пишется #! python3, и скрипт исполняется другим движком. Смешивать их в одном расширении можно, но помнить надо.
Reload не всё подхватывает. Правки в script.py подхватываются сразу, а новые папки-кнопки и переименования - только после Reload. Иногда требуется перезапуск Revit.
Ошибка в скрипте роняет не Revit, а окно вывода. Это хорошая новость. Трейсбек показывается прямо в окне, с номером строки. Отладка идёт быстрее, чем в Dynamo, где ошибка прячется внутри жёлтой ноды.
Revit API не прощает версий. Метод, работавший в 2022, в 2024 может быть переименован или помечен устаревшим. Перед переходом на новую версию прогоните все свои кнопки на тестовой модели. У меня из восьми скриптов при переезде с 2021 на 2023 сломался один, и то из-за изменения в работе с единицами измерения.
Где pyRevit не подойдёт
Он не заменяет полноценный плагин на C#. Тяжёлые вычисления на десятках тысяч элементов на IronPython идут заметно медленнее. Своя оконная форма со сложным интерфейсом, лицензирование, продажа инструмента наружу - всё это территория обычной надстройки. Разница подробно разобрана в сравнении плагина и Dynamo.
Не подойдёт он и там, где IT-политика запрещает сторонние надстройки. Спорить бесполезно, лучше заранее показать службе безопасности открытый код и подписанный установщик.
И не ждите, что кнопки сами по себе поменяют процессы. Инструмент ускоряет то, что уже устроено разумно. Если в модели бардак с параметрами, кнопка будет быстро и красиво обрабатывать бардак.
Три трейсбека первого вечера
Окно вывода pyRevit показывает ошибку полностью, с номером строки. Это приятнее жёлтых нод Dynamo, но читать всё равно надо уметь.
«Autodesk.Revit.Exceptions.InvalidOperationException: Starting a transaction from an external application running outside of API context is not allowed.»
Длинно, а смысл простой: вы пытаетесь менять модель без транзакции. Оберните запись в with revit.Transaction("Название"):. Название попадёт в список отмены Revit, поэтому пишите его по-русски и понятно: пользователь увидит эту строку, когда нажмёт Ctrl+Z.
«SyntaxError: Non-ASCII character '\xd0' in file script.py on line 3, but no encoding declared.»
Привет от IronPython 2.7. Первой строкой файла ставится # -- coding: utf-8 --, и проблема исчезает. Сам файл при этом должен быть сохранён в UTF-8: Блокнот Windows любит записать в другой кодировке, и тогда кириллица в кнопках превращается в кашу. Пишите скрипты в VS Code, там кодировка видна в строке состояния.
«AttributeError: 'NoneType' object has no attribute 'AsString'.»
Параметра у элемента нет, LookupParameter вернул None, а вы сразу дёрнули метод. На разнородной выборке это происходит постоянно: у одного семейства параметр есть, у другого нет. Проверка на None перед обращением стоит одну строку и экономит вечер.
Отдельная история без всякого трейсбека: кнопка не появилась на ленте. Проверьте окончания папок (.extension, .tab, .panel, .pushbutton, точка обязательна), наличие script.py внутри и путь в Custom Extension Directories. Помогает нажатие Reload, иногда требуется перезапуск Revit.
Чек-лист перед раздачей команде
- Все кнопки прогнаны на трёх моделях разного размера, включая тяжёлую.
- В
__doc__каждой кнопки написано, меняет ли она модель. Это единственный текст, который пользователь прочитает, наведя курсор. - Иконки нарисованы. Кнопка без картинки выглядит сломанной, и её не нажимают.
- Скрипты, меняющие модель, лежат на отдельной панели, визуально отделённой от проверок.
- Проверено на чужой машине, а не только на вашей: пути, права на сетевую папку, версия Revit.
- Есть человек номер два, который знает, где лежит расширение и как его откатить.
- Расширение не грузится с диска, который отваливается при работе из дома через VPN.
Короткие ответы на частые вопросы
Сколько стоит pyRevit? Нисколько. Открытый исходный код, бесплатен и для коммерческой работы. Деньги в этой теме уходят только на ваше время и на разработку своих инструментов.
Что скажет служба безопасности? Обычно ничего, если прийти к ним заранее. Установщик подписан, код открыт и лежит на GitHub, расширения читаются с вашего же сетевого диска. Конфликт возникает там, где надстройку ставят молча, а потом её находит аудит.
Можно ли запускать Dynamo-графы кнопкой pyRevit? Технически можно через API Dynamo, но связка хрупкая и ломается при обновлениях. Проще переписать логику графа на python: то, что в Dynamo занимает 30 нод, обычно укладывается в 40 строк кода и работает быстрее.
Что будет при переходе на новую версию Revit? Прогоняете установщик заново, он подцепляет свежую версию. Дальше проверяете свои кнопки на тестовой модели: код на python версий не боится, а вот методы Revit API иногда меняются.
Dynamo теперь не нужен? Нужен. Геометрию и всё, что удобно смотреть глазами по шагам, быстрее собрать графом. pyRevit выигрывает на логике, интерфейсе и скорости запуска. В командах, где живут оба инструмента, графы обычно остаются у проектировщиков, а кнопки пишет один человек на весь отдел.
Что сделать сегодня
Поставьте pyRevit, создайте папку расширения с одной кнопкой-проверкой и скопируйте туда скрипт выше. Полчаса от нуля до работающей кнопки, из них 20 минут уйдёт на угадывание правильных имён папок.
Дальше по маршруту: если ещё не собирали графы, посмотрите разбор первого скрипта в Dynamo - логика та же, синтаксис проще. Хорошее содержимое для первых кнопок берётся из автозаполнения параметров и выгрузок в Excel. А про то, как вообще приживаются инструменты в команде, написано в статье про Dynamo Player.
Нужен набор кнопок под ваши регламенты, с проверками модели по вашему BIM-стандарту? Напишите в Telegram или через форму на странице контактов, обсудим объём. Что мы делаем на таких задачах, коротко в услугах.
Нужен похожий BIM/AI процесс?
Напишите в Telegram или на email — разберём задачу и предложим архитектуру решения.
Telegram Оставить заявку