use folder naming

This commit is contained in:
Jakub Trllo 2024-03-04 17:48:24 +01:00
parent 262cbda493
commit c3296b1322
11 changed files with 110 additions and 106 deletions

View file

@ -181,7 +181,7 @@ class Commands:
json.dump(env, file_stream, indent=4)
@staticmethod
def contextselection(output_path, project_name, asset_name, strict):
def contextselection(output_path, project_name, folder_path, strict):
from ayon_core.tools.context_dialog import main
main(output_path, project_name, asset_name, strict)
main(output_path, project_name, folder_path, strict)

View file

@ -161,13 +161,13 @@ class HostBase(object):
# Use current context to fill the context title
current_context = self.get_current_context()
project_name = current_context["project_name"]
asset_name = current_context["folder_path"]
folder_path = current_context["folder_path"]
task_name = current_context["task_name"]
items = []
if project_name:
items.append(project_name)
if asset_name:
items.append(asset_name.lstrip("/"))
if folder_path:
items.append(folder_path.lstrip("/"))
if task_name:
items.append(task_name)
if items:

View file

@ -109,7 +109,7 @@ class OpenPypeContextSelector:
if not self.context or \
not self.context.get("project") or \
not self.context.get("asset") or \
not self.context.get("folder") or \
not self.context.get("task"):
self._show_rr_warning("Context selection failed.")
return False
@ -137,7 +137,7 @@ class OpenPypeContextSelector:
def run_publish(self):
"""Run publish process."""
env = {"AYON_PROJECT_NAME": str(self.context.get("project")),
"AYON_FOLDER_PATH": str(self.context.get("asset")),
"AYON_FOLDER_PATH": str(self.context.get("folder")),
"AYON_TASK_NAME": str(self.context.get("task")),
# "AYON_APP_NAME": str(self.context.get("app_name"))
}
@ -184,7 +184,7 @@ selector = OpenPypeContextSelector()
# try to set context from environment
for key, env_keys in (
("project", ["AYON_PROJECT_NAME", "AVALON_PROJECT"]),
("asset", ["AYON_FOLDER_PATH", "AVALON_ASSET"]),
("folder", ["AYON_FOLDER_PATH", "AVALON_ASSET"]),
("task", ["AYON_TASK_NAME", "AVALON_TASK"]),
# ("app_name", ["AYON_APP_NAME", "AVALON_APP_NAME"])
):

View file

@ -24,14 +24,14 @@ class StartTimer(pyblish.api.ContextPlugin):
return
project_name = context.data["projectName"]
asset_name = context.data.get("folderPath")
folder_path = context.data.get("folderPath")
task_name = context.data.get("task")
if not project_name or not asset_name or not task_name:
if not project_name or not folder_path or not task_name:
self.log.info((
"Current context does not contain all"
" required information to start a timer."
))
return
timers_manager.start_timer_with_webserver(
project_name, asset_name, task_name, self.log
project_name, folder_path, task_name, self.log
)

View file

@ -45,7 +45,7 @@ class TimersManagerModuleRestApi:
data = await request.json()
try:
project_name = data["project_name"]
asset_name = data["folder_path"]
folder_path = data["folder_path"]
task_name = data["task_name"]
except KeyError:
msg = (
@ -57,7 +57,7 @@ class TimersManagerModuleRestApi:
self.module.stop_timers()
try:
self.module.start_timer(project_name, asset_name, task_name)
self.module.start_timer(project_name, folder_path, task_name)
except Exception as exc:
return Response(status=404, message=str(exc))
@ -70,9 +70,9 @@ class TimersManagerModuleRestApi:
async def get_task_time(self, request):
data = await request.json()
try:
project_name = data['project_name']
asset_name = data['folder_path']
task_name = data['task_name']
project_name = data["project_name"]
folder_path = data["folder_path"]
task_name = data["task_name"]
except KeyError:
message = (
"Payload must contain fields 'project_name, 'folder_path',"
@ -81,5 +81,5 @@ class TimersManagerModuleRestApi:
self.log.warning(message)
return Response(text=message, status=404)
time = self.module.get_task_time(project_name, asset_name, task_name)
time = self.module.get_task_time(project_name, folder_path, task_name)
return Response(text=json.dumps(time))

View file

@ -1,8 +1,8 @@
import os
import platform
import ayon_api
from ayon_core.client import get_asset_by_name
from ayon_core.addon import (
AYONAddon,
ITrayService,
@ -24,14 +24,18 @@ class ExampleTimersManagerConnector:
Required methods are 'stop_timer' and 'start_timer'.
# TODO pass asset document instead of `hierarchy`
Example of `data` that are passed during changing timer:
```
data = {
"project_name": project_name,
"folder_id": folder_id,
"folder_path": folder_entity["path"],
"task_name": task_name,
"task_type": task_type,
"hierarchy": hierarchy
# Deprecated
"asset_id": folder_id,
"asset_name": folder_entity["name"],
"hierarchy": hierarchy_items,
}
```
"""
@ -176,16 +180,14 @@ class TimersManager(
"""Convert string path to a timer data.
It is expected that first item is project name, last item is task name
and parent asset name is before task name.
and folder path in the middle.
"""
path_items = task_path.split("/")
if len(path_items) < 3:
raise InvalidContextError("Invalid path \"{}\"".format(task_path))
task_name = path_items.pop(-1)
asset_name = path_items.pop(-1)
project_name = path_items.pop(0)
folder_path = "/" + "/".join(path_items)
return self.get_timer_data_for_context(
project_name, asset_name, task_name, self.log
project_name, folder_path, task_name, self.log
)
def get_launch_hook_paths(self):
@ -204,40 +206,38 @@ class TimersManager(
@staticmethod
def get_timer_data_for_context(
project_name, asset_name, task_name, logger=None
project_name, folder_path, task_name, logger=None
):
"""Prepare data for timer related callbacks.
TODO:
- return predefined object that has access to asset document etc.
"""
if not project_name or not asset_name or not task_name:
"""Prepare data for timer related callbacks."""
if not project_name or not folder_path or not task_name:
raise InvalidContextError((
"Missing context information got"
" Project: \"{}\" Asset: \"{}\" Task: \"{}\""
).format(str(project_name), str(asset_name), str(task_name)))
" Project: \"{}\" Folder: \"{}\" Task: \"{}\""
).format(str(project_name), str(folder_path), str(task_name)))
asset_doc = get_asset_by_name(
folder_entity = ayon_api.get_folder_by_path(
project_name,
asset_name,
fields=["_id", "name", "data.tasks", "data.parents"]
folder_path,
fields={"id", "name", "path"}
)
if not asset_doc:
if not folder_entity:
raise InvalidContextError((
"Asset \"{}\" not found in project \"{}\""
).format(asset_name, project_name))
"Folder \"{}\" not found in project \"{}\""
).format(folder_path, project_name))
asset_data = asset_doc.get("data") or {}
asset_tasks = asset_data.get("tasks") or {}
if task_name not in asset_tasks:
folder_id = folder_entity["id"]
task_entity = ayon_api.get_task_by_name(
project_name, folder_id, task_name
)
if not task_entity:
raise InvalidContextError((
"Task \"{}\" not found on asset \"{}\" in project \"{}\""
).format(task_name, asset_name, project_name))
"Task \"{}\" not found on folder \"{}\" in project \"{}\""
).format(task_name, folder_path, project_name))
task_type = ""
try:
task_type = asset_tasks[task_name]["type"]
task_type = task_entity["taskType"]
except KeyError:
msg = "Couldn't find task_type for {}".format(task_name)
if logger is not None:
@ -245,32 +245,34 @@ class TimersManager(
else:
print(msg)
hierarchy_items = asset_data.get("parents") or []
hierarchy_items.append(asset_name)
hierarchy_items = folder_entity["path"].split("/")
hierarchy_items.pop(0)
return {
"project_name": project_name,
"asset_id": str(asset_doc["_id"]),
"asset_name": asset_name,
"folder_id": folder_id,
"folder_path": folder_entity["path"],
"task_name": task_name,
"task_type": task_type,
"hierarchy": hierarchy_items
"asset_id": folder_id,
"asset_name": folder_entity["name"],
"hierarchy": hierarchy_items,
}
def start_timer(self, project_name, asset_name, task_name):
def start_timer(self, project_name, folder_path, task_name):
"""Start timer for passed context.
Args:
project_name (str): Project name
asset_name (str): Asset name
task_name (str): Task name
project_name (str): Project name.
folder_path (str): Folder path.
task_name (str): Task name.
"""
data = self.get_timer_data_for_context(
project_name, asset_name, task_name, self.log
project_name, folder_path, task_name, self.log
)
self.timer_started(None, data)
def get_task_time(self, project_name, asset_name, task_name):
def get_task_time(self, project_name, folder_path, task_name):
"""Get total time for passed context.
TODO:
@ -281,7 +283,7 @@ class TimersManager(
if hasattr(connector, "get_task_time"):
module = self._modules_by_id[module_id]
times[module.name] = connector.get_task_time(
project_name, asset_name, task_name
project_name, folder_path, task_name
)
return times
@ -394,7 +396,7 @@ class TimersManager(
@staticmethod
def start_timer_with_webserver(
project_name, asset_name, task_name, logger=None
project_name, folder_path, task_name, logger=None
):
"""Prepared method for calling change timers on REST api.
@ -403,7 +405,7 @@ class TimersManager(
Args:
project_name (str): Project name.
asset_name (str): Asset name.
folder_path (str): Folder path.
task_name (str): Task name.
logger (logging.Logger): Logger object. Using 'print' if not
passed.
@ -430,7 +432,7 @@ class TimersManager(
return
data = {
"project_name": project_name,
"folder_path": asset_name,
"folder_path": folder_path,
"task_name": task_name
}
@ -472,13 +474,13 @@ class TimersManager(
def _on_host_task_change(self, event):
project_name = event["project_name"]
asset_name = event["folder_path"]
folder_path = event["folder_path"]
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))
" Project: {} Folder: {} Task: {}"
).format(project_name, folder_path, task_name))
self.start_timer_with_webserver(
project_name, asset_name, task_name, self.log
project_name, folder_path, task_name, self.log
)

View file

@ -280,13 +280,13 @@ class BaseAnatomy(object):
```
## Entered filepath
"P:/projects/project/asset/task/animation_v001.ma"
"P:/projects/project/folder/task/animation_v001.ma"
## Entered template
"<{}>"
## Output
"<AYON_PROJECT_ROOT_NAS>/project/asset/task/animation_v001.ma"
"<AYON_PROJECT_ROOT_NAS>/project/folder/task/animation_v001.ma"
Args:
filepath (str): Full file path where root should be replaced.

View file

@ -1603,12 +1603,12 @@ class CreateContext:
bool: Context changed.
"""
project_name, asset_name, task_name, workfile_path = (
project_name, folder_path, task_name, workfile_path = (
self._get_current_host_context()
)
return (
self._current_project_name != project_name
or self._current_folder_path != asset_name
or self._current_folder_path != folder_path
or self._current_task_name != task_name
or self._current_workfile_path != workfile_path
)
@ -1679,18 +1679,18 @@ class CreateContext:
self.refresh_thumbnails()
def _get_current_host_context(self):
project_name = asset_name = task_name = workfile_path = None
project_name = folder_path = task_name = workfile_path = None
if hasattr(self.host, "get_current_context"):
host_context = self.host.get_current_context()
if host_context:
project_name = host_context.get("project_name")
asset_name = host_context.get("folder_path")
folder_path = host_context.get("folder_path")
task_name = host_context.get("task_name")
if isinstance(self.host, IWorkfileHost):
workfile_path = self.host.get_current_workfile()
return project_name, asset_name, task_name, workfile_path
return project_name, folder_path, task_name, workfile_path
def reset_current_context(self):
"""Refresh current context.

View file

@ -81,15 +81,19 @@ class WebServerTool:
await client.connect()
context = get_global_context()
project = context["project_name"]
asset = context["folder_path"]
task = context["task_name"]
log.info("Sending context change to {}-{}-{}".format(project,
asset,
task))
project_name = context["project_name"]
folder_path = context["folder_path"]
task_name = context["task_name"]
log.info("Sending context change to {}{}/{}".format(
project_name, folder_path, task_name
))
await client.call('{}.set_context'.format(host),
project=project, asset=asset, task=task)
await client.call(
'{}.set_context'.format(host),
project=project_name,
folder=folder_path,
task=task_name
)
await client.close()
def port_occupied(self, host_name, port):

View file

@ -277,8 +277,8 @@ class ContextDialogController:
def is_initial_context_valid(self):
return self._initial_folder_found and self._initial_project_found
def set_initial_context(self, project_name=None, asset_name=None):
result = self._prepare_initial_context(project_name, asset_name)
def set_initial_context(self, project_name=None, folder_path=None):
result = self._prepare_initial_context(project_name, folder_path)
self._initial_project_name = project_name
self._initial_folder_id = result["folder_id"]
@ -352,7 +352,7 @@ class ContextDialogController:
with open(self._output_path, "w") as stream:
json.dump(self.get_selected_context(), stream, indent=4)
def _prepare_initial_context(self, project_name, asset_name):
def _prepare_initial_context(self, project_name, folder_path):
project_found = True
output = {
"project_found": project_found,
@ -362,26 +362,26 @@ class ContextDialogController:
"tasks_found": True,
}
if project_name is None:
asset_name = None
folder_path = None
else:
project = ayon_api.get_project(project_name)
project_found = project is not None
output["project_found"] = project_found
if not project_found or not asset_name:
if not project_found or not folder_path:
return output
output["folder_label"] = asset_name
output["folder_label"] = folder_path
folder_id = None
folder_found = False
# First try to find by path
folder = ayon_api.get_folder_by_path(project_name, asset_name)
folder = ayon_api.get_folder_by_path(project_name, folder_path)
# Try to find by name if folder was not found by path
# - prevent to query by name if 'asset_name' contains '/'
if not folder and "/" not in asset_name:
# - prevent to query by name if 'folder_path' contains '/'
if not folder and "/" not in folder_path:
folder = next(
ayon_api.get_folders(
project_name, folder_names=[asset_name], fields=["id"]),
project_name, folder_names=[folder_path], fields=["id"]),
None
)
@ -496,10 +496,10 @@ class ContextDialog(QtWidgets.QDialog):
Context has 3 parts:
- Project
- Asset
- Folder
- Task
It is possible to predefine project and asset. In that case their widgets
It is possible to predefine project and folder. In that case their widgets
will have passed preselected values and will be disabled.
"""
def __init__(self, controller=None, parent=None):
@ -521,7 +521,7 @@ class ContextDialog(QtWidgets.QDialog):
# UI initialization
main_splitter = QtWidgets.QSplitter(self)
# Left side widget contains project combobox and asset widget
# Left side widget contains project combobox and folders widget
left_side_widget = QtWidgets.QWidget(main_splitter)
project_combobox = ProjectsCombobox(
@ -531,7 +531,7 @@ class ContextDialog(QtWidgets.QDialog):
)
project_combobox.set_select_item_visible(True)
# Assets widget
# Folders widget
folders_widget = FoldersWidget(
controller,
parent=left_side_widget,
@ -661,11 +661,7 @@ class ContextDialog(QtWidgets.QDialog):
self._controller.set_strict(enabled)
def refresh(self):
"""Refresh all widget one by one.
When asset refresh is triggered we have to wait when is done so
this method continues with `_on_asset_widget_refresh_finished`.
"""
"""Refresh all widget one by one."""
self._controller.reset()
@ -673,10 +669,10 @@ class ContextDialog(QtWidgets.QDialog):
"""Result of dialog."""
return self._controller.get_selected_context()
def set_context(self, project_name=None, asset_name=None):
def set_context(self, project_name=None, folder_path=None):
"""Set context which will be used and locked in dialog."""
self._controller.set_initial_context(project_name, asset_name)
self._controller.set_initial_context(project_name, folder_path)
def _on_projects_refresh(self):
initial_context = self._controller.get_initial_context()
@ -784,14 +780,14 @@ class ContextDialog(QtWidgets.QDialog):
def main(
path_to_store,
project_name=None,
asset_name=None,
folder_path=None,
strict=True
):
# Run Qt application
app = get_ayon_qt_app()
controller = ContextDialogController()
controller.set_strict(strict)
controller.set_initial_context(project_name, asset_name)
controller.set_initial_context(project_name, folder_path)
controller.set_output_json_path(path_to_store)
window = ContextDialog(controller=controller)
window.show()

View file

@ -309,9 +309,11 @@ class ActionsModel:
task_name = None
task_type = None
if task_id is not None:
task = self._controller.get_task_entity(project_name, task_id)
task_name = task["name"]
task_type = task["taskType"]
task_entity = self._controller.get_task_entity(
project_name, task_id
)
task_name = task_entity["name"]
task_type = task_entity["taskType"]
output = should_start_last_workfile(
project_name,