Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3357 from pypeclub/feature/OP-3420_Trigger-callba…
Browse files Browse the repository at this point in the history
…ck-on-workfile-open

Hosts: More options for in-host callbacks
  • Loading branch information
iLLiCiTiT authored Jun 20, 2022
2 parents 93960da + 48f966a commit c782c61
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 20 deletions.
8 changes: 7 additions & 1 deletion openpype/lib/avalon_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,8 +797,14 @@ def update_current_task(task=None, asset=None, app=None, template_key=None):
else:
os.environ[key] = value

data = changes.copy()
# Convert env keys to human readable keys
data["project_name"] = legacy_io.Session["AVALON_PROJECT"]
data["asset_name"] = legacy_io.Session["AVALON_ASSET"]
data["task_name"] = legacy_io.Session["AVALON_TASK"]

# Emit session change
emit_event("taskChanged", changes.copy())
emit_event("taskChanged", data)

return changes

Expand Down
19 changes: 19 additions & 0 deletions openpype/modules/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,25 @@ def modify_application_launch_arguments(self, application, env):

pass

def on_host_install(self, host, host_name, project_name):
"""Host was installed which gives option to handle in-host logic.
It is a good option to register in-host event callbacks which are
specific for the module. The module is kept in memory for rest of
the process.
Arguments may change in future. E.g. 'host_name' should be possible
to receive from 'host' object.
Args:
host (ModuleType): Access to installed/registered host object.
host_name (str): Name of host.
project_name (str): Project name which is main part of host
context.
"""

pass

def cli(self, module_click_group):
"""Add commands to click group.
Expand Down
18 changes: 18 additions & 0 deletions openpype/modules/timers_manager/timers_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
ITrayService,
ILaunchHookPaths
)
from openpype.lib.events import register_event_callback
from openpype.pipeline import AvalonMongoDB

from .exceptions import InvalidContextError
Expand Down Expand Up @@ -422,3 +423,20 @@ def start_timer_with_webserver(
}

return requests.post(rest_api_url, json=data)

def on_host_install(self, host, host_name, project_name):
self.log.debug("Installing task changed callback")
register_event_callback("taskChanged", self._on_host_task_change)

def _on_host_task_change(self, event):
project_name = event["project_name"]
asset_name = event["asset_name"]
task_name = event["task_name"]
self.log.debug((
"Sending message that timer should change to"
" Project: {} Asset: {} Task: {}"
).format(project_name, asset_name, task_name))

self.start_timer_with_webserver(
project_name, asset_name, task_name, self.log
)
40 changes: 30 additions & 10 deletions openpype/pipeline/context_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
from openpype.settings import get_project_settings
from openpype.lib import (
Anatomy,
register_event_callback,
filter_pyblish_plugins,
change_timer_to_current_context,
)

from . import (
Expand All @@ -33,6 +31,9 @@
_is_installed = False
_registered_root = {"_": ""}
_registered_host = {"_": None}
# Keep modules manager (and it's modules) in memory
# - that gives option to register modules' callbacks
_modules_manager = None

log = logging.getLogger(__name__)

Expand All @@ -44,6 +45,23 @@
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")


def _get_modules_manager():
"""Get or create modules manager for host installation.
This is not meant for public usage. Reason is to keep modules
in memory of process to be able trigger their event callbacks if they
need any.
Returns:
ModulesManager: Manager wrapping discovered modules.
"""

global _modules_manager
if _modules_manager is None:
_modules_manager = ModulesManager()
return _modules_manager


def register_root(path):
"""Register currently active root"""
log.info("Registering root: %s" % path)
Expand Down Expand Up @@ -74,6 +92,7 @@ def install_host(host):
_is_installed = True

legacy_io.install()
modules_manager = _get_modules_manager()

missing = list()
for key in ("AVALON_PROJECT", "AVALON_ASSET"):
Expand All @@ -95,8 +114,6 @@ def install_host(host):

register_host(host)

register_event_callback("taskChanged", _on_task_change)

def modified_emit(obj, record):
"""Method replacing `emit` in Pyblish's MessageHandler."""
record.msg = record.getMessage()
Expand All @@ -112,7 +129,14 @@ def modified_emit(obj, record):
else:
pyblish.api.register_target("local")

install_openpype_plugins()
project_name = os.environ.get("AVALON_PROJECT")
host_name = os.environ.get("AVALON_APP")

# Give option to handle host installation
for module in modules_manager.get_enabled_modules():
module.on_host_install(host, host_name, project_name)

install_openpype_plugins(project_name, host_name)


def install_openpype_plugins(project_name=None, host_name=None):
Expand All @@ -124,7 +148,7 @@ def install_openpype_plugins(project_name=None, host_name=None):
pyblish.api.register_discovery_filter(filter_pyblish_plugins)
register_loader_plugin_path(LOAD_PATH)

modules_manager = ModulesManager()
modules_manager = _get_modules_manager()
publish_plugin_dirs = modules_manager.collect_plugin_paths()["publish"]
for path in publish_plugin_dirs:
pyblish.api.register_plugin_path(path)
Expand Down Expand Up @@ -168,10 +192,6 @@ def install_openpype_plugins(project_name=None, host_name=None):
register_inventory_action(path)


def _on_task_change():
change_timer_to_current_context()


def uninstall_host():
"""Undo all of what `install()` did"""
host = registered_host()
Expand Down
61 changes: 52 additions & 9 deletions openpype/tools/workfiles/files_widget.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import logging
import shutil
import copy

import Qt
from Qt import QtWidgets, QtCore
Expand Down Expand Up @@ -90,14 +91,17 @@ def __init__(self, parent):
self._task_type = None

# Pype's anatomy object for current project
self.anatomy = Anatomy(legacy_io.Session["AVALON_PROJECT"])
project_name = legacy_io.Session["AVALON_PROJECT"]
self.anatomy = Anatomy(project_name)
self.project_name = project_name
# Template key used to get work template from anatomy templates
self.template_key = "work"

# This is not root but workfile directory
self._workfiles_root = None
self._workdir_path = None
self.host = registered_host()
self.host_name = os.environ["AVALON_APP"]

# Whether to automatically select the latest modified
# file on a refresh of the files model.
Expand Down Expand Up @@ -385,8 +389,9 @@ def _get_asset_doc(self):
return None

if self._asset_doc is None:
project_name = legacy_io.active_project()
self._asset_doc = get_asset_by_id(project_name, self._asset_id)
self._asset_doc = get_asset_by_id(
self.project_name, self._asset_id
)

return self._asset_doc

Expand All @@ -396,8 +401,8 @@ def _get_session(self):
session = legacy_io.Session.copy()
self.template_key = get_workfile_template_key(
self._task_type,
session["AVALON_APP"],
project_name=session["AVALON_PROJECT"]
self.host_name,
project_name=self.project_name
)
changes = compute_session_changes(
session,
Expand Down Expand Up @@ -430,6 +435,21 @@ def _enter_session(self):
template_key=self.template_key
)

def _get_event_context_data(self):
asset_id = None
asset_name = None
asset_doc = self._get_asset_doc()
if asset_doc:
asset_id = asset_doc["_id"]
asset_name = asset_doc["name"]
return {
"project_name": self.project_name,
"asset_id": asset_id,
"asset_name": asset_name,
"task_name": self._task_name,
"host_name": self.host_name
}

def open_file(self, filepath):
host = self.host
if host.has_unsaved_changes():
Expand All @@ -453,8 +473,21 @@ def open_file(self, filepath):
# Save current scene, continue to open file
host.save_file(current_file)

event_data_before = self._get_event_context_data()
event_data_before["filepath"] = filepath
event_data_after = copy.deepcopy(event_data_before)
emit_event(
"workfile.open.before",
event_data_before,
source="workfiles.tool"
)
self._enter_session()
host.open_file(filepath)
emit_event(
"workfile.open.after",
event_data_after,
source="workfiles.tool"
)
self.file_opened.emit()

def save_changes_prompt(self):
Expand Down Expand Up @@ -567,9 +600,14 @@ def _save_as_with_dialog(self):
src_path = self._get_selected_filepath()

# Trigger before save event
event_data_before = self._get_event_context_data()
event_data_before.update({
"filename": work_filename,
"workdir_path": self._workdir_path
})
emit_event(
"workfile.save.before",
{"filename": work_filename, "workdir_path": self._workdir_path},
event_data_before,
source="workfiles.tool"
)

Expand Down Expand Up @@ -602,15 +640,20 @@ def _save_as_with_dialog(self):
# Create extra folders
create_workdir_extra_folders(
self._workdir_path,
legacy_io.Session["AVALON_APP"],
self.host_name,
self._task_type,
self._task_name,
legacy_io.Session["AVALON_PROJECT"]
self.project_name
)
event_data_after = self._get_event_context_data()
event_data_after.update({
"filename": work_filename,
"workdir_path": self._workdir_path
})
# Trigger after save events
emit_event(
"workfile.save.after",
{"filename": work_filename, "workdir_path": self._workdir_path},
event_data_after,
source="workfiles.tool"
)

Expand Down

0 comments on commit c782c61

Please sign in to comment.