def execPushButton(self): """ Execute the function associated with a button. ***NOT YET IMPLEMENTED*** """ verbose.print_( "%s %s" % (self.sender().objectName(), self.sender().property('exec')))
def createDir(path): """ Create a directory with the specified path. """ path = os.path.normpath(path) if os.path.isdir(path): verbose.print_("Directory already exists: %s" % path) pass else: try: os.makedirs(path) # Hide the folder if its name starts with a dot, as these files # are not automatically hidden on Windows if os.environ['IC_RUNNING_OS'] == "Windows": if os.path.basename(path).startswith('.'): setHidden(path) verbose.print_( 'mkdir "%s"' % path) # This causes an error if user config dir doesn't exist return path except: verbose.error("Cannot create directory: %s" % path) return False
def storeValue(self, category, attr, value=""): """ Store value in data. """ currentAttrStr = "%20s %s.%s" % (type(value), category, attr) if currentAttrStr == self.currentAttrStr: verbose.print_("%s=%s" % (currentAttrStr, value), inline=True) else: verbose.print_("%s=%s" % (currentAttrStr, value)) self.prefs.set_attr(category, attr, value) # str(value) self.currentAttrStr = currentAttrStr
def storeWindow(self): """ Store window geometry and state. (Save state may cause issues with PyQt5) """ if self.store_window_geometry: try: self.settings.setValue("geometry", self.saveGeometry()) verbose.print_("Storing window geometry for '%s'." % self.objectName()) except: verbose.warning("Could not store window geometry for '%s'." % self.objectName())
def copyDirContents(source, destination, umask='000'): """ Copy the contents of a folder recursively. Could rewrite using shutil.copy / copytree? """ src = os.path.normpath(os.path.join(source, "*")) dst = os.path.normpath(destination) if os.environ['IC_RUNNING_OS'] == "Windows": cmdStr = 'copy /Y "%s" "%s"' % (src, dst) elif os.environ['IC_RUNNING_OS'] == "Linux": # Quick bodge cmdStr = 'cp -rf %s %s' % (src, dst) else: cmdStr = 'cp -rf "%s" "%s"' % (src, dst) verbose.print_(cmdStr) os.system(cmdStr)
def calcAspectRatio(self): """ Calculate aspect ratio. """ # # fullWidth = self.frame.fullWidth_spinBox.value() # # fullHeight = self.frame.fullHeight_spinBox.value() # fullWidth = int(self.parent.prefs.get_attr('resolution', 'fullWidth')) # fullHeight = int(self.parent.prefs.get_attr('resolution', 'fullHeight')) fullWidth = self.getInt('fullWidth') fullHeight = self.getInt('fullHeight') ar = Fraction(fullWidth, fullHeight) self.parent.aspectRatio = float(fullWidth) / float(fullHeight) verbose.print_("Aspect ratio: %f" % self.parent.aspectRatio, 4) self.frame.preserveAR_checkBox.setText( "Lock aspect ratio to %d:%d (%.3f)" % (ar.numerator, ar.denominator, self.parent.aspectRatio))
def move(source, destination, quiet=False): """ Move a file or folder. """ src = os.path.normpath(source) dst = os.path.normpath(destination) if not quiet: verbose.print_('move "%s" -> "%s"' % (src, dst)) try: shutil.move(src, dst) return True except: exc_type, exc_value, exc_traceback = sys.exc_info() msg = traceback.format_exception_only(exc_type, exc_value)[0] if not quiet: verbose.error(msg) return False
def execute(args): """ Wrapper to execute a command using subprocess.check_output(). """ verbose.print_(" ".join(arg for arg in args)) try: if os.environ['IC_RUNNING_OS'] == "Windows": output = subprocess.check_output(args, creationflags=CREATE_NO_WINDOW) else: output = subprocess.check_output(args) return True, output.decode() except subprocess.CalledProcessError as e: error_msg = e.output.decode() # verbose.error(error_msg) # raise RuntimeError(error_msg) return False, error_msg
def openProperties(self, category, storeProperties=True): """ Open properties panel for selected settings category. Loads UI file and sets up widgets. """ self.currentCategory = category # Show panel & load values into form widgets if self.loadPanel(category): if (self.inherit is not None) \ and self.ui.settings_frame.property('inheritable'): verbose.print_("Category: %s (values inheritable)" % category) self.setupWidgets(self.ui.settings_frame, forceCategory=category, inherit=self.prefs_inherited, storeProperties=False) else: verbose.print_("Category: %s" % category) self.setupWidgets(self.ui.settings_frame, forceCategory=category, storeProperties=storeProperties)
def hardLink(source, destination, umask='000', verify=True): """ Creates hard links. """ src = os.path.normpath(source) dst = os.path.normpath(destination) if os.environ['IC_RUNNING_OS'] == "Windows": # If destination is a folder, append the filename from the source if os.path.isdir(dst): filename = os.path.basename(src) dst = os.path.join(dst, filename) # Delete the destination file if it already exists - this is to mimic # the Unix behaviour and force creation of the hard link if os.path.isfile(dst): os.system('del "%s" /f /q' % dst) # Create the hardlink #cmdStr = 'mklink /H "%s" "%s"' %(dst, src) # This only works with local NTFS volumes cmdStr = 'fsutil hardlink create "%s" "%s" >nul' % ( dst, src ) # Works over SMB network shares; suppressing output to null else: #cmdStr = '%s; ln -f %s %s' %(setUmask(umask), src, dst) cmdStr = 'ln -f %s %s' % (src, dst) verbose.print_(cmdStr) os.system(cmdStr) # Make sure source and destination files match if verify: if verify_hardlink(src, dst): return dst else: verbose.warning( "Failed to create hardlink. Attempting to copy file instead.") copy(src, dst) else: return dst
def submit_job(**kwargs): """ Submit job to Deadline. """ cmd_output = "" result_msg = "" # if kwargs is not None: # for key, value in kwargs.items(): # print("%24s = %s" %(key, value)) try: if kwargs['renderLayers']: # Batch submission ----------------------- # Generate submission info files num_jobs = 0 job_info_file_list = [] plugin_info_file_list = [] for render_layer in re.split( r',\s*', kwargs['renderLayers']): # may be better to pass as list kwargs['renderLayer'] = render_layer # kwargs['isMovie'] = False job_info_file = generate_job_info_file(**kwargs) job_info_file_list.append(job_info_file) plugin_info_file = generate_plugin_info_file(**kwargs) plugin_info_file_list.append(plugin_info_file) num_jobs += 1 # Generate batch file batch_submission_file = generate_batch_file( kwargs['scene'], job_info_file_list, plugin_info_file_list) # Execute deadlinecommand cmd_result, cmd_output = os_wrapper.execute( [os.environ['RQ_DEADLINECOMMAND'], batch_submission_file]) if cmd_result: result_msg = "Successfully submitted %d job(s) to Deadline." % num_jobs else: # Single job submission --------------------------------------- # Generate submission info files kwargs['renderLayer'] = None job_info_file = generate_job_info_file(**kwargs) plugin_info_file = generate_plugin_info_file(**kwargs) # Execute deadlinecommand cmd_result, cmd_output = os_wrapper.execute([ os.environ['RQ_DEADLINECOMMAND'], job_info_file, plugin_info_file ]) if cmd_result: result_msg = "Successfully submitted job to Deadline." if cmd_result: result = True verbose.print_(cmd_output) #.decode()) verbose.message(result_msg) else: raise RuntimeError(cmd_output) except: # Submission failed --------------------------------------------- result = False exc_type, exc_value, exc_traceback = sys.exc_info() traceback.print_exception(exc_type, exc_value, exc_traceback) result_msg = "Failed to submit job to Deadline." verbose.error(result_msg) if (exc_type == RuntimeError) and cmd_output: result_msg += "\n" + cmd_output else: result_msg += "\nCheck console output for details." #output_str = "Either the Deadline executable could not be found, or the submission info files could not be written." #output_str = traceback.format_exception_only(exc_type, exc_value)[0] return result, result_msg
def setupUI(self, window_object, window_title="", ui_file="", stylesheet="", prefs_file=None, store_window_geometry=True): """ Setup the UI. """ verbose.debug("Window object: %s Parent: %s" % (self, self.parent)) # Instantiate preferences data class if prefs_file is None: self.prefs = None else: self.prefs = self.createPrefs(prefs_file) # Define some global variables self.currentAttrStr = "" # Load UI & stylesheet found_ui_file = self.checkFilePath(ui_file, searchpath=[ os.environ['IC_FORMSDIR'], ]) if os.path.isfile(found_ui_file): self.ui = QtCompat.loadUi(found_ui_file, self) else: verbose.error("UI file does not exist: %s" % found_ui_file) # Store some system UI colours & define colour palette self.col = {} self.col['text'] = QtGui.QColor(204, 204, 204) self.col['disabled'] = QtGui.QColor(102, 102, 102) self.col['highlighted-text'] = QtGui.QColor(255, 255, 255) tmpWidget = QtWidgets.QWidget() self.col['sys-window'] = tmpWidget.palette().color( QtGui.QPalette.Window) self.col['sys-highlight'] = tmpWidget.palette().color( QtGui.QPalette.Highlight) # self.col['window'] = self.col['sys-window'] self.col['highlight'] = self.col['sys-highlight'] self.col['window'] = QtGui.QColor('#444444') # self.col['highlight'] = QtGui.QColor('#78909c') self.computeUIPalette() # Load and set stylesheet self.stylesheet = self.checkFilePath(stylesheet, searchpath=[ os.environ['IC_FORMSDIR'], ]) self.loadStyleSheet() # Set window title self.setObjectName(window_object) if window_title: self.setWindowTitle(window_title) else: window_title = self.windowTitle() # Perform custom widget setup self.setupWidgets(self.ui) # Restore window geometry and state self.store_window_geometry = store_window_geometry if self.store_window_geometry: try: uiName = self.objectName() if os.environ['IC_ENV'] != 'STANDALONE': uiName += "_" + os.environ['IC_ENV'].lower() self.settings = QtCore.QSettings(os.environ['IC_VENDOR'], uiName) self.restoreGeometry(self.settings.value("geometry", "")) verbose.print_("Restoring window geometry for '%s'." % self.objectName()) except (KeyError, TypeError): verbose.warning("Could not restore window geometry for '%s'." % self.objectName()) # # Use QSettings to store window geometry and state. # # (Restore state may cause issues with PyQt5) # if os.environ['IC_ENV'] == 'STANDALONE': # verbose.print_("Restoring window geometry for '%s'." %self.objectName()) # try: # self.settings = QtCore.QSettings( # os.environ['IC_VENDOR'], window_title) # self.restoreGeometry(self.settings.value("geometry", "")) # # self.restoreState(self.settings.value("windowState", "")) # except: # pass # # Makes Maya perform magic which makes the window stay on top in # # OS X and Linux. As an added bonus, it'll make Maya remember the # # window position. # elif os.environ['IC_ENV'] == 'MAYA': # self.setProperty("saveWindowPref", True) # elif os.environ['IC_ENV'] == 'NUKE': # pass # else: # # Move to centre of active screen # desktop = QtWidgets.QApplication.desktop() # screen = desktop.screenNumber(desktop.cursor().pos()) # self.move(desktop.screenGeometry(screen).center() - self.frameGeometry().center()) # # Move to centre of parent window # self.move(self.parent.frameGeometry().center() - self.frameGeometry().center()) # Set up keyboard shortcuts self.shortcutUnloadStyleSheet = QtWidgets.QShortcut(self) self.shortcutUnloadStyleSheet.setKey('Ctrl+Shift+R') self.shortcutUnloadStyleSheet.activated.connect(self.unloadStyleSheet) self.shortcutReloadStyleSheet = QtWidgets.QShortcut(self) self.shortcutReloadStyleSheet.setKey('Ctrl+R') self.shortcutReloadStyleSheet.activated.connect(self.loadStyleSheet)
def parse(filepath, base_dir=os.environ['SCNMGR_SAVE_DIR'], convention=os.environ['SCNMGR_CONVENTION']): """ Parse the given filepath (relative to base_dir) based on a naming convention and return a dictionary of elements for processing. TODO: check shot, artist, discipline etc. against valid whitelist """ if not os.path.isfile(filepath): verbose.print_("Could not parse filename as file doesn't exist: %s" % filepath) return None filepath = os.path.normpath(filepath) base_dir = os.path.normpath(base_dir) # Make filepath relative to base_dir if filepath.startswith(base_dir): filepath = filepath.replace(base_dir, '', 1) filepath = filepath.replace('\\', '/') # Convert to forward slashes if filepath.startswith('/'): filepath = filepath.replace('/', '', 1) # Remove leading slash # Find optional parts in naming convention # (only one optional section is allowed, if there are more, all optional # parts will be ignored.) valid_conventions = [convention.replace('[', '').replace(']', '')] pattern = r'\[.+?\]' optionals = re.findall(pattern, convention) if len(optionals) == 1: for i, optional in enumerate(optionals): valid_conventions.append(convention.replace(optional, '', i + 1)) # print valid_conventions # # Find tokens in naming convention # pattern = r'<\w+>' # tokens = re.findall(pattern, convention) # # Remove duplicates & sort list # tokens = list(set(tokens)) # # tokens.sort() # print tokens # # Generate regular expression to represent naming convention token_dict = {} success = False f = explode_path(filepath) for con in valid_conventions: c = explode_path(con) if same_structure(f, c): for i, dirs in enumerate(c): for j, token in enumerate(dirs): value = f[i][j] if token in token_dict: # Sanity check duplicated tokens if token_dict[token] != value: verbose.error( "Could not parse filename due to a token value mismatch." ) return None else: token_dict[token] = value success = True if success: # print(token_dict) return token_dict else: msg = "The filename '%s' could not be parsed because it does not comply with the naming convention." % filepath for con in valid_conventions: msg += "\n" + con verbose.error(msg) return None