def get_folders(root_folder, recursive=False, full_path=False): """ Get folders found in the root folder :param root_folder: str, folder we ant to search folders on :param recursive: bool, Whether to search in all root folder child folders or not :return: list<str> """ from tpDcc.libs.python import path found_folders = list() if not recursive: try: found_folders = next(os.walk(root_folder))[1] except Exception: pass else: try: for root, dirs, files in os.walk(root_folder): for d in dirs: if full_path: folder_name = path.join_path(root, d) found_folders.append(folder_name) else: folder_name = path.join_path(root, d) folder_name = os.path.relpath(folder_name, root_folder) folder_name = path.clean_path(folder_name) found_folders.append(folder_name) except Exception: return found_folders return found_folders
def get_files(root_folder, full_path=False, recursive=False, pattern="*"): """ Returns files found in the given folder :param root_folder: str, folder we want to search files on :param full_path: bool, if true, full path to the files will be returned otherwise file names will be returned :return: list<str> """ from tpDcc.libs.python import path if not path.is_dir(root_folder): return [] # TODO: For now pattern only works in recursive searches. Fix it to work on both found = list() if recursive: for dir_path, dir_names, file_names in os.walk(root_folder): for file_name in fnmatch.filter(file_names, pattern): if full_path: found.append(path.join_path(dir_path, file_name)) else: found.append(file_name) else: files = os.listdir(root_folder) for f in files: file_path = path.join_path(root_folder, f) if path.is_file(file_path=file_path): if full_path: found.append(file_path) else: found.append(f) return found
def rename_file(name, directory, new_name, new_version=False): """ Renames the give nfile in the directory with a new name :param name: :param directory: :param new_name: :param new_version: :return: """ from tpDcc.libs.python import path full_path = path.join_path(directory, name) if not path.is_file(full_path): return full_path new_full_path = path.join_path(directory, new_name) if path.is_file(new_full_path): print('A file named {} already exists in the directory: {}'.format( new_name, directory)) return full_path os.chmod(full_path, 0o777) os.rename(full_path, new_full_path) return new_full_path
def _get_version_folder(self): if path.is_file(self._file_path): version_dir = path.get_dirname(self._file_path) version_path = path.join_path(version_dir, self._version_folder_name) else: version_path = path.join_path(self._file_path, self._version_folder_name) return version_path
def _get_version_folder(self): from tpDcc.libs.python import path if path.is_file(self.file_path): dir_name = path.get_dirname(self.file_path) version_path = path.join_path(dir_name, self._version_folder_name) else: version_path = path.join_path(self.file_path, self._version_folder_name) return version_path
def get_package_path_from_name(module_name, return_module_path=False): """ Returns package path from given package name :param module_name: str, name of the module we want to retrieve path of :param return_module_path: bool :return: str """ split_name = module_name.split('.') if len(split_name) > 1: sub_path = string.join(split_name[:-1], '/') else: sub_path = module_name paths = sys.path found_path = None for path in paths: test_path = path_utils.join_path(path, sub_path) if path_utils.is_dir(test_path): found_path = path if not found_path: return None test_path = found_path good_path = '' index = 0 for name in split_name: if index == len(split_name) - 1: if return_module_path: good_path = path_utils.join_path(good_path, '{}.py'.format(name)) break test_path = path_utils.join_path(test_path, name) if not path_utils.is_dir(test_path): continue files = fileio.get_files(test_path) if '__init__.py' in files: good_path = test_path else: return None index += 1 return good_path
def create_item(self, name=None): """ Creates a new item (folder) inside the selected item :param name: str, name of the new item """ current_item = self._current_item if current_item: item_path = self.get_tree_item_path_string(self._current_item) item_path = path.join_path(self._directory, item_path) if path.is_file(item_path): item_path = path.get_dirname(item_path) current_item = self._current_item.parent() if not current_item: item_path = self._directory if not name: name = self.NEW_ITEM_NAME folder.create_folder(name=name, directory=item_path) if current_item: self._add_sub_items(current_item) self.setItemExpanded(current_item, True) else: self.refresh()
def delete_folder(folder_name, directory=None): """ Deletes the folder by name in the given directory :param folder_name: str, name of the folder to delete :param directory: str, the directory path where the folder is stored :return: str, folder that was deleted with path """ from tpDcc.libs.python import path def delete_read_only_error(action, name, exc): """ Helper to delete read only files """ os.chmod(name, 0o777) action(name) full_path = folder_name if directory: full_path = path.join_path(directory, folder_name) if not path.is_dir(full_path): return None try: shutil.rmtree(full_path, onerror=delete_read_only_error) except Exception as exc: LOGGER.warning('Could not remove children of path "{}" | {}'.format( full_path, exc)) return full_path
def save_current_scene(force=True, **kwargs): """ Saves current scene :param force: bool """ path_to_save = kwargs.get('path_to_save', None) name_to_save = kwargs.get('name_to_save', None) extension_to_save = kwargs.get('extension_to_save', get_extensions()[0]) current_scene_name = rt.maxFileName if not extension_to_save.startswith('.'): extension_to_save = '.{}'.format(extension_to_save) name_to_save = name_to_save or current_scene_name if not name_to_save: return file_to_save = path_utils.join_path(path_to_save, name_to_save) if not file_to_save.endswith(extension_to_save): file_to_save = '{}{}'.format(file_to_save, extension_to_save) if force: return rt.saveMaxFile(file_to_save, quiet=True) else: file_check_state = rt.getSaveRequired() if not file_check_state: return rt.saveMaxFile(file_to_save) if rt.checkForSave(): return rt.saveMaxFile(file_to_save)
def get_projects(projects_path, project_class=None): """ Returns all projects located in given path :param projects_path: str :param project_class: cls :return: list(Project) """ if not project_class: project_class = Project projects_found = list() if not projects_path or not os.path.isdir(projects_path): LOGGER.warning('Projects Path {} is not valid!'.format(projects_path)) return projects_found for root, dirs, files in os.walk(projects_path): if consts.PROJECTS_NAME in files: new_project = project_class.create_project_from_data( path.join_path(root, consts.PROJECTS_NAME)) if new_project is not None: projects_found.append(new_project) return projects_found
def delete_file(name, directory=None, show_warning=True): """ Delete the file by name in the directory :param name: str, name of the file to delete :param directory: str, the directory where the file is stored :param show_warning: bool :return: str, file path that was deleted """ from tpDcc.libs.python import path, osplatform if not directory: full_path = name else: full_path = path.join_path(directory, name) if not path.is_file(full_path): if show_warning: print('File "{}" was not deleted.'.format(full_path)) return full_path try: osplatform.get_permission(full_path) except Exception: pass try: os.remove(full_path) except Exception: pass return full_path
def move(self, new_folder): if not new_folder or not os.path.isdir(new_folder): return identifier = self.format_identifier() file_directory, file_name, file_extension = path_utils.split_path( identifier) new_path = path_utils.join_path( new_folder, '{}{}'.format(file_name, file_extension)) valid = fileio.move_file(self.format_identifier(), new_path) if not valid: return dependencies = self.get_dependencies() self._db.move(identifier, new_path) skin_folder = dependencies.get('skin_folder', None) if not skin_folder or not os.path.isdir(skin_folder): return skin_folder_item = self.library.get(skin_folder) move_function = skin_folder_item.functionality().get('move') if move_function: move_function(new_folder) return new_folder
def rename_folder(directory, name, make_unique=False): """ Renames given with a new name :param directory: str, full path to the diretory we want to rename :param name: str, new name of the folder we want to rename :param make_unique: bool, Whether to add a number to the folder name to make it unique :return: str, path of the renamed folder """ from tpDcc.libs.python import path base_name = path.get_basename(directory=directory) if base_name == name: return parent_path = path.get_dirname(directory=directory) rename_path = path.join_path(parent_path, name) if make_unique: rename_path = path.unique_path_name(directory=rename_path) if path.is_dir(rename_path) or path.is_file(rename_path): return False try: os.chmod(directory, 0o777) message = 'rename: {0} >> {1}'.format(directory, rename_path) LOGGER.info(message) os.rename(directory, rename_path) except Exception: LOGGER.error('{}'.format(traceback.format_exc())) return False return rename_path
def load_python_module(module_name, directory): """ Loads a given module name located in the given directory NOTE: After loading a module you can access programmatically to all functions and attributes of the module :param module_name: str, name of the module we want to load :param directory: str, directory path where the module is located :return: mod, loaded module """ import imp from tpDcc.libs.python import path if not path.is_dir(directory): return None full_path = path.join_path(directory, module_name) if not path.is_file(full_path): return None split_name = module_name.split('.') file_path, path_name, description = imp.find_module( split_name[0], [directory]) try: module = imp.load_module(module_name, file_path, path_name, description) except Exception: file_path.close() return traceback.format_exc() finally: if file_path: file_path.close() return module
def show_save_widget(cls, item_class, library_window, item_view=None): """ Function used to show the create widget of the current item :param library_window: LibraryWindow :param item_view: LibraryItem or None """ path = library_window.selected_folder_path() or library_window.path() name, button = messagebox.MessageBox.input( library_window, 'Create Folder', 'Create a new folder with the name:') if not name or not button == QDialogButtonBox.Ok: return path = path_utils.join_path(path, name.strip()) item_data = item_class(path, library_window.library()) if not item_data: return save_function = item_data.functionality().get('save') if not save_function: return valid = save_function() if not valid: return if library_window: library_window.sync() library_window.refresh() library_window.select_folder_path(path)
def get_folders_without_dot_prefix(directory, recursive=False, base_directory=None): from tpDcc.libs.python import path, version if not path.exists(directory): return found_folders = list() base_directory = base_directory or directory folders = get_folders(directory) for folder in folders: if folder == 'version': version = version.VersionFile(directory) if version.updated_old: continue if folder.startswith('.'): continue folder_path = path.join_path(directory, folder) folder_name = path.clean_path(os.path.relpath(folder_path, base_directory)) found_folders.append(folder_name) if recursive: sub_folders = get_folders_without_dot_prefix( folder_path, recursive=recursive, base_directory=base_directory) found_folders += sub_folders return found_folders
def import_python_module(module_name, directory): """ Imports the given module :param module_name: str, name of the module :param directory: str, path where the module is located :return: mod, imported module """ from tpDcc.libs.python import path, fileio if not path.is_dir(directory=directory): return module = None full_path = path.join_path(directory, module_name) if path.is_file(full_path): if directory not in sys.path: sys.path.append(directory) split_name = module_name.split('.') script_name = split_name[0] exec('import {}'.format(script_name)) exec('reload({})'.format(script_name)) module = eval(script_name) sys.path.remove(directory) return module
def get_scene_name_and_path(): """ Returns the name and path of the current open 3ds Max scene including the extension (.max) :return: str """ return path_utils.join_path(rt.maxFilePath, rt.maxFileName)
def dropEvent(self, event): item = self.item_at(event.pos()) if item: item_path = self.get_tree_item_path_string(item) item_full_path = path.join_path(self._directory, item_path) if item_full_path and path.is_dir(item_full_path): super(FileTreeWidget, self).dropEvent(event)
def _on_sub_path_filter_edited(self): """ Internal callback function that is called when sub path filter text is edited """ current_text = str(self._sub_path_filter.text()).strip() if not current_text: self.set_directory(self._directory) if self._update_tree: self._tree_widget.set_directory(self._directory) text = self._filter_names.text self._on_filter_names(text) return sub_dir = path.join_path(self._directory, current_text) if not sub_dir: return if path.is_dir(sub_dir): if self._update_tree: self._tree_widget.set_directory(self._directory) text = self._filter_names.text self._on_filter_names(text) if self._emit_changes: self.subPathChanged.emit(current_text)
def create_file(filename, directory=None, make_unique=False): """ Creates a file :param filename: str, name of the new file :param directory: str, directory of the new file :param make_unique: bool, whether to make the name unique or not :return: variant, str || bool, filename with path or False if create file failed """ from tpDcc.libs.python import name, path, osplatform if directory is None: directory = path.get_dirname(filename) filename = path.get_basename(filename) filename = name.clean_file_string(filename) full_path = path.join_path(directory, filename) if make_unique: full_path = path.unique_path_name(full_path) open_file = None try: open_file = open(full_path, 'a') open_file.close() except Exception: if open_file: open_file.close() return False osplatform.get_permission(full_path) return full_path
def get_project_file(self): """ Returns path where project file is located :return: str """ return path.join_path(self.full_path, consts.PROJECTS_NAME)
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 create_folder(self, name, relative_path=None): if relative_path is None: folder.create_folder(name=name, directory=self.full_path) else: folder.create_folder(name=name, directory=path.join_path( self.full_path, relative_path))
def _import_mesh_obj(self, data_path): """ Internal function that imports mesh object stored in given path :param data_path: str, path that contains already exported mesh object :return: str, name of the imported mesh """ dependencies = self.get_dependencies(data_path) mesh_path = dependencies.get('geo_file', None) if not mesh_path or not os.path.isfile(mesh_path): mesh_path = path_utils.join_path(data_path, 'mesh.obj') if not path_utils.is_file(mesh_path): return None nodes = dcc.client().list_nodes(node_type='mesh', full_path=False) dcc.client().import_file(mesh_path, import_type='OBJ', ignore_version=True, options='mo=1') current_nodes = dcc.client().list_nodes(node_type='mesh', full_path=False) delta = list(set(current_nodes).difference(nodes)) if delta: delta = dcc.client().node_parent(delta, full_path=True) return delta
def _get_comment_path(self): version_folder = self._get_version_folder() comment_path = None if version_folder: comment_path = path.join_path(version_folder, 'comments.txt') return comment_path
def get_comments(comment_directory, comment_filename=None): """ Returns all the comments from a comments.txt file :param comment_directory: str, directory where comment.txt file is located :param comment_filename: str, name of the c omment file. By default, comment.txt. :return: dict(filename, value), (comment, user) """ comment_filename = comment_filename or 'comments.json' comment_file = path.join_path(comment_directory, comment_filename) if not comment_file or not os.path.isfile(comment_file): return comments = dict() comments_data = jsonio.read_file(comment_file) if not comments_data: return comments for version_dict in comments_data: file_name = version_dict.get('version', None) comment = version_dict.get('comment', '') user = version_dict.get('user', '') if comment_filename and comment_filename == file_name: return comment, comments[file_name] = [comment, user] return comments
def _get_influences(self, folder_path): """ Internal function that returns a dictionary containing influences data from influence files contained in the given directory :param folder_path: str, path that contains influence file :return: dict, influence data """ influence_dict = dict() files = fileio.get_files(folder_path) dependencies = self.get_dependencies(folder_path) or dict() info_file = dependencies.get('info_file', None) if not info_file or not os.path.isfile(info_file): if not files: return influence_dict info_file = path_utils.join_path(folder_path, 'influence.info') if not path_utils.is_file(info_file): return influence_dict info_lines = fileio.get_file_lines(info_file) for line in info_lines: if not line: continue line_dict = eval(line) influence_dict.update(line_dict) weight_files = python.force_list(dependencies.get('weight', list())) if not weight_files: for influence in files: if not influence.endswith( '.weights') or influence == 'influence.info': continue weight_files.append( path_utils.join_path(folder_path, influence)) for weight_file in weight_files: read_thread = ReadWeightFileThread() try: influence_dict = read_thread.run(influence_dict, weight_file) except Exception as exc: logger.error( 'Errors with influence "{}" while reading weight file: "{}" | {}' .format(weight_file, info_file, exc)) return influence_dict
def _get_comment_path(self): from tpDcc.libs.python import path version_folder = self._get_version_folder() file_path = None if version_folder: file_path = path.join_path(version_folder, 'comments.txt') return file_path
def _default_version_file_name(self): if not self._version_name: return version_folder = self._get_version_folder() version_path = path.join_path(version_folder, self._version_name + '.default') return version_path