Automation19 августа 20261553 слов

pyRevit: ставим и делаем свои кнопки за вечер

Установка pyRevit, структура расширения из папок, первый скрипт на Python и раздача кнопок команде через сетевую папку или git. С граблями по дороге и без C#.

pyRevit: ставим и делаем свои кнопки за вечер

Скриптов в Dynamo набралось два десятка. Половину запускают через Player, половину не запускают вообще, потому что искать их дольше, чем сделать руками. Хочется кнопку на ленте: нажал, отработало, поехали дальше.

pyRevit ровно про это. Бесплатный, открытый, ставится за 10 минут, кнопки делаются папками и файлами. Компилировать ничего не нужно, Visual Studio не нужен, C# не нужен. Вечера хватает на установку, три рабочие кнопки и раздачу их команде.

Установка

Идём на github.com/pyrevitlabs/pyRevit, в разделе Releases берём подписанный установщик последней стабильной версии ветки 4.8. Он поддерживает Revit с 2019 по 2025, включая нужные нам 2022, 2023 и 2024.

Ставится в две минуты. Установщик сам находит установленные Revit и подцепляется к ним. Открываем Revit: на ленте появилась вкладка pyRevit с полусотней готовых инструментов от сообщества. Уже ради них стоит поставить: там и поиск элементов по id, и сравнение моделей, и массовое переименование видов.

Что проверить сразу:

Ставить лучше «для текущего пользователя», без прав администратора. На машинах в организациях это обычно единственный способ поставить что-то самому.

Как устроено расширение

Вся структура интерфейса - это папки с говорящими окончаниями. Никакого 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, а не собирать граф.

Разбор по строчкам:

Запись в модель оборачивается в транзакцию:

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.

Чек-лист перед раздачей команде

Короткие ответы на частые вопросы

Сколько стоит 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 Оставить заявку