Skip to content

api

CommunicationWrapper

Source code in client/ayon_tvpaint/api/communication_server.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class CommunicationWrapper:
    # TODO add logs and exceptions
    communicator = None

    log = logging.getLogger("CommunicationWrapper")

    @classmethod
    def create_qt_communicator(cls, *args, **kwargs):
        """Create communicator for Artist usage."""
        communicator = QtCommunicator(*args, **kwargs)
        cls.set_communicator(communicator)
        return communicator

    @classmethod
    def set_communicator(cls, communicator):
        if not cls.communicator:
            cls.communicator = communicator
        else:
            cls.log.warning("Communicator was set multiple times.")

    @classmethod
    def client(cls):
        if not cls.communicator:
            return None
        return cls.communicator.client()

    @classmethod
    def execute_george(cls, george_script):
        """Execute passed goerge script in TVPaint."""
        if not cls.communicator:
            return
        return cls.communicator.execute_george(george_script)

create_qt_communicator(*args, **kwargs) classmethod

Create communicator for Artist usage.

Source code in client/ayon_tvpaint/api/communication_server.py
37
38
39
40
41
42
@classmethod
def create_qt_communicator(cls, *args, **kwargs):
    """Create communicator for Artist usage."""
    communicator = QtCommunicator(*args, **kwargs)
    cls.set_communicator(communicator)
    return communicator

execute_george(george_script) classmethod

Execute passed goerge script in TVPaint.

Source code in client/ayon_tvpaint/api/communication_server.py
57
58
59
60
61
62
@classmethod
def execute_george(cls, george_script):
    """Execute passed goerge script in TVPaint."""
    if not cls.communicator:
        return
    return cls.communicator.execute_george(george_script)

TVPaintHost

Bases: HostBase, IWorkfileHost, ILoadHost, IPublishHost

Source code in client/ayon_tvpaint/api/pipeline.py
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
class TVPaintHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
    name = "tvpaint"

    def install(self):
        """Install TVPaint-specific functionality."""

        log.info("AYON - Installing TVPaint integration")

        # Create workdir folder if does not exist yet
        workdir = os.getenv("AYON_WORKDIR")
        if not os.path.exists(workdir):
            os.makedirs(workdir)

        plugins_dir = os.path.join(TVPAINT_ROOT_DIR, "plugins")
        publish_dir = os.path.join(plugins_dir, "publish")
        load_dir = os.path.join(plugins_dir, "load")
        create_dir = os.path.join(plugins_dir, "create")

        pyblish.api.register_host("tvpaint")
        pyblish.api.register_plugin_path(publish_dir)
        register_loader_plugin_path(load_dir)
        register_creator_plugin_path(create_dir)

        register_event_callback("application.launched", self.initial_launch)
        register_event_callback("application.exit", self.application_exit)
        register_event_callback(
            "workfile.open.after",
            self._on_workfile_open_after
        )

    def get_current_project_name(self):
        """
        Returns:
            Union[str, None]: Current project name.
        """

        return self.get_current_context().get("project_name")

    def get_current_folder_path(self):
        """
        Returns:
            Union[str, None]: Current folder path.
        """

        return self.get_current_context().get("folder_path")

    def get_current_task_name(self):
        """
        Returns:
            Union[str, None]: Current task name.
        """

        return self.get_current_context().get("task_name")

    def get_current_context(self):
        context = get_current_workfile_context()
        if not context:
            return get_global_context()

        if "project_name" in context:
            if "asset_name" in context:
                context["folder_path"] = context["asset_name"]
            return context
        # This is legacy way how context was stored
        return {
            "project_name": context.get("project"),
            "folder_path": context.get("asset"),
            "task_name": context.get("task")
        }

    # --- Create ---
    def get_context_data(self):
        return get_workfile_metadata(SECTION_NAME_CREATE_CONTEXT, {})

    def update_context_data(self, data, changes):
        return write_workfile_metadata(SECTION_NAME_CREATE_CONTEXT, data)

    def list_instances(self):
        """List all created instances from current workfile."""
        return list_instances()

    def write_instances(self, data):
        return write_instances(data)

    # --- Workfile ---
    def open_workfile(self, filepath):
        george_script = "tv_LoadProject '\"'\"{}\"'\"'".format(
            filepath.replace("\\", "/")
        )
        return execute_george_through_file(george_script)

    def save_workfile(self, filepath=None):
        if not filepath:
            filepath = self.get_current_workfile()
        context = get_global_context()
        save_current_workfile_context(context)

        # Execute george script to save workfile.
        george_script = "tv_SaveProject {}".format(filepath.replace("\\", "/"))
        return execute_george(george_script)

    def work_root(self, session):
        return session["AYON_WORKDIR"]

    def get_current_workfile(self):
        # TVPaint returns a '\' character when no scene is currently opened
        current_workfile = execute_george("tv_GetProjectName")
        if current_workfile == '\\':
            return None
        return current_workfile

    def workfile_has_unsaved_changes(self):
        return None

    def get_workfile_extensions(self):
        return [".tvpp"]

    # --- Load ---
    def get_containers(self):
        return get_containers()

    def initial_launch(self):
        # Setup project context
        # - if was used e.g. template the context might be invalid.
        if not self.get_current_workfile():
            return

        log.info("Setting up context...")
        global_context = get_global_context()
        project_name = global_context.get("project_name")
        if not project_name:
            return

        save_current_workfile_context(global_context)
        # TODO fix 'set_context_settings'
        return

        folder_path = global_context.get("folder_path")
        task_name = global_context.get("task_name")

        if not folder_path:
            return

        folder_entity = ayon_api.get_folder_by_path(project_name, folder_path)
        if folder_entity and task_name:
            task_entity = ayon_api.get_task_by_name(
                project_name,
                folder_id=folder_entity["id"],
                task_name=task_name)
            context_entity = task_entity
        else:
            log.warning(
                "Falling back to setting context settings using folder entity "
                "because no task was found.")
            context_entity = folder_entity

        set_context_settings(context_entity)

    def application_exit(self):
        """Logic related to TimerManager.

        Todo:
            This should be handled out of TVPaint integration logic.
        """

        data = get_current_project_settings()
        stop_timer = data["tvpaint"]["stop_timer_on_application_exit"]

        if not stop_timer:
            return

        # Stop application timer.
        webserver_url = os.environ.get("AYON_WEBSERVER_URL")
        rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url)
        requests.post(rest_api_url)

    def _on_workfile_open_after(self):
        # Make sure opened workfile has stored correct context
        global_context = get_global_context()
        save_current_workfile_context(global_context)

application_exit()

Logic related to TimerManager.

Todo

This should be handled out of TVPaint integration logic.

Source code in client/ayon_tvpaint/api/pipeline.py
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
def application_exit(self):
    """Logic related to TimerManager.

    Todo:
        This should be handled out of TVPaint integration logic.
    """

    data = get_current_project_settings()
    stop_timer = data["tvpaint"]["stop_timer_on_application_exit"]

    if not stop_timer:
        return

    # Stop application timer.
    webserver_url = os.environ.get("AYON_WEBSERVER_URL")
    rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url)
    requests.post(rest_api_url)

get_current_folder_path()

Returns:

Type Description

Union[str, None]: Current folder path.

Source code in client/ayon_tvpaint/api/pipeline.py
100
101
102
103
104
105
106
def get_current_folder_path(self):
    """
    Returns:
        Union[str, None]: Current folder path.
    """

    return self.get_current_context().get("folder_path")

get_current_project_name()

Returns:

Type Description

Union[str, None]: Current project name.

Source code in client/ayon_tvpaint/api/pipeline.py
92
93
94
95
96
97
98
def get_current_project_name(self):
    """
    Returns:
        Union[str, None]: Current project name.
    """

    return self.get_current_context().get("project_name")

get_current_task_name()

Returns:

Type Description

Union[str, None]: Current task name.

Source code in client/ayon_tvpaint/api/pipeline.py
108
109
110
111
112
113
114
def get_current_task_name(self):
    """
    Returns:
        Union[str, None]: Current task name.
    """

    return self.get_current_context().get("task_name")

install()

Install TVPaint-specific functionality.

Source code in client/ayon_tvpaint/api/pipeline.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def install(self):
    """Install TVPaint-specific functionality."""

    log.info("AYON - Installing TVPaint integration")

    # Create workdir folder if does not exist yet
    workdir = os.getenv("AYON_WORKDIR")
    if not os.path.exists(workdir):
        os.makedirs(workdir)

    plugins_dir = os.path.join(TVPAINT_ROOT_DIR, "plugins")
    publish_dir = os.path.join(plugins_dir, "publish")
    load_dir = os.path.join(plugins_dir, "load")
    create_dir = os.path.join(plugins_dir, "create")

    pyblish.api.register_host("tvpaint")
    pyblish.api.register_plugin_path(publish_dir)
    register_loader_plugin_path(load_dir)
    register_creator_plugin_path(create_dir)

    register_event_callback("application.launched", self.initial_launch)
    register_event_callback("application.exit", self.application_exit)
    register_event_callback(
        "workfile.open.after",
        self._on_workfile_open_after
    )

list_instances()

List all created instances from current workfile.

Source code in client/ayon_tvpaint/api/pipeline.py
139
140
141
def list_instances(self):
    """List all created instances from current workfile."""
    return list_instances()