Source code for bgdev.tools.toolbar.utils

"""Utility method used in the toolbar.

:created: 12/11/2018
:author: Benoit GIELLY <benoit.gielly@gmail.com>
"""
from collections import OrderedDict
import importlib
import logging
import os
import pkgutil
import sys

from PySide2 import QtCore
import yaml
import yaml.representer

from . import cfg

LOG = logging.getLogger(__name__)
PY_EXTS = (".py", ".pyc", ".pyo", ".pyw", ".so", ".dll")


[docs]def get_dcc_package(): """Get the current DCC's "check" package.""" modpath = modpath_from_file(__file__).rpartition(".")[0] module = "{}.tabs.{}.main".format(modpath, get_dcc()) return importlib.import_module(module)
[docs]def get_dcc(): """Get current DCC application.""" apps = {"maya": "maya", "houdini": "hou", "nuke": "nuke"} for dcc, module in apps.items(): if pkgutil.find_loader(module): return dcc return "system"
[docs]def modpath_from_file(filename): """Get the module import path from its filename. Args: filename (str): Path to python file. Raises: ImportError: When module cannot be found in sys.path. Returns: str: The module import path. """ filename = os.path.realpath(os.path.expanduser(filename)) base = os.path.splitext(filename)[0] for path in sys.path: path = os.path.realpath(os.path.expanduser(path)) path = os.path.normcase(os.path.abspath(path)) if path and os.path.normcase(base).startswith(path): modpath = [ pkg for pkg in base[len(path) :].split(os.sep) if pkg # noqa ] if check_modpath_has_init(path, modpath[:-1]): return ".".join(modpath) raise ImportError("Can't find module for {} in sys.path".format(filename))
[docs]def check_modpath_has_init(path, parts): """Check if given module parts all contains an __init__ file. Args: path (str): Path to python file. parts (list): Each parts of a module path. (Eg. ["sanity", "core"]). Returns: bool: True if each part as an __init__ file as sibling else False. """ modpath = [] for part in parts: modpath.append(part) path = os.path.join(path, part) if not _has_init(path): return False return True
def _has_init(directory): """Check if given directory contains an __init__ file. Args: directory (str): Path to directory. Returns: bool: True if given directory contains an __init__ file. """ module_or_pkg = os.path.join(directory, "__init__") for ext in PY_EXTS: if os.path.exists(module_or_pkg + ext): return True return False
[docs]def check_image(icon, normalized=True): """Convert the given image path to full path name. Args: icon (str): Name of the icon to check normalized (bool): Normalize the path to work on all OS Returns: str: Updated icon path so it's ready to be used. """ icon_paths = cfg.ICON_PATHS or [] # create a list of paths to lookup icons icon_folder = os.path.join(os.path.dirname(__file__), "icons") if icon_folder not in icon_paths: icon_paths.insert(0, icon_folder) # check for relatives path icons if icon.startswith(".."): for each in icon_paths: _icon = os.path.join(each, icon[3:]) if os.path.exists(_icon): icon = _icon break elif not os.path.isfile(icon): icon = ":/{0}".format(icon) # when icon file doesn't seem to exist if not QtCore.QFile.exists(icon): icon = "../default_icon.png" icon = os.path.abspath(os.path.join(icon_folder, icon[1:])) # normalize the path for windows icon = icon.replace(os.sep, "/") if normalized else icon return icon
[docs]def create_module_callback(source): """Set the command for each buttons. Args: source (str): Source python code to execute. Returns: function: A callable function """ if not source: return None # build a python function to keep it in an isolated scope _source = "".join(" " + line for line in source.splitlines(True)) command = "def _callback():\n{0}".format(_source) # execute the callback and extract the callable function from it exec(command) # pylint: disable=exec-used callback = locals()["_callback"] # add to shared variable cfg.COMMAND_CALLBACK = callback return callback
[docs]def yaml_load(path, ordered=False, **kwargs): """Import YAML file. Args: path (str): YAML file path to save data ordered (bool): Load data in an orderedDict when True. kwargs (dict): Any extra flags to pass in the :func:`json.load` command Returns: dict: the loaded data """ data = {} if ordered: data = OrderedDict() kwargs["Loader"] = Loader if not os.path.exists(path): LOG.warning("Path doesn't exists, returning empty dictionary.") return data with open(path) as stream: data = yaml.load(stream, **kwargs) return data
class Loader(yaml.Loader): """Custom YAML Loader to load data in an OrderedDict.""" def __init__(self, *args, **kwargs): super(Loader, self).__init__(*args, **kwargs) self.add_constructor( yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, self.dict_constructor, ) @staticmethod def dict_constructor(loader, node): """Create a custom constructor for yaml loader.""" return OrderedDict(loader.construct_pairs(node))
[docs]def yaml_dump(data, path, ordered=False, **kwargs): """Export YAML file. Args: data (dict): Dictionary to export as JSON path (str): YAML file path to save data ordered (bool): Dump data ordered when True. kwargs (dict): Any extra flags to pass in the :func:`json.dump` command Returns: str: given file path """ if ordered: kwargs["Dumper"] = Dumper with open(path, "w") as stream: yaml.dump(data, stream, **kwargs) return path
class Dumper(yaml.Dumper): """Custom YAML Dumper to dump data from an OrderedDict.""" def __init__(self, *args, **kwargs): super(Dumper, self).__init__(*args, **kwargs) rpz = yaml.representer.SafeRepresenter self.add_representer(OrderedDict, self.dict_representer) self.add_representer(str, rpz.represent_str) self.add_representer(unicode, rpz.represent_unicode) @staticmethod def dict_representer(dumper, data): """Create a custom representer for yaml dumper.""" return dumper.represent_dict(data.iteritems())