Source code for nomenclator.utilities

# -*- coding: utf-8 -*-

import copy
import os

import nuke

from nomenclator.symbol import OUTPUT_CLASSES, DEFAULT_EXPRESSION
import nomenclator.template


[docs]def fetch_next_version(path, pattern, token_mapping): """Fetch next version from scene files saved in *path*. :param path: Path to fetch scene files from. :param pattern: Pattern to compare scene files with. :param token_mapping: Mapping regrouping resolved token values associated with their name. :return: version integer. """ next_version = 1 # Ignore version token when resolving base pattern mapping = copy.deepcopy(token_mapping) mapping["version"] = r"{version:\d+}" # Generate expected base name pattern from resolved tokens. pattern = nomenclator.template.resolve(pattern, mapping) for file_name in os.listdir(path): data = nomenclator.template.fetch_resolved_tokens( file_name, pattern, match_start=True, match_end=False ) if data is None: continue previous_version = int(data.get("version", 0)) next_version = max(next_version, previous_version + 1) return next_version
[docs]def fetch_version(scene_path, pattern, token_mapping): """Fetch version from scene path. :param scene_path: Path to the scene file to analyze. :param pattern: Pattern to compare scene file with. :param token_mapping: Mapping regrouping resolved token values associated with their name. :return: version integer, or None if no version is found. """ # Ignore version token when resolving base pattern mapping = copy.deepcopy(token_mapping) mapping["version"] = r"{version:\d+}" # Generate expected base name pattern from resolved tokens. pattern = nomenclator.template.resolve(pattern, mapping) data = nomenclator.template.fetch_resolved_tokens( os.path.basename(scene_path), pattern, match_start=True, match_end=False ) if data is not None: return int(data.get("version", 0)) or None
[docs]def fetch_template_config(path, template_configs, token_mapping): """Return template configuration compatible with *path*. Incoming token mapping will be mutated with new token values extracted from matching template configuration. :param path: Path to extract template configuration from. :param template_configs: List of available :class:`~nomenclator.config.TemplateConfig` instances :param token_mapping: Mapping regrouping resolved token values associated with their name. It will be updated with new token found. :return: :class:`~nomenclator.config.TemplateConfig` Instance or None. """ for config in template_configs: data = nomenclator.template.fetch_resolved_tokens( path, config.pattern_path, default_expression=config.default_expression, match_start=config.match_start, match_end=config.match_end, ) if data is not None: token_mapping.update(data) return config return None
[docs]def fetch_output_template_config(path, template_configs): """Return output template configuration compatible with *path*. Incoming token mapping will be mutated with new token values extracted from matching template configuration. :param path: Path to extract template configuration from. :param template_configs: List of available :class:`~nomenclator.config.OutputTemplateConfig` instances :return: :class:`~nomenclator.config.OutputTemplateConfig` Instance or None. """ for config in template_configs: levels = config.pattern_base.count(os.sep) _path = path.rsplit(os.sep, levels)[0] data = nomenclator.template.fetch_resolved_tokens( _path, config.pattern_path, default_expression=DEFAULT_EXPRESSION, match_start=True, match_end=True, ) if data is not None: return config return None
[docs]def fetch_nodes(): """Fetch all available output nodes in the graph with all node names. :return: tuple with a list of output nodes and a list all available node names. """ nodes = [] all_names = [] for node in nuke.allNodes(group=nuke.root()): if node.Class() in OUTPUT_CLASSES: nodes.append(node) all_names.append(node.name()) return nodes, all_names
[docs]def fetch_recent_comp_paths(max_values=10): """Return list of paths recently used to save a composition. :param max_values: Maximum number of recent composition paths to return :return: List of recent composition paths. """ paths = [] try: for index in range(1, max_values + 1): path = os.path.dirname(nuke.recentFile(index)) if path not in paths: paths.append(path) except RuntimeError: pass return tuple(paths)
[docs]def fetch_recent_project_paths(max_values=10): """Return list of paths recently used to save a project. :param max_values: Maximum number of recent composition paths to return :return: List of recent composition paths. """ import hiero.ui paths = [] action_name = "foundry.project.recentprojects" action = hiero.ui.findMenuAction(action_name) if action is not None: action_menu = action.menu() if action_menu is not None: items = action_menu.actions() for index, item in enumerate(items, 1): if index > max_values: break path = item.text() if not os.path.isfile(path): continue path = os.path.dirname(path) if path not in paths: paths.append(path) return tuple(paths)
[docs]def fetch_paddings(max_value=5): """Return all available paddings if notation requested. :param max_value: Maximum padding number to use. :return: List of available paddings. """ available = { "Hashes (#)": tuple([ "#" * (index + 1) for index in range(max_value) ]), "Printf Notation (%d)": tuple([ "%{0:02}d".format(index + 1) for index in range(max_value) ]) } try: preferences = nuke.toNode("preferences") notation = preferences["UISequenceDisplayMode"].value() return available[notation] except (TypeError, NameError, KeyError): return available["Hashes (#)"]
[docs]def fetch_current_comp_path(): """Return current composition path. :return: Path to current 'nk' file or empty string. """ try: return nuke.scriptName() except RuntimeError: return ""
[docs]def fetch_current_project_path(): """Return current project path. :return: Path to current 'hrox' file or empty string. """ import hiero.core projects = hiero.core.projects() if not len(projects): return "" return projects[-1].path()
[docs]def fetch_output_path(node): """Return output path from *node*. :param node: :class:`nuke.Node` instance. :return: Output path. """ return node["file"].value()
[docs]def fetch_colorspace(node, alias_mapping): """Return colorspace value from *node*. :param node: :class:`nuke.Node` instance. :param alias_mapping: Mapping containing alias to replace some values. :return: Colorspace value, or "none" if *node* does not have a 'colorspace' knob. """ knob = node.knob("colorspace") if knob is None: return "none" value = knob.value() return alias_mapping.get(value) or value
[docs]def fetch_file_type(node, default_value): """Return file type from *node*. :param node: :class:`nuke.Node` instance. :param default_value: Default value to return if no file type is set. :return: File type value. """ value = node["file_type"].value() return value.strip() or default_value
[docs]def fetch_file_types(node): """Return list of available file types for *node*. :param node: :class:`nuke.Node` instance. :return: Tuple containing all available file types. """ values = node["file_type"].values() # Strip spaces before and after each value. values = (value.strip() for value in values) # Keep only first part of value and exclude null values. values = (value.split()[0] for value in values if len(value)) return tuple(values)
[docs]def has_multiple_views(node): """Indicate whether *node* is configured with multiple views. :param node: :class:`nuke.Node` instance. :return: Boolean value. """ return len(node["views"].value().split()) > 1
[docs]def is_enabled(node): """Indicate whether *node* is enabled in the graph. :param node: :class:`nuke.Node` instance. :return: Boolean value. """ return not node["disable"].value()
[docs]def save_comp(context): """Save comp with path from *context*.""" try: nuke.scriptSaveAs(context.path) except RuntimeError: # thrown if operation is cancelled by user. return
[docs]def save_project(context): """Save project with path from *context*.""" import hiero.core project = hiero.core.newProject() try: project.saveAs(context.path) except RuntimeError: # thrown if operation is cancelled by user. return
[docs]def update_nodes(context): """Update nodes in graph from *context*.""" for _context in context.outputs: if not _context.enabled: continue node = nuke.toNode(str(_context.name)) node.setName(str(_context.new_name)) node["file"].setValue(str(_context.path)) node["file_type"].setValue(str(_context.file_type)) node["disable"].setValue(not _context.enabled) if context.create_subfolders: path = os.path.dirname(_context.path) if not os.path.isdir(path): os.makedirs(path)