The TDI Library is already a game-changer since 2025 released and and the TDI docs are a wealth of knowledge but I have a serious stumbling block that would help with an authoritative technique and adds to the docs here.
Based on the import model of picking from sibling DATs then local/modules then modules in sys, referring between python files to get class definitions to build the Intellisense in VS Code is very difficult. Modules in the filesystem do not look up in the same priority as inside TD’s interpreter, and even using a tool like Embody which does save in the operator path, then building those import declarations is tricky and heavy in boilerplate.
Here are some common scenarios. If:
- I am referring to an Extension in the same Comp and they are both synced:
In the below case ComplexMultiTouchExt.py exists synced to ComplexMultiTouchExt the DAT, while CMT is the extension name defined on the parent COMP.
from ComplexMultiTouchExt import ComplexMultiTouchExt
def getExtension() -> ComplexMultiTouchExt:
return ext.CMT
In this case I am grabbing the file location (which is easiest with siblings) to patch types on a class found automagically by ext.
- I am referring to an extension in another folder/COMP path and they are both synced:
For this to work I have to block the inside-TD interpreter from saying “does not exist” because it doesn’t like the .. path referencing. Only when TYPE_CHECKING is true (in VS Code type hints) then navigate up the file hierarchy only to look for modules, but this ONLY works for types, never variables or classes because they would then be not imported once type checking is no longer true.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..UI_Table.UI1Ext import UI1Ext
from ..TangibleEngine.ComplexMultiTouchExt import ComplexMultiTouchExt
from ...Components.Metrics_Logger.MetricsLoggerExt import MetricsLoggerExt
...
# Use my class definitions but not for instancing, only method defs
_uiComp: UI1COMP = op.UI1 # type: ignore
_teComp: ComplexMultiTouchCOMP = op.TE # type: ignore
_metricsComp: MetricsCOMP = op.METRICS # type: ignore
In this case TD “finds” by Global shortcut, but Python linting finds by path to file. This is a huge block needed for even one import, never mind three.
- I am referring to a COMP which has elevated the UpperCase methods:
At the end of every extension script I add another class, undefined if running normally, which marries the operator class with the extension class. Of course this pollutes the joined class with all the lowercase as well but I can’t selectively promote without redeclaring them all here (haven’t tried that yet).
if TYPE_CHECKING:
class StateCOMP(baseCOMP, StateExt):
pass
This can then be imported in another file in the same way as before:
if TYPE_CHECKING:
from ..State.StateExt import StateCOMP
And go from there. Once again its not going to allow me to actually import or reuse any of these classes/methods/etc, just use them to describe an operator we find using op() or op. or parent. referencing.
- … and I haven’t figured out how to match up the local/modules approach yet with TDI typing.
So this is asking for trouble.
Pulling in a type by one location method then the actual object by another method is fragile. If I’m not saving these in identical positions between op path and name and file path and name, its going to break. There is obviously the class reuse limitations beyond siblings in the same COMP, and there is the general hunting for definitions already done in another script in the project as the approach for cross-module referencing is not documented.
So I’m here to ask if this is a skill issue, if there is a better way!
Can someone from Derivative share their approaches here, and what the “right way” for these would be? I turn on type checking and am still flooded by type errors that require loads of # type: ignore flags. I would like to consolidate some approaches/scenarios to both help my self and bolster out the docs which are already a good FAQ.
Cheers,
Chris