Skip to content

plugins

LoaderPlugin

Bases: list

Load representation into host application

Source code in client/ayon_core/pipeline/load/plugins.py
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 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
 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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
class LoaderPlugin(list):
    """Load representation into host application"""

    product_types = set()
    representations = set()
    extensions = {"*"}
    order = 0
    is_multiple_contexts_compatible = False
    enabled = True

    options = []

    log = logging.getLogger("ProductLoader")
    log.propagate = True

    @classmethod
    def apply_settings(cls, project_settings):
        host_name = os.environ.get("AYON_HOST_NAME")
        plugin_type = "load"
        plugin_type_settings = (
            project_settings
            .get(host_name, {})
            .get(plugin_type, {})
        )
        global_type_settings = (
            project_settings
            .get("core", {})
            .get(plugin_type, {})
        )
        if not global_type_settings and not plugin_type_settings:
            return

        plugin_name = cls.__name__

        plugin_settings = None
        # Look for plugin settings in host specific settings
        if plugin_name in plugin_type_settings:
            plugin_settings = plugin_type_settings[plugin_name]

        # Look for plugin settings in global settings
        elif plugin_name in global_type_settings:
            plugin_settings = global_type_settings[plugin_name]

        if not plugin_settings:
            return

        print(">>> We have preset for {}".format(plugin_name))
        for option, value in plugin_settings.items():
            if option == "enabled" and value is False:
                print("  - is disabled by preset")
            else:
                print("  - setting `{}`: `{}`".format(option, value))
            setattr(cls, option, value)

    @classmethod
    def has_valid_extension(cls, repre_entity):
        """Has representation document valid extension for loader.

        Args:
            repre_entity (dict[str, Any]): Representation entity.

        Returns:
             bool: Representation has valid extension
        """

        if "*" in cls.extensions:
            return True

        # Get representation main file extension from 'context'
        repre_context = repre_entity.get("context") or {}
        ext = repre_context.get("ext")
        if not ext:
            # Legacy way how to get extensions
            path = repre_entity.get("attrib", {}).get("path")
            if not path:
                cls.log.info(
                    "Representation doesn't have known source of extension"
                    " information."
                )
                return False

            cls.log.debug("Using legacy source of extension from path.")
            ext = os.path.splitext(path)[-1].lstrip(".")

        # If representation does not have extension then can't be valid
        if not ext:
            return False

        valid_extensions_low = {ext.lower() for ext in cls.extensions}
        return ext.lower() in valid_extensions_low

    @classmethod
    def is_compatible_loader(cls, context):
        """Return whether a loader is compatible with a context.

        On override make sure it is overridden as class or static method.

        This checks the product type and the representation for the given
        loader plugin.

        Args:
            context (dict[str, Any]): Documents of context for which should
                be loader used.

        Returns:
            bool: Is loader compatible for context.
        """

        plugin_repre_names = cls.get_representations()
        plugin_product_types = cls.product_types
        if (
            not plugin_repre_names
            or not plugin_product_types
            or not cls.extensions
        ):
            return False

        repre_entity = context.get("representation")
        if not repre_entity:
            return False

        plugin_repre_names = set(plugin_repre_names)
        if (
            "*" not in plugin_repre_names
            and repre_entity["name"] not in plugin_repre_names
        ):
            return False

        if not cls.has_valid_extension(repre_entity):
            return False

        plugin_product_types = set(plugin_product_types)
        if "*" in plugin_product_types:
            return True

        product_entity = context["product"]
        product_type = product_entity["productType"]

        return product_type in plugin_product_types

    @classmethod
    def get_representations(cls):
        """Representation names with which is plugin compatible.

        Empty set makes the plugin incompatible with any representation. To
            allow compatibility with all representations use '{"*"}'.

        Returns:
            set[str]: Names with which is plugin compatible.

        """
        return cls.representations

    @classmethod
    def filepath_from_context(cls, context):
        return get_representation_path_from_context(context)

    def load(self, context, name=None, namespace=None, options=None):
        """Load asset via database

        Arguments:
            context (dict): Full parenthood of representation to load
            name (str, optional): Use pre-defined name
            namespace (str, optional): Use pre-defined namespace
            options (dict, optional): Additional settings dictionary

        """
        raise NotImplementedError("Loader.load() must be "
                                  "implemented by subclass")

    def update(self, container, context):
        """Update `container` to `representation`

        Args:
            container (avalon-core:container-1.0): Container to update,
                from `host.ls()`.
            context (dict): Update the container to this representation.

        """
        raise NotImplementedError("Loader.update() must be "
                                  "implemented by subclass")

    def remove(self, container):
        """Remove a container

        Arguments:
            container (avalon-core:container-1.0): Container to remove,
                from `host.ls()`.

        Returns:
            bool: Whether the container was deleted

        """

        raise NotImplementedError("Loader.remove() must be "
                                  "implemented by subclass")

    @classmethod
    def get_options(cls, contexts):
        """
            Returns static (cls) options or could collect from 'contexts'.

            Args:
                contexts (list): of repre or product contexts
            Returns:
                (list)
        """
        return cls.options or []

    @property
    def fname(self):
        """Backwards compatibility with deprecation warning"""

        self.log.warning((
            "DEPRECATION WARNING: Source - Loader plugin {}."
            " The 'fname' property on the Loader plugin will be removed in"
            " future versions of OpenPype. Planned version to drop the support"
            " is 3.16.6 or 3.17.0."
        ).format(self.__class__.__name__))
        if hasattr(self, "_fname"):
            return self._fname

    @classmethod
    def get_representation_name_aliases(cls, representation_name: str):
        """Return representation names to which switching is allowed from
        the input representation name, like an alias replacement of the input
        `representation_name`.

        For example, to allow an automated switch on update from representation
        `ma` to `mb` or `abc`, then when `representation_name` is `ma` return:
            ["mb", "abc"]

        The order of the names in the returned representation names is
        important, because the first one existing under the new version will
        be chosen.

        Returns:
            List[str]: Representation names switching to is allowed on update
              if the input representation name is not found on the new version.
        """
        return []

fname property

Backwards compatibility with deprecation warning

get_options(contexts) classmethod

Returns static (cls) options or could collect from 'contexts'.

Parameters:

Name Type Description Default
contexts list

of repre or product contexts

required

Returns: (list)

Source code in client/ayon_core/pipeline/load/plugins.py
212
213
214
215
216
217
218
219
220
221
222
@classmethod
def get_options(cls, contexts):
    """
        Returns static (cls) options or could collect from 'contexts'.

        Args:
            contexts (list): of repre or product contexts
        Returns:
            (list)
    """
    return cls.options or []

get_representation_name_aliases(representation_name) classmethod

Return representation names to which switching is allowed from the input representation name, like an alias replacement of the input representation_name.

For example, to allow an automated switch on update from representation ma to mb or abc, then when representation_name is ma return: ["mb", "abc"]

The order of the names in the returned representation names is important, because the first one existing under the new version will be chosen.

Returns:

Type Description

List[str]: Representation names switching to is allowed on update if the input representation name is not found on the new version.

Source code in client/ayon_core/pipeline/load/plugins.py
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
@classmethod
def get_representation_name_aliases(cls, representation_name: str):
    """Return representation names to which switching is allowed from
    the input representation name, like an alias replacement of the input
    `representation_name`.

    For example, to allow an automated switch on update from representation
    `ma` to `mb` or `abc`, then when `representation_name` is `ma` return:
        ["mb", "abc"]

    The order of the names in the returned representation names is
    important, because the first one existing under the new version will
    be chosen.

    Returns:
        List[str]: Representation names switching to is allowed on update
          if the input representation name is not found on the new version.
    """
    return []

get_representations() classmethod

Representation names with which is plugin compatible.

Empty set makes the plugin incompatible with any representation. To allow compatibility with all representations use '{"*"}'.

Returns:

Type Description

set[str]: Names with which is plugin compatible.

Source code in client/ayon_core/pipeline/load/plugins.py
155
156
157
158
159
160
161
162
163
164
165
166
@classmethod
def get_representations(cls):
    """Representation names with which is plugin compatible.

    Empty set makes the plugin incompatible with any representation. To
        allow compatibility with all representations use '{"*"}'.

    Returns:
        set[str]: Names with which is plugin compatible.

    """
    return cls.representations

has_valid_extension(repre_entity) classmethod

Has representation document valid extension for loader.

Parameters:

Name Type Description Default
repre_entity dict[str, Any]

Representation entity.

required

Returns:

Name Type Description
bool

Representation has valid extension

Source code in client/ayon_core/pipeline/load/plugins.py
 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
@classmethod
def has_valid_extension(cls, repre_entity):
    """Has representation document valid extension for loader.

    Args:
        repre_entity (dict[str, Any]): Representation entity.

    Returns:
         bool: Representation has valid extension
    """

    if "*" in cls.extensions:
        return True

    # Get representation main file extension from 'context'
    repre_context = repre_entity.get("context") or {}
    ext = repre_context.get("ext")
    if not ext:
        # Legacy way how to get extensions
        path = repre_entity.get("attrib", {}).get("path")
        if not path:
            cls.log.info(
                "Representation doesn't have known source of extension"
                " information."
            )
            return False

        cls.log.debug("Using legacy source of extension from path.")
        ext = os.path.splitext(path)[-1].lstrip(".")

    # If representation does not have extension then can't be valid
    if not ext:
        return False

    valid_extensions_low = {ext.lower() for ext in cls.extensions}
    return ext.lower() in valid_extensions_low

is_compatible_loader(context) classmethod

Return whether a loader is compatible with a context.

On override make sure it is overridden as class or static method.

This checks the product type and the representation for the given loader plugin.

Parameters:

Name Type Description Default
context dict[str, Any]

Documents of context for which should be loader used.

required

Returns:

Name Type Description
bool

Is loader compatible for context.

Source code in client/ayon_core/pipeline/load/plugins.py
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
@classmethod
def is_compatible_loader(cls, context):
    """Return whether a loader is compatible with a context.

    On override make sure it is overridden as class or static method.

    This checks the product type and the representation for the given
    loader plugin.

    Args:
        context (dict[str, Any]): Documents of context for which should
            be loader used.

    Returns:
        bool: Is loader compatible for context.
    """

    plugin_repre_names = cls.get_representations()
    plugin_product_types = cls.product_types
    if (
        not plugin_repre_names
        or not plugin_product_types
        or not cls.extensions
    ):
        return False

    repre_entity = context.get("representation")
    if not repre_entity:
        return False

    plugin_repre_names = set(plugin_repre_names)
    if (
        "*" not in plugin_repre_names
        and repre_entity["name"] not in plugin_repre_names
    ):
        return False

    if not cls.has_valid_extension(repre_entity):
        return False

    plugin_product_types = set(plugin_product_types)
    if "*" in plugin_product_types:
        return True

    product_entity = context["product"]
    product_type = product_entity["productType"]

    return product_type in plugin_product_types

load(context, name=None, namespace=None, options=None)

Load asset via database

Parameters:

Name Type Description Default
context dict

Full parenthood of representation to load

required
name str

Use pre-defined name

None
namespace str

Use pre-defined namespace

None
options dict

Additional settings dictionary

None
Source code in client/ayon_core/pipeline/load/plugins.py
172
173
174
175
176
177
178
179
180
181
182
183
def load(self, context, name=None, namespace=None, options=None):
    """Load asset via database

    Arguments:
        context (dict): Full parenthood of representation to load
        name (str, optional): Use pre-defined name
        namespace (str, optional): Use pre-defined namespace
        options (dict, optional): Additional settings dictionary

    """
    raise NotImplementedError("Loader.load() must be "
                              "implemented by subclass")

remove(container)

Remove a container

Parameters:

Name Type Description Default
container avalon - core

container-1.0): Container to remove, from host.ls().

required

Returns:

Name Type Description
bool

Whether the container was deleted

Source code in client/ayon_core/pipeline/load/plugins.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
def remove(self, container):
    """Remove a container

    Arguments:
        container (avalon-core:container-1.0): Container to remove,
            from `host.ls()`.

    Returns:
        bool: Whether the container was deleted

    """

    raise NotImplementedError("Loader.remove() must be "
                              "implemented by subclass")

update(container, context)

Update container to representation

Parameters:

Name Type Description Default
container avalon - core

container-1.0): Container to update, from host.ls().

required
context dict

Update the container to this representation.

required
Source code in client/ayon_core/pipeline/load/plugins.py
185
186
187
188
189
190
191
192
193
194
195
def update(self, container, context):
    """Update `container` to `representation`

    Args:
        container (avalon-core:container-1.0): Container to update,
            from `host.ls()`.
        context (dict): Update the container to this representation.

    """
    raise NotImplementedError("Loader.update() must be "
                              "implemented by subclass")

ProductLoaderPlugin

Bases: LoaderPlugin

Load product into host application Arguments: context (dict): avalon-core:context-1.0 name (str, optional): Use pre-defined name namespace (str, optional): Use pre-defined namespace

Source code in client/ayon_core/pipeline/load/plugins.py
258
259
260
261
262
263
264
class ProductLoaderPlugin(LoaderPlugin):
    """Load product into host application
    Arguments:
        context (dict): avalon-core:context-1.0
        name (str, optional): Use pre-defined name
        namespace (str, optional): Use pre-defined namespace
    """