def match_rotation(source_transform=None, target_transform=None): """ Matches rotation of the source node to the rotation of the given target node(s) """ out_dict = {'success': False, 'result': list()} selection = dcc.selected_nodes_of_type(node_type='transform') source_transform = source_transform or selection[ 0] if python.index_exists_in_list(selection, 0) else None if not source_transform: out_dict[ 'msg'] = 'No source transform given to match against target rotation.' return out_dict target_transform = target_transform or selection[1:] if len( selection) > 1 else None if not source_transform: out_dict[ 'msg'] = 'No target transform(s) given to match source rotation against.' return out_dict source_transform = python.force_list(source_transform) target_transform = python.force_list(target_transform) percentage = 100.0 / len(source_transform) for i, source in enumerate(source_transform): library.Command.progressCommand.emit( percentage * (i + 1), 'Matching rotation: {}'.format(source)) try: maya.cmds.delete( maya.cmds.orientConstraint(target_transform, source, maintainOffset=False)) # For joints, we store now rotation data in jointOrient attribute if dcc.node_type(source) == 'joint': for axis in 'XYZ': joint_orient_attr = 'jointOrient{}'.format(axis) joint_rotation_attr = 'rotate{}'.format(axis) dcc.set_attribute_value(source, joint_orient_attr, 0.0) joint_rotation = dcc.get_attribute_value( source, joint_rotation_attr) dcc.set_attribute_value(source, joint_orient_attr, joint_rotation) dcc.set_attribute_value(source, joint_rotation_attr, 0.0) out_dict['result'].append(source) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to match node "{}" rotation to "{}" : {}'.format( source_transform, target_transform, exc) return out_dict matched_nodes = out_dict.get('result', None) if matched_nodes: dcc.select_node(matched_nodes) out_dict['success'] = True return out_dict
def set_names(nodes, names): """ Renames given list of nodes with the given list of names :param nodes: list(MObject) :param names: list(str) """ nodes = python.force_list(nodes) names = python.force_list(names) # TODO: Check why after calling this function, the undo does not allow to undo the renaming operation for node, node_name in zip(nodes, names): maya.api.OpenMaya.MFnDagNode(node).setName(node_name)
def mirror_object(self, obj): """ Returns the other/opposite side for teh given name (if exists); Otherwise None. :param obj: str :return: str or None """ left_sides = python.force_list(self.left_side()) right_sides = python.force_list(self.right_side()) for left_side, right_side in zip(left_sides, right_sides): obj = self.mirror_object_from_sides(obj, left_side, right_side) return obj
def detach_bind_skin(geo=None, show_options=False): out_dict = {'success': False, 'result': list()} geo_nodes = geo or dcc.selected_nodes_of_type(node_type='transform') geo_nodes = python.force_list(geo_nodes) valid_geo_nodes = list() for geo_node in geo_nodes: if not mesh_utils.is_a_mesh(geo_node): continue valid_geo_nodes.append(geo_node) if not valid_geo_nodes: out_dict['msg'] = 'No meshes to apply rigid bind skin into found.' return out_dict try: result = skin_utils.detach_bind_skin(geo=valid_geo_nodes, show_options=show_options) out_dict['result'].append(result) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to apply smooth bind skin: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def restore_to_bind_pose(skinned_mesh=None): out_dict = {'success': False, 'result': None} skinned_meshes = skinned_mesh or dcc.selected_nodes_of_type('transform') skinned_meshes = python.force_list(skinned_meshes) if not skinned_meshes: skinned_meshes = list() meshes = dcc.list_nodes(node_type='mesh') for mesh in meshes: skinned_meshes.append( maya.cmds.listRelatives(mesh, parent=True)[0]) if not skinned_meshes: out_dict['msg'] = 'No skinned meshes to restore bind poses of found.' return out_dict try: result = skin_utils.restore_to_bind_pose(skinned_mesh) out_dict['result'] = result except Exception as exc: out_dict[ 'msg'] = 'Was not possible to restore skinned mesh to bind pose: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def paint_background(image, background_color=None): """ Paints a background of the given color into the given QImage :param image: QImage :param background_color: tuple(r, g, b) :return: QImage, image with painted background """ if not background_color: background_color = [0, 0, 0] if type(background_color) not in (list, tuple) or len(background_color) != 3: LOGGER.warning( 'background_color argument is not valid ({}) using black color instead!' .format(background_color)) background_color = [0, 0, 0] background_color = python.force_list(background_color) for i in range(len(background_color)): if background_color[i] < 0 or background_color[i] > 255: LOGGER.warning( 'Background color channel ({})({}) out of limit (0, 255). Fixing to fit range ...' .format(i, background_color[i])) background_color[i] = min(max(background_color[i], 0), 255) image.fill(QColor(*background_color).rgb()) return image
def freeze_transforms(transforms=None): """ Freeze selected transforms """ out_dict = {'success': False, 'result': list()} transforms = python.force_list( transforms or dcc.selected_nodes_of_type(node_type='transform') or list()) if not transforms: out_dict[ 'msg'] = 'No transforms to freeze transforms of. Select at least one.' return out_dict percentage = 100.0 / len(transforms) for i, node in enumerate(transforms): library.Command.progressCommand.emit( percentage * (i + 1), 'Freezing transforms: {}'.format(node)) try: dcc.freeze_transforms(node) out_dict['result'].append(node) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to freeze transforms in node: "{}" : {}'.format( node, exc) return out_dict out_dict['success'] = True return out_dict
def _load_package_toolsets(self, package_name, tools_to_load): """ Loads all toolsets available in given package :param package_name: str :param tools_to_load: list """ if not tools_to_load: return tools_to_load = python.force_list(tools_to_load) paths_to_register = OrderedDict() tools_path = '{}.tools.{}' tools_paths_to_load = list() for tool_name in tools_to_load: pkg_path = tools_path.format(package_name, tool_name) pkg_loader = loader.find_loader(pkg_path) if not pkg_loader: LOGGER.debug('No loader found for "{}"'.format(tool_name)) continue if tool_name not in paths_to_register: paths_to_register[tool_name] = list() package_filename = pkg_loader.filename if python.is_python2( ) else os.path.dirname(pkg_loader.path) if package_filename not in tools_paths_to_load: tools_paths_to_load.append(package_filename) # Find where toolset widgets are located if tools_paths_to_load: self._manager.register_paths(tools_paths_to_load, package_name=package_name)
def set_icon_color(self, colors, update=True): if any(isinstance(el, list) for el in colors): self.iconColors = colors else: self.iconColors = [python.force_list(colors)] if update and self.idleIcon is not None and self.icon is not None: self.update_icons()
def create(base_geo, target_geo=None, origin='local', deform_order=None, name=None): """ Creates a blend shape deformer for the given base geometry :param base_geo: str, geometry to apply blend shape deformer to :param target_geo: list<str>, list of blend shape target models :param origin: BlendShapeOrigin, create a local or world space blendshape deformer :param deform_order: BlendShapeDeformerOrder, deform order :param name: str, blendshape node name :param target_weight: float, default target weight value :return: str """ if not maya.cmds.objExists(base_geo): raise Exception('Base geometry "{}" does not exists!'.format(base_geo)) if not name: name = '{}_blendShape'.format(base_geo.split(':')[-1]) if is_blendshape(name): LOGGER.debug('BlendShape {} already exists!'.format(name)) return name if deform_order == BlendShapeDeformerOrder.After: blend_shape = maya.cmds.blendShape(base_geo, name=name, origin=origin, after=True)[0] elif deform_order == BlendShapeDeformerOrder.Before: blend_shape = maya.cmds.blendShape(base_geo, name=name, origin=origin, before=True)[0] elif deform_order == BlendShapeDeformerOrder.Parallel: blend_shape = maya.cmds.blendShape(base_geo, name=name, origin=origin, parallel=True)[0] elif deform_order == BlendShapeDeformerOrder.Split: blend_shape = maya.cmds.blendShape(base_geo, name=name, origin=origin, split=True)[0] elif deform_order == BlendShapeDeformerOrder.Foc: blend_shape = maya.cmds.blendShape(base_geo, name=name, origin=origin, foc=True)[0] else: blend_shape = maya.cmds.blendShape(base_geo, name=name, origin=origin)[0] target_geo = python.force_list(target_geo) for target in target_geo: add_target(blend_shape=blend_shape, target=target, base=base_geo) return blend_shape
def create_hair_follicle(name=None, hair_system=None, uv=None): """ Creates a new hair follicle :param name: str, name of the follicle :param hair_system: str, name of the hair system we want to connect follicle into :param uv: list(float, flaot), follicle uvs :return: list(str, str), [follicle name, follicle shape name] """ name = 'follicle_{}'.format(name) if name else 'follicle' uv = python.force_list(uv) follicle_shape = maya.cmds.createNode('follicle') follicle = maya.cmds.listRelatives(follicle_shape, p=True) follicle = maya.cmds.rename(follicle, name_utils.find_unique_name(name)) follicle_shape = maya.cmds.listRelatives(follicle, shapes=True)[0] maya.cmds.setAttr('{}.startDirection'.format(follicle_shape), 1) maya.cmds.setAttr('{}.restPose'.format(follicle_shape), 1) maya.cmds.setAttr('{}.degree'.format(follicle_shape), 3) if uv: maya.cmds.setAttr('{}.parameterU'.format(follicle), uv[0]) maya.cmds.setAttr('{}.parameterV'.format(follicle), uv[1]) if hair_system: connect_follicle_to_hair_system(follicle, hair_system) maya.cmds.connectAttr('{}.outTranslate'.format(follicle_shape), '{}.translate'.format(follicle)) maya.cmds.connectAttr('{}.outRotate'.format(follicle_shape), '{}.rotate'.format(follicle))
def check_joint_labels(joints=None): out_dict = {'success': False, 'result': False} valid_joints = list() joints = joints or dcc.selected_nodes_of_type(node_type='joint') joints = python.force_list(joints) for joint in joints: if not dcc.object_type(joint) == 'joint': continue valid_joints.append(joint) if not valid_joints: out_dict['msg'] = 'No joints to check found.' return out_dict try: result = joint_utils.check_joint_labels(valid_joints) out_dict['result'] = result except Exception as exc: out_dict['msg'] = 'Was not possible to check joints label: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def create_joints_on_curve(curve=None, num_joints=1): out_dict = {'success': False, 'result': list()} valid_curves = list() curves = curve or dcc.selected_nodes_of_type(node_type='transform') curves = python.force_list(curves) for curve in curves: if not curve_utils.is_a_curve(curve): continue valid_curves.append(curve) if not valid_curves: out_dict['msg'] = 'No curves to create joints on found.' return out_dict try: for curve in valid_curves: new_joint = joint_utils.create_oriented_joints_along_curve( curve, num_joints) out_dict['result'].append(new_joint) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to create joints on curve: {}'.format( exc) return out_dict out_dict['success'] = True return out_dict
def insert_joints(joints=None, num_joints=1): """ Inserts new joints between selected joint and its direct child :param joints: int :param num_joints: int """ out_dict = {'success': False, 'result': None} joints = joints or dcc.selected_nodes_of_type(node_type='joint') joints = python.force_list(joints) if not joints: out_dict['msg'] = 'No joints to insert joints into found.' return out_dict try: result = joint_utils.insert_joints(joints=joints, joint_count=num_joints) out_dict['result'] = result except Exception as exc: out_dict['msg'] = 'Was not possible to insert joints: {}'.format(exc) return out_dict out_dict['success'] = True return out_dict
def set_rgb_color(node, rgb_list, linear=True, color_shapes=True): """ Sets the override RGB color of the given nodes NOTE: This function only works for versions of Maya greater than 2015 :param node: str or list(str) :param linear: bool, Whether or not the RGB should be set in linear space (matches viewport color) :param color_shapes: bool, Whether to apply color to the given node or its shapes :param rgb_list: list(float, float, float) """ from tpDcc.dccs.maya.core import shape if not linear: rgb_list = color.convert_color_linear_to_srgb(rgb_list) nodes = python.force_list(node) if color_shapes: nodes = shape.filter_shapes_in_list(nodes) if not nodes: return for node in nodes: if not maya.cmds.objExists('{}.overrideRGBColors'.format( node)) or not maya.cmds.objExists( '{}.overrideEnabled'.format(node)): continue maya.cmds.setAttr('{}.overrideRGBColors'.format(node), True) maya.cmds.setAttr('{}.overrideEnabled'.format(node), True) maya.cmds.setAttr('{}.overrideColorR'.format(node), rgb_list[0]) maya.cmds.setAttr('{}.overrideColorG'.format(node), rgb_list[1]) maya.cmds.setAttr('{}.overrideColorB'.format(node), rgb_list[2]) maya.cmds.setAttr('{}.overrideColorRGB'.format(node), rgb_list[0], rgb_list[1], rgb_list[2])
def find_side(cls, objects, regex_sides): """ Returns the naming convention for the given object names :param objects: list(str) :param regex_sides: str or list(str) :return: str """ if python.is_string(regex_sides): regex_sides = regex_sides.split('|') regex_sides = python.force_list(regex_sides) regex_sides = [re.compile(side) for side in regex_sides] for obj in objects: obj = obj.split('|')[-1].split(':')[-1] for regex_side in regex_sides: match = regex_side.search(obj) if match: side = match.group() if obj.startswith(side): side += '*' if obj.endswith(side): side = '*' + side return side return ''
def get_node_types(nodes, return_shape_type=True): """ Returns the Maya node type for the given nodes :param nodes: list<str>, list of nodes we want to check types of :param return_shape_type: bool, Whether to check shape type or not :return: dict<str>, [node_type_name], node dictionary of matching nodes """ from tpDcc.dccs.maya.core import shape nodes = python.force_list(nodes) found_type = dict() for n in nodes: node_type = maya.cmds.nodeType(n) if node_type == 'transform': if return_shape_type: shapes = shape.get_shapes(n) if shapes: node_type = maya.cmds.nodeType(shapes[0]) if node_type not in found_type: found_type[node_type] = list() found_type[node_type].append(n) return found_type
def get_types(self): """ Returns a list of types for the current asset :return: list(str) """ return python.force_list(self._get_attribute('types'))
def unlock_visibility(transforms=None): """ Locks visibility channel of the given transforms nodes """ out_dict = {'success': False, 'result': list()} transforms = python.force_list( transforms or dcc.selected_nodes_of_type(node_type='transform') or list()) if not transforms: out_dict[ 'msg'] = 'No transforms to unlock all scale channels of. Select at least one.' return out_dict percentage = 100.0 / len(transforms) for i, node in enumerate(transforms): library.Command.progressCommand.emit( percentage * (i + 1), 'Unlocking scale channels: {}'.format(node)) try: dcc.unlock_visibility_attribute(node) out_dict['result'].append(node) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to unlock visibility channel in node: "{}" : {}'.format( node, exc) return out_dict out_dict['success'] = True return out_dict
def renumber_objects(obj_names=None, remove_trailing_numbers=True, add_underscore=True, padding=2, rename_shape=True): """ Renumber a given object or list of objects remove_trailing_numbers=True, add_underscore=True, padding=2 == ['a1', 'b1'] -> ['a_01', 'b_02'] remove_trailing_numbers=True, add_unerscore=True, padding=3 == ['a1', 'b1'] -> ['a_001', 'b_002'] remove_trailing_numbers=True, add_unerscore=False, padding=1 == ['a1', 'b1'] -> ['a1', 'b2'] :param obj_names: list(str), list of Maya node names to renumber :param remove_trailing_numbers: bool, Whether to remove trailing numbers before doing the renumber :param add_underscore: bool, Whether or not to remove underscore between name and new number :param padding: int, amount of numerical padding (2=01, 3=001, etc). Only used if given names has no numbers. :param rename_shape: bool, Whether to rename shape nodes automatically to match transform nodes :return: list(str), list of new renumbered names """ obj_names = python.force_list(obj_names) if not obj_names: obj_names = maya.cmds.ls(sl=True, long=True) uuid_list = maya.cmds.ls(obj_names, uuid=True) for i, obj in enumerate(obj_names): if remove_trailing_numbers: obj = remove_numbers_from_object(obj, uuid=uuid_list[i], trailing_only=True) number_suffix = str(i + 1).zfill(padding) if add_underscore: number_suffix = '_{}'.format(number_suffix) new_name = ''.join([obj, number_suffix]) rename(obj, new_name, uuid=uuid_list[i], rename_shape=rename_shape) return maya.cmds.ls(uuid_list, long=True)
def is_settable(self, valid_connections=None): """ Returns True if the attribute can be set; False otherwise. :param valid_connections: list(str) or None """ valid_connections = python.force_list(valid_connections) if not self.exists(): return False if not dcc.list_attributes(self.fullname, unlocked=True, keyable=True, multi=True, scalar=True): return False connection = dcc.list_connections(self.name, self.attr, destination=False) if connection: connection_type = dcc.node_type(connection) for valid_type in valid_connections: if connection_type.startswith(valid_type): return True return False return True
def is_connected(self, ignore_connections=None): """ Returns True if the attribute is connected; False otherwise. :param ignore_connections: list(str) or None :return: bool """ ignore_connections = python.force_list(ignore_connections) try: connection = dcc.list_connections(self.name, self.attr, destination=False) except ValueError: return False if not connection: return False if ignore_connections: connection_type = dcc.node_type(connection) for ignore_type in ignore_connections: if connection_type.startswith(ignore_type): return False return True
def get_meshes_from_nodes(nodes, search_child_node=False, full_path=False, mesh=True, nurbs=False): """ Function that returns polygon meshes from given nodes :param nodes: list(str) :param search_child_node: bool :param full_path: bool :param mesh: bool :param nurbs: bool :return: list(str) """ nodes = python.force_list(nodes) polygon_meshes = list() if search_child_node: parent_nodes = nodes for n in parent_nodes: try: found_nodes = maya.cmds.listRelatives(n, ad=True, c=True, type='transform', fullPath=full_path, s=False) except Exception: pass if found_nodes is not None: nodes += found_nodes for n in nodes: if mesh: try: mesh_node = maya.cmds.listRelatives(n, s=True, pa=True, type='mesh', fullPath=True) if mesh_node: polygon_meshes.append(n) except Exception: pass if nurbs: try: nurbs_node = maya.cmds.listRelatives(s=True, pa=True, type='nurbsSurface', fullPath=True) if nurbs_node: polygon_meshes.append(nurbs_node) except Exception: pass if len(polygon_meshes) > 0: return polygon_meshes else: return list()
def _get_available_modules(self, paths=None): imports = list() if not paths: paths = sys.path if paths: paths = python.force_list(paths) for path in paths: fix_path = path_utils.normalize_path(path) stuff_in_folder = folder_utils.get_files_and_folders(fix_path) for file_or_folder in stuff_in_folder: folder_path = path_utils.join_path(fix_path, file_or_folder) files = folder_utils.get_files_with_extension('py', folder_path, full_path=False) if '__init__.py' in files: imports.append(str(file_or_folder)) python_files = folder_utils.get_files_with_extension( 'py', fix_path, full_path=False) for python_file in python_files: if python_file.startswith('__'): continue python_file_name = python_file.split('.')[0] imports.append(str(python_file_name)) if imports: imports = list(set(imports)) return imports
def rename_shapes(transform_node=None): """ Rename all shapes under the given transform to match the name of the transform :param transform_node: str, name of a transform """ renamed_shapes = list() transform_node = python.force_list(transform_node or dcc.selected_nodes()) for node in transform_node: node_shapes = list() short_name = name_utils.get_short_name(node) shapes = get_shapes(node) if shapes: node_shapes.append( maya.cmds.rename(shapes[0], '{}Shape'.format(short_name))) if len(shapes) > 1: i = 1 for s in shapes[1:]: node_shapes.append( maya.cmds.rename(s, '{}Shape{}'.format(short_name, i))) i += 1 renamed_shapes.append(node_shapes) return renamed_shapes
def move_pivot_to_zero(transforms=None): """ Moves selected nodes pivots to zero (0, 0, 0 in the world) """ out_dict = {'success': False, 'result': list()} transforms = python.force_list( transforms or dcc.selected_nodes_of_type(node_type='transform') or list()) if not transforms: out_dict[ 'msg'] = 'No transforms to move pivot to zero of. Select at least one.' return out_dict percentage = 100.0 / len(transforms) for i, node in enumerate(transforms): library.Command.progressCommand.emit( percentage * (i + 1), 'Moving pivot to zero: {}'.format(node)) try: dcc.move_pivot_to_zero(node) out_dict['result'].append(node) except Exception as exc: out_dict[ 'msg'] = 'Was not possible move pivot to zero for node: "{}" : {}'.format( node, exc) return out_dict out_dict['success'] = True return out_dict
def separate_meshes(meshes=None, new_mesh_name=None): """ Separates given meshes into one transform """ out_dict = {'success': False, 'result': None} meshes = meshes or dcc.selected_nodes_of_type(node_type='transform') meshes = python.force_list(meshes) if not meshes: out_dict['msg'] = 'No meshes to separate selected.' return out_dict new_mesh_name = new_mesh_name or dcc.node_short_name(meshes[0]) try: result_meshes = list() separated_meshes = dcc.separate_meshes(construction_history=False) if not separated_meshes: out_dict[ 'msg'] = 'Separate operation was done but not separated mesh was generated' return out_dict for separated_mesh in separated_meshes: separated_mesh = dcc.rename_node(separated_mesh, new_mesh_name) result_meshes.append(separated_mesh) out_dict['result'] = result_meshes except Exception as exc: out_dict[ 'msg'] = 'Was not possible to separate meshes "{}" : {}'.format( meshes, exc) return out_dict out_dict['success'] = True return out_dict
def match_scale(source_transform=None, target_transform=None): """ Matches scale of the source node to the scale of the given target node(s) """ out_dict = {'success': False, 'result': list()} selection = dcc.selected_nodes_of_type(node_type='transform') source_transform = source_transform or selection[ 0] if python.index_exists_in_list(selection, 0) else None if not source_transform: out_dict[ 'msg'] = 'No source transform given to match against target scale.' return out_dict target_transform = target_transform or selection[1:] if len( selection) > 1 else None if not source_transform: out_dict[ 'msg'] = 'No target transform(s) given to match source scale against.' return out_dict source_transform = python.force_list(source_transform) target_transform = python.force_list(target_transform) percentage = 100.0 / len(source_transform) for i, source in enumerate(source_transform): library.Command.progressCommand.emit( percentage * (i + 1), 'Matching scale: {}'.format(source)) try: maya.cmds.delete( maya.cmds.scaleConstraint(target_transform, source, maintainOffset=False)) out_dict['result'].append(source) except Exception as exc: out_dict[ 'msg'] = 'Was not possible to match node "{}" scale to "{}" : {}'.format( source_transform, target_transform, exc) return out_dict matched_nodes = out_dict.get('result', None) if matched_nodes: dcc.select_node(matched_nodes) out_dict['success'] = True return out_dict
def _on_import_alembic(self, as_reference=False): """ Internal callback function that is called when Import/Reference Alembic button is clicked :param as_reference: bool """ abc_file = self._alembic_path_line.text() if not abc_file or not os.path.isfile(abc_file): dcc.client().confirm_dialog( title='Error', message= 'No Alembic File is selected or file is not currently available in disk' ) return None abc_name = os.path.basename(abc_file).split('.')[0] tag_json_file = os.path.join( os.path.dirname(abc_file), os.path.basename(abc_file).replace('.abc', '_abc.info')) valid_tag_info = True if os.path.isfile(tag_json_file): with open(tag_json_file, 'r') as f: tag_info = json.loads(f.read()) if not tag_info: logger.warning('No Alembic Info loaded!') valid_tag_info = False else: logger.warning('No Alembic Info file found!') valid_tag_info = False if as_reference: reference_nodes = self._reference_alembic(alembic_file=abc_file, namespace=abc_name) else: reference_nodes = self._import_alembic( alembic_file=abc_file, valid_tag_info=valid_tag_info) reference_nodes = python.force_list(reference_nodes) added_tag = False for key in tag_info.keys(): if reference_nodes: for obj in reference_nodes: short_obj = dcc.client().node_short_name(obj) if key == short_obj: self._add_tag_info_data(self._project, tag_info[key], obj) added_tag = True if not added_tag: self._add_tag_info_data(self._project, tag_info, reference_nodes[0]) if reference_nodes: if as_reference: self.showOk.emit('Alembic file referenced successfully!') else: self.showOk.emit('Alembic file imported successfully!') return reference_nodes
def set_accepted_files(self, list_files): list_files = python.force_list(list_files) for f in list_files: if not f.startswith('.'): f = '.' + f self._accepted_files.append(f)