Skip to content

Pre and post loader hooks #1222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
04a2f08
Added new Pre and Post Loader Hooks
kalisp Apr 3, 2025
7ec99b3
Initial implementation of pre/post loader hooks
kalisp Apr 3, 2025
e76691e
Moved usage of hooks out of UI actions to utils
kalisp Apr 4, 2025
f10564f
Removed unnecessary functions
kalisp Apr 4, 2025
9260072
Extracted get_hook_loaders_by_identifier to utils
kalisp Apr 4, 2025
969358d
Removed missed unnecessary functions
kalisp Apr 4, 2025
42d8699
Fixed circular import
kalisp Apr 4, 2025
3961f8a
Added get_hook_loaders_by_identifier to pipeline API
kalisp Apr 4, 2025
a963f8c
Added get_hook_loaders_by_identifier SceneInventory controller
kalisp Apr 4, 2025
761ef4b
Added update methods for Loader Hooks
kalisp Apr 4, 2025
f44b81a
Pass hook_loaders_by_id in SceneInventory view
kalisp Apr 4, 2025
a5c1076
Added loader hooks to update_container
kalisp Apr 4, 2025
82ae29d
Lazy initialization of get_hook_loaders_by_identifier
kalisp Apr 4, 2025
f609d2f
Added switch methods to Loader Hooks
kalisp Apr 4, 2025
3a2d831
Added Loader Hooks to switch_container
kalisp Apr 4, 2025
0070edb
Updated docstrings
kalisp Apr 7, 2025
310174f
Fix calling hook
kalisp Apr 7, 2025
fd46d3e
Merge branch 'develop' into feature/AY-2218_Plugin-hooks-Loader-and-S…
kalisp Apr 7, 2025
a000277
Update naming
kalisp Apr 7, 2025
d11a8d2
Update naming
kalisp Apr 7, 2025
70cf7fe
Import annotations
kalisp Apr 7, 2025
44fc6f7
Typo
kalisp Apr 8, 2025
2fe9381
Added loaded container to Post process arguments
kalisp Apr 8, 2025
fb1879a
Updated names
kalisp Apr 8, 2025
1e5f544
Renamed loaders to more descriptive
kalisp Apr 8, 2025
7f8cc96
Merge remote-tracking branch 'origin/feature/AY-2218_Plugin-hooks-Loa…
kalisp Apr 8, 2025
1e2b7b9
Merge branch 'develop' of https://github.com/ynput/ayon-core into fea…
kalisp Apr 8, 2025
8c90fac
Fix renamed class names
kalisp Apr 8, 2025
4257344
Merge branch 'develop' into feature/AY-2218_Plugin-hooks-Loader-and-S…
antirotor Apr 14, 2025
5574ce0
Merge branch 'develop' into feature/AY-2218_Plugin-hooks-Loader-and-S…
kalisp Apr 23, 2025
2d4acc6
Merge branch 'develop' into feature/AY-2218_Plugin-hooks-Loader-and-S…
antirotor May 7, 2025
d5fc06c
Merge branch 'develop' into feature/AY-2218_Plugin-hooks-Loader-and-S…
antirotor May 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions client/ayon_core/pipeline/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@
register_loader_plugin_path,
deregister_loader_plugin,

register_loader_pre_hook_plugin,
deregister_loader_pre_hook_plugin,
register_loader_pre_hook_plugin_path,
deregister_loader_pre_hook_plugin_path,

register_loader_post_hook_plugin,
deregister_loader_post_hook_plugin,
register_loader_post_hook_plugin_path,
deregister_loader_post_hook_plugin_path,

load_container,
remove_container,
update_container,
Expand All @@ -51,6 +61,7 @@
get_representation_path,
get_representation_context,
get_repres_contexts,
get_hook_loaders_by_identifier
)

from .publish import (
Expand Down Expand Up @@ -160,6 +171,16 @@
"register_loader_plugin_path",
"deregister_loader_plugin",

"register_loader_pre_hook_plugin",
"deregister_loader_pre_hook_plugin",
"register_loader_pre_hook_plugin_path",
"deregister_loader_pre_hook_plugin_path",

"register_loader_post_hook_plugin",
"deregister_loader_post_hook_plugin",
"register_loader_post_hook_plugin_path",
"deregister_loader_post_hook_plugin_path",

"load_container",
"remove_container",
"update_container",
Expand Down Expand Up @@ -220,6 +241,8 @@
"register_workfile_build_plugin_path",
"deregister_workfile_build_plugin_path",

"get_hook_loaders_by_identifier",

# Backwards compatible function names
"install",
"uninstall",
Expand Down
22 changes: 22 additions & 0 deletions client/ayon_core/pipeline/load/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

get_loader_identifier,
get_loaders_by_name,
get_hook_loaders_by_identifier,

get_representation_path_from_context,
get_representation_path,
Expand All @@ -49,6 +50,16 @@
deregister_loader_plugin_path,
register_loader_plugin_path,
deregister_loader_plugin,

register_loader_pre_hook_plugin,
deregister_loader_pre_hook_plugin,
register_loader_pre_hook_plugin_path,
deregister_loader_pre_hook_plugin_path,

register_loader_post_hook_plugin,
deregister_loader_post_hook_plugin,
register_loader_post_hook_plugin_path,
deregister_loader_post_hook_plugin_path,
)


Expand Down Expand Up @@ -79,6 +90,7 @@

"get_loader_identifier",
"get_loaders_by_name",
"get_hook_loaders_by_identifier",

"get_representation_path_from_context",
"get_representation_path",
Expand All @@ -103,4 +115,14 @@
"deregister_loader_plugin_path",
"register_loader_plugin_path",
"deregister_loader_plugin",

"register_loader_pre_hook_plugin",
"deregister_loader_pre_hook_plugin",
"register_loader_pre_hook_plugin_path",
"deregister_loader_pre_hook_plugin_path",

"register_loader_post_hook_plugin",
"deregister_loader_post_hook_plugin",
"register_loader_post_hook_plugin_path",
"deregister_loader_post_hook_plugin_path",
)
79 changes: 79 additions & 0 deletions client/ayon_core/pipeline/load/plugins.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vote for using type hints in methods arguments and return values - since annotations from __future__ is imported. If you use mypy later on, it will really help.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations
import os
import logging
from typing import ClassVar

from ayon_core.settings import get_project_settings
from ayon_core.pipeline.plugin_discover import (
Expand Down Expand Up @@ -251,6 +253,51 @@ class ProductLoaderPlugin(LoaderPlugin):
"""


class PreLoaderHookPlugin:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it'd make more sense to make a single PrePostLoaderHookPlugin instead.

That way, one could make a Plugin that could act like a context manager by storing attributes on the plugin itself, e.g.

def pre_process(self):
    self.handle = do_whatever()

def post_process(self):
    cleanup(self.handle)

Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, how should the hooks behave if the loading failed? Should post hooks still trigger, or should those not?
Also, what should happen if a pre hook errors, should it continue loading, or should it stop?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats probably question of who is making pre/post hook. If they want to loading to fail/be skipped, they need to raise an exception.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with the error handling that it is up to the developer . Loader itself should be mostly decoupled from the logic in per-load hook (otherwiser you could put everytthing to the loader). Bur the context manager idea is interesting, maybe something for the future when we rewrite the loading API.

Copy link
Member

@iLLiCiTiT iLLiCiTiT May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we will really do this, then I agree with @BigRoy, we should have one hook being able to handle pre and post (less classes, less functions). And I think it should have is_compatible method instead of loader_identifiers and avoid the mapping by loader identifiers (which makes it even more complicated).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be also removed from pipeline.__init__ to make it "less visible" as this should be removed/made obsolete with impeding Loader API.

"""Plugin that should be run before any Loaders in 'loaders'

Should be used as non-invasive method to enrich core loading process.
Any external studio might want to modify loaded data before or after
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Any external studio might want to modify loaded data before or after
Any studio might want to modify loaded data before or after

I'd say almost everyone is "external studio" as there is no internal one 😜

they are loaded without need to override existing core plugins.
"""
loader_identifiers: ClassVar[set[str]]

def process(self, context, name=None, namespace=None, options=None):
pass

def update(self, container, context):
pass

def switch(self, container, context):
pass


class PostLoaderHookPlugin:
"""Plugin that should be run after any Loaders in 'loaders'

Should be used as non-invasive method to enrich core loading process.
Any external studio might want to modify loaded data before or after
they are loaded without need to override existing core plugins.
"""
loader_identifiers: ClassVar[set[str]]

def process(
self,
container,
context,
name=None,
namespace=None,
options=None
):
pass

def update(self, container, context):
pass

def switch(self, container, context):
pass


def discover_loader_plugins(project_name=None):
from ayon_core.lib import Logger
from ayon_core.pipeline import get_current_project_name
Expand Down Expand Up @@ -287,3 +334,35 @@ def deregister_loader_plugin_path(path):

def register_loader_plugin_path(path):
return register_plugin_path(LoaderPlugin, path)


def register_loader_pre_hook_plugin(plugin):
return register_plugin(PreLoaderHookPlugin, plugin)


def deregister_loader_pre_hook_plugin(plugin):
deregister_plugin(PreLoaderHookPlugin, plugin)


def register_loader_pre_hook_plugin_path(path):
return register_plugin_path(PreLoaderHookPlugin, path)


def deregister_loader_pre_hook_plugin_path(path):
deregister_plugin_path(PreLoaderHookPlugin, path)


def register_loader_post_hook_plugin(plugin):
return register_plugin(PostLoaderHookPlugin, plugin)


def deregister_loader_post_hook_plugin(plugin):
deregister_plugin(PostLoaderHookPlugin, plugin)


def register_loader_post_hook_plugin_path(path):
return register_plugin_path(PostLoaderHookPlugin, path)


def deregister_loader_post_hook_plugin_path(path):
deregister_plugin_path(PostLoaderHookPlugin, path)
Loading
Loading