Ошибки Python и модулей
Python сломался. Где искать ошибку без отладчика, почему маркер висит не на том DAT, что проверить при ModuleNotFoundError и какими командами TouchDesigner помогает разбираться.
Пошагового отладчика нет: это система реального времени, поэтому начинают
с Textport (Alt+T). Удобнее держать его панелью рядом с сетью, тип
Textport and DATs.
На DAT, который не компилируется, появляется красный значок, текст — по щелчку
или среднему клику. Ошибка при выполнении ставит маркер на DAT, откуда
выполнение началось, хотя случилась она, может, в другом модуле; вся
цепочка вызовов — в маркере и Textport. Все ошибки проекта — Dialogs → Errors с переходом к узлу или Error DAT таблицей и с колбэками,
а из Textport — op('/').errors(recurse=True) и
op('/').scriptErrors(recurse=True).
Импорт
ModuleNotFoundError. Пакет с двоичными частями собран под ту же версию
Python, что внутри TouchDesigner: 3.11 в ветке 2025.30000, 3.14
в экспериментальной 2026.20000. В Edit → Preferences → General включён
Add External Python to Search Path, путь в Python 64-bit Module Path,
несколько — через ;. Новые пути заработают после перезапуска. Проверка
изнутри:
import sys
for p in sys.path: print(p)
Окружения и TDPyEnvManager — Внешние модули и окружения.
Импорт прошёл, а потом всё падает — подменили встроенные numpy или OpenCV. Чужая их версия роняет TouchDesigner молча, иногда через час. Конфликтующее не подключают; если библиотека нужна, её выносят в отдельный процесс.
Молчит
| Симптом | Причина |
|---|---|
| Ничего и без ошибок | Колбэк не включён параметром или DAT выключен (Active) |
| Работал и перестал | Внутри было исключение — Textport и маркер |
| Сработал раз | Так и задумано, это не цикл |
| В редакторе да, в Perform нет | Узел считался благодаря вьюеру |
| Значение не обновляется | Выражение не зависит от меняющегося — Ссылки, выражения и экспорт |
На шоу колбэки оборачивают в try/except с записью в лог: колбэк, который молча
перестал работать, хуже громкой ошибки.
AttributeError: 'NoneType' object has no attribute ... — op('имя')
ничего не нашёл; относительный путь считается от оператора, где идёт код.
Код, который создаёт, удаляет или переподключает операторы прямо из кука
другого оператора (скажем, из колбэка Script-оператора), может упасть
с ошибкой — такое откладывают на кадр:
run("op('base1').create(nullTOP)", delayFrames=1)
Интерфейс застыл — главный поток занят сетевым запросом, большим файлом или моделью. В поток или в отдельный процесс — Отложенный запуск и потоки.
Инструменты
debug('ширина', w) # как print, но с именем DAT и строкой
print(project.pythonStack()) # кто нас вызвал
op('null1').errors() # ошибки узла
op('null1').warnings() # предупреждения
raise Exception('width = 0 в ' + parent().path) # стоп с понятным текстом
debug() всегда пишет, откуда вызван, и забытые отладочные строки находятся
сами. Если отладочных данных много, их пишут в Table DAT — они сохранятся вместе
с проектом. Время кусков скрипта — time.perf_counter(). Error DAT на служебной
панели показывает на площадке, что выдаёт ошибки,
Мониторинг.
Сборка, Python, пакеты, драйвер — записать. Через полгода при переустановке это сбережёт день.
Нашли в статье ошибку, устаревшее или непонятное место?