Skip to content
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

General: Lib code cleanup #5003

Merged
merged 7 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
6 changes: 4 additions & 2 deletions openpype/lib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# flake8: noqa E402
"""Pype module API."""
"""OpenPype lib functions."""
# add vendor to sys path based on Python version
import sys
import os
Expand Down Expand Up @@ -94,7 +94,8 @@
modules_from_path,
recursive_bases_from_class,
classes_from_module,
import_module_from_dirpath
import_module_from_dirpath,
is_func_signature_supported,
)

from .profiles_filtering import (
Expand Down Expand Up @@ -243,6 +244,7 @@
"recursive_bases_from_class",
"classes_from_module",
"import_module_from_dirpath",
"is_func_signature_supported",

"get_transcode_temp_directory",
"should_convert_for_ffmpeg",
Expand Down
43 changes: 5 additions & 38 deletions openpype/lib/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
import logging
import weakref
from uuid import uuid4
try:
from weakref import WeakMethod
except Exception:
from openpype.lib.python_2_comp import WeakMethod

from .python_2_comp import WeakMethod
from .python_module_tools import is_func_signature_supported


class MissingEventSystem(Exception):
Expand Down Expand Up @@ -80,40 +79,8 @@ def __init__(self, topic, func):

# Get expected arguments from function spec
# - positional arguments are always preferred
expect_args = False
expect_kwargs = False
fake_event = "fake"
if hasattr(inspect, "signature"):
# Python 3 using 'Signature' object where we try to bind arg
# or kwarg. Using signature is recommended approach based on
# documentation.
sig = inspect.signature(func)
try:
sig.bind(fake_event)
expect_args = True
except TypeError:
pass

try:
sig.bind(event=fake_event)
expect_kwargs = True
except TypeError:
pass

else:
# In Python 2 'signature' is not available so 'getcallargs' is used
# - 'getcallargs' is marked as deprecated since Python 3.0
try:
inspect.getcallargs(func, fake_event)
expect_args = True
except TypeError:
pass

try:
inspect.getcallargs(func, event=fake_event)
expect_kwargs = True
except TypeError:
pass
expect_args = is_func_signature_supported(func, "fake")
expect_kwargs = is_func_signature_supported(func, event="fake")

self._func_ref = func_ref
self._func_name = func_name
Expand Down
79 changes: 41 additions & 38 deletions openpype/lib/python_2_comp.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,44 @@
import weakref


class _weak_callable:
def __init__(self, obj, func):
self.im_self = obj
self.im_func = func

def __call__(self, *args, **kws):
if self.im_self is None:
return self.im_func(*args, **kws)
else:
return self.im_func(self.im_self, *args, **kws)


class WeakMethod:
""" Wraps a function or, more importantly, a bound method in
a way that allows a bound method's object to be GCed, while
providing the same interface as a normal weak reference. """

def __init__(self, fn):
try:
self._obj = weakref.ref(fn.im_self)
self._meth = fn.im_func
except AttributeError:
# It's not a bound method
self._obj = None
self._meth = fn

def __call__(self):
if self._dead():
return None
return _weak_callable(self._getobj(), self._meth)

def _dead(self):
return self._obj is not None and self._obj() is None

def _getobj(self):
if self._obj is None:
return None
return self._obj()
WeakMethod = getattr(weakref, "WeakMethod", None)

if WeakMethod is None:
class _WeakCallable:
def __init__(self, obj, func):
self.im_self = obj
self.im_func = func

def __call__(self, *args, **kws):
if self.im_self is None:
return self.im_func(*args, **kws)
else:
return self.im_func(self.im_self, *args, **kws)


class WeakMethod:
iLLiCiTiT marked this conversation as resolved.
Show resolved Hide resolved
""" Wraps a function or, more importantly, a bound method in
a way that allows a bound method's object to be GCed, while
providing the same interface as a normal weak reference. """

def __init__(self, fn):
try:
self._obj = weakref.ref(fn.im_self)
self._meth = fn.im_func
except AttributeError:
# It's not a bound method
self._obj = None
self._meth = fn

def __call__(self):
if self._dead():
return None
return _WeakCallable(self._getobj(), self._meth)

def _dead(self):
return self._obj is not None and self._obj() is None

def _getobj(self):
if self._obj is None:
return None
return self._obj()
67 changes: 67 additions & 0 deletions openpype/lib/python_module_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,70 @@ def import_module_from_dirpath(dirpath, folder_name, dst_module_name=None):
dirpath, folder_name, dst_module_name
)
return module


def is_func_signature_supported(func, *args, **kwargs):
"""Check if a function signature supports passed args and kwargs.

This check does not actually call the function, just look if function can
be called with the arguments.

Notes:
This does NOT check if the function would work with passed arguments
only if they can be passed in. If function have *args, **kwargs
in paramaters, this will always return 'True'.

Example:
>>> def my_function(my_number):
... return my_number + 1
...
>>> is_func_signature_supported(my_function, 1)
True
>>> is_func_signature_supported(my_function, 1, 2)
False
>>> is_func_signature_supported(my_function, my_number=1)
True
>>> is_func_signature_supported(my_function, number=1)
False
>>> is_func_signature_supported(my_function, "string")
True
>>> def my_other_function(*args, **kwargs):
... my_function(*args, **kwargs)
...
>>> is_func_signature_supported(
... my_other_function,
... "string",
... 1,
... other=None
... )
True

Args:
func (function): A function where the signature should be tested.
*args (tuple[Any]): Positional arguments for function signature.
**kwargs (dict[str, Any]): Keyword arguments for function signature.

Returns:
bool: Function can pass in arguments.
"""

if hasattr(inspect, "signature"):
# Python 3 using 'Signature' object where we try to bind arg
# or kwarg. Using signature is recommended approach based on
# documentation.
sig = inspect.signature(func)
try:
sig.bind(*args, **kwargs)
return True
except TypeError:
pass

else:
# In Python 2 'signature' is not available so 'getcallargs' is used
# - 'getcallargs' is marked as deprecated since Python 3.0
try:
inspect.getcallargs(func, *args, **kwargs)
return True
except TypeError:
pass
return False
34 changes: 18 additions & 16 deletions openpype/pipeline/publish/lib.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import os
import sys
import types
import inspect
import copy
import tempfile
import xml.etree.ElementTree

import six
import pyblish.util
import pyblish.plugin
import pyblish.api
Expand Down Expand Up @@ -42,7 +40,9 @@ def get_template_name_profiles(

Args:
project_name (str): Name of project where to look for templates.
project_settings(Dic[str, Any]): Prepared project settings.
project_settings (Dict[str, Any]): Prepared project settings.
logger (Optional[logging.Logger]): Logger object to be used instead
of default logger.

Returns:
List[Dict[str, Any]]: Publish template profiles.
Expand Down Expand Up @@ -103,7 +103,9 @@ def get_hero_template_name_profiles(

Args:
project_name (str): Name of project where to look for templates.
project_settings(Dic[str, Any]): Prepared project settings.
project_settings (Dict[str, Any]): Prepared project settings.
logger (Optional[logging.Logger]): Logger object to be used instead
of default logger.

Returns:
List[Dict[str, Any]]: Publish template profiles.
Expand Down Expand Up @@ -172,9 +174,10 @@ def get_publish_template_name(
project_name (str): Name of project where to look for settings.
host_name (str): Name of host integration.
family (str): Family for which should be found template.
task_name (str): Task name on which is intance working.
task_type (str): Task type on which is intance working.
project_setting (Dict[str, Any]): Prepared project settings.
task_name (str): Task name on which is instance working.
task_type (str): Task type on which is instance working.
project_settings (Dict[str, Any]): Prepared project settings.
hero (bool): Template is for hero version publishing.
logger (logging.Logger): Custom logger used for 'filter_profiles'
function.

Expand Down Expand Up @@ -264,19 +267,18 @@ def load_help_content_from_plugin(plugin):
def publish_plugins_discover(paths=None):
"""Find and return available pyblish plug-ins

Overridden function from `pyblish` module to be able collect crashed files
and reason of their crash.
Overridden function from `pyblish` module to be able to collect
crashed files and reason of their crash.

Arguments:
paths (list, optional): Paths to discover plug-ins from.
If no paths are provided, all paths are searched.

"""

# The only difference with `pyblish.api.discover`
result = DiscoverResult(pyblish.api.Plugin)

plugins = dict()
plugins = {}
plugin_names = []

allow_duplicates = pyblish.plugin.ALLOW_DUPLICATES
Expand All @@ -302,7 +304,7 @@ def publish_plugins_discover(paths=None):

mod_name, mod_ext = os.path.splitext(fname)

if not mod_ext == ".py":
if mod_ext != ".py":
continue

try:
Expand Down Expand Up @@ -525,10 +527,10 @@ def find_close_plugin(close_plugin_name, log):
def remote_publish(log, close_plugin_name=None, raise_error=False):
"""Loops through all plugins, logs to console. Used for tests.

Args:
log (openpype.lib.Logger)
close_plugin_name (str): name of plugin with responsibility to
close host app
Args:
log (Logger)
close_plugin_name (str): name of plugin with responsibility to
close host app
"""
# Error exit as soon as any error occurs.
error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}"
Expand Down
Loading