def update_sequences_categories(self): """ Updates current sequences categories """ from artellapipe.widgets import sequence as sequence_widgets for btn in self._sequences_btn_grp.buttons(): self._sequences_btn_grp.removeButton(btn) qtutils.clear_layout(self._sequences_menu_layout) all_sequences_categories = ['All'] all_sequences = artellapipe.SequencesMgr().find_all_sequences() if all_sequences: sequence_names = [ sequence.get_name() for sequence in all_sequences ] all_sequences_categories.extend(sequence_names) for sequence_name in all_sequences_categories: sequence = artellapipe.SequencesMgr().find_sequence(sequence_name) new_btn = sequence_widgets.SequenceCategoryButton( sequence_name, sequence) new_btn.setMinimumWidth( QFontMetrics(new_btn.font()).width(sequence_name) + 10) new_btn.setCheckable(True) self._sequences_menu_layout.addWidget(new_btn) self._sequences_btn_grp.addButton(new_btn) if sequence_name == 'All': new_btn.setIcon(tpDcc.ResourcesMgr().icon('home')) new_btn.setChecked(True) new_btn.toggled.connect( partial(self._on_change_sequence, sequence_name))
def get_path(self): """ Implements abstract get_path function Returns the path of the sequence :return: str """ path_template_name = artellapipe.SequencesMgr().config.get('data', 'path_template_name') template = artellapipe.FilesMgr().get_template(path_template_name) if not template: LOGGER.warning( 'Impossible to retrieve sequence path because template "{}" is not in configuration file'.format( path_template_name)) return None template_dict = { 'project_id': self._project.id, 'project_id_number': self._project.id_number, 'sequence_name': self.get_name() } sequence_path = template.format(template_dict) if not sequence_path: LOGGER.warning( 'Impossible to retrieve sequence path from template: "{} | {} | {}"'.format( template.name, template.pattern, template_dict)) return None sequence_path = artellapipe.FilesMgr().prefix_path_with_project_path(sequence_path) return sequence_path
def change_sequence(self, sequence_name=None): """ Changes the sequence of the shots that are being showed by the viewer :param sequence_name: str """ if not sequence_name: sequence_name = 'All' all_sequences_names = artellapipe.SequencesMgr().get_sequence_names() if sequence_name != 'All' and sequence_name not in all_sequences_names: LOGGER.warning( 'Sequence {} not found for current project {}'.format( sequence_name, self._project.name.title())) sequence_name = 'All' self.clear() new_shots = list() for new_shot in reversed(self._shots): if sequence_name == 'All': new_shot.setVisible(True) new_shots.insert(0, new_shot) else: if new_shot.shot.get_sequence() == sequence_name: new_shot.setVisible(True) new_shots.insert(0, new_shot) else: new_shot.setVisible(False) new_shots.append(new_shot) for new_shot in new_shots: self._add_widget(new_shot)
def __init__(self, sequence, text=None, parent=None): self._sequence = sequence self._text = text or artellapipe.SequencesMgr( ).get_default_sequence_name() super(ArtellaSequenceWidget, self).__init__(parent=parent) self._init()
def get_latest_published_versions(self): """ Implements base ArtellaFile get_path function Returns latest published version of file :return: str """ file_path = self.get_path() return artellapipe.SequencesMgr().get_latest_published_versions( file_path, file_type=self.FILE_TYPE)
def update_cache(self, force=False): """ Updates internal cache with the current sequences located in Artella server """ if self._cache and not force: return self._cache python.clear_list(self._sequences) return artellapipe.SequencesMgr().find_all_sequences( force_update=force)
def get_thumbnail_path(self): """ Implements abstract get_path function Returns the path where sequence thumbnail is located :return: str """ thumb_attr = artellapipe.SequencesMgr().config.get('data', 'thumb_attribute') thumb_path = self._sequence_data.get(thumb_attr, None) return thumb_path
def get_name(self): """ Implements abstract get_name function Returns the name of the sequence :return: str """ name_attr = artellapipe.SequencesMgr().config.get('data', 'name_attribute') sequence_name = self._sequence_data.get(name_attr, None) if not sequence_name: LOGGER.warning( 'Impossible to retrieve sequence name because sequence data does not contains "{}" attribute.' '\nSequence Data: {}'.format(name_attr, self._sequence_data)) return None return sequence_name.rstrip()
def _on_sequence_clicked(self, sequence_widget): if not sequence_widget: return sequence = sequence_widget.sequence if not sequence: return sequence_name = sequence.get_name() sequence = artellapipe.SequencesMgr().find_sequence(sequence_name) if not sequence: LOGGER.warning('No Sequence found with name "{}" in current project'.format(sequence_name)) return valid_open = sequence.open_master_layout() if not valid_open: return self._stack.slide_in_index(1)
def get_file_type(self, file_type, extension=None): """ Returns sequence file object of the current sequence and given file type :param file_type: str :param extension: str :return: ArtellaAssetType """ if file_type not in self.FILES: return None sequence_file_class = artellapipe.SequencesMgr().get_sequence_file(file_type=file_type, extension=extension) if not sequence_file_class: LOGGER.warning( 'File Type: {} | {} not registered in current project!'.format(file_type, extension)) return return sequence_file_class(sequence=self)
def process(self, instance): if not instance.data.get('publish', False): return False project = instance.data.get('project', None) assert project, 'No valid project defined in current instance: {}'.format( instance) shots_config = tp.ConfigsMgr().get_config( config_name='artellapipe-shots') assert shots_config, 'No valid shots configuration file found in current instance: {}'.format( instance) shot_node = instance.data.get('shot', None) assert shot_node, 'No valid shot node found in current instance: {}'.format( instance) # Retrieve master layout file path sequence_name = shot_node.get_sequence() assert sequence_name, 'No valid sequence name found linked to current instance: {}'.format( instance) sequence = artellapipe.SequencesMgr().find_sequence(sequence_name) assert sequence, 'No valid sequence found linked to current instance: {}'.format( instance) sequence_file_type = sequence.get_file_type('master') assert sequence, 'File type "master" not found in current project' sequence_file_type.open_file() shot_name = shot_node.get_name() assert tp.Dcc.object_exists( shot_name), 'No valid shot found in current instance: {}'.format( instance) all_shots = artellapipe.ShotsMgr().find_all_shots() assert all_shots, 'No shots defined in current project!' start_frame = shots_config.get('start_frame', default=101) found = False for shot in all_shots: if shot.get_name() == shot_name: found = True break assert found, 'Shot with name: "{}" not found in current sequence!'.format( shot_name) new_version = bool( util.strtobool( os.environ.get( '{}_SEQUENCES_PUBLISHER_NEW_VERSION'.format( project.get_clean_name().upper()), 'False'))) base_comment = '{} | {} | Sequences Publisher > Shot "{}" Export'.format( timedate.get_current_time(), osplatform.get_user(True), shot_name) comment = instance.data.get('comment', None) if comment: base_comment = '{} | {}'.format(base_comment, comment) valid_export = artellapipe.ShotsMgr().export_shot( shot_name, start_frame=start_frame, new_version=new_version, comment=base_comment) assert valid_export, 'Shot with name "{}" was not exported successfully!'.format( shot_name) return True
def _export_file(self, file_path, *args, **kwargs): # Retrieve master layout file path sequence_name = self._shot.get_sequence() if not sequence_name: LOGGER.warning( 'Impossible to export shot file "{}" because is not linked to any sequence!' .format(self._shot.get_name())) return None sequence = artellapipe.SequencesMgr().find_sequence(sequence_name) if not sequence: LOGGER.warning( 'Impossible to export shot file "{}" because sequence "{}" was not found in current project' .format(self._shot.get_name(), sequence_name)) return None sequence_file_type = sequence.get_file_type('master') if not sequence_file_type: LOGGER.warning( 'Impossible to export shot file "{}" because sequence file type "master" is not defined ' 'in current project'.format(self._shot.get_name())) return None master_file_path = sequence_file_type.get_file() if not master_file_path or not os.path.exists(master_file_path): LOGGER.warning( 'Impossible to export shot file "{}" because master layout file "{}" does not exists!' .format(self._shot.get_name(), master_file_path)) return None sequence_file_type.open_file() master_locked = False if os.path.isfile(master_file_path): valid_lock = artellapipe.FilesMgr().lock_file(master_file_path) master_locked = True if not valid_lock: LOGGER.warning('Was not possible to lock file: {}'.format( master_file_path)) return False sequence_file_type.open_file() file_path_name = os.path.basename(file_path) file_path_dir = os.path.dirname(file_path) if not os.path.isdir(file_path_dir): LOGGER.info('Creating export file path directory: {}'.format( file_path_dir)) try: os.makedirs(file_path_dir) except Exception as exc: LOGGER.error( 'Error while creating export path directory: "{}" | {} | {}' .format(file_path_dir, exc, traceback.format_exc())) return None try: if os.path.isfile(file_path): fileio.delete_file(file_path_name, file_path_dir) fileio.copy_file(master_file_path, file_path) LOGGER.info('Created new Shot File: {}'.format(file_path)) except Exception as exc: LOGGER.error( 'Error while copying shot file "{}" from master layout file "{}" | {} | {}' .format(file_path, master_file_path, exc, traceback.format_exc())) return None if os.path.isfile(file_path): valid_lock = artellapipe.FilesMgr().lock_file(file_path) if not valid_lock: LOGGER.warning( 'Was not possible to lock file: {}'.format(file_path)) tp.Dcc.open_file(file_path) shot_anim_file_type = self._shot.get_file_type('shot_layout_anim') if not shot_anim_file_type: LOGGER.warning( 'Impossible to export shot "{}" because shot file type "shot_layout_anim" is not defined ' 'in current project'.format(self._shot.get_name())) return None start_frame = kwargs.get('start_frame', 101) valid_anim_export = shot_anim_file_type.export_file( start_frame=start_frame) if not valid_anim_export: LOGGER.warning('Layout Animation Export was not exported in file!') return None if master_locked: artellapipe.FilesMgr().unlock_file(master_file_path, warn_user=False) try: shot_anim_file_path = shot_anim_file_type.get_file() shot_anim_file_path_name = os.path.basename(shot_anim_file_path) shot_anim_file_path_directory = os.path.dirname( shot_anim_file_path) fileio.delete_file(shot_anim_file_path_name, shot_anim_file_path_directory) except Exception as exc: LOGGER.warning( 'Was not possible to remove Shot Layout Animation File: "{}" | {} | {}. Remove it manually' .format(shot_anim_file_path, exc, traceback.format_exc())) try: tp.Dcc.convert_fraction_keys_to_whole_keys( consider_selected_range=False) except Exception as exc: LOGGER.warning( 'Could not resolve any keyframes on fractions of a frame: {} | {}' .format(exc, traceback.format_exc())) # Clean shot nodes that are not valid anymore all_shots = tp.Dcc.all_scene_shots() shots_to_delete = [ shot for shot in all_shots if shot != self.get_name() ] tp.Dcc.delete_object(shots_to_delete) # Update timeline start_offset = self._shot.get_start_frame() - start_frame start_frame = self._shot.get_start_frame() - start_offset end_frame = self._shot.get_end_frame() - start_offset tp.Dcc.set_active_frame_range(start_frame, end_frame) # Update shot attributes self._shot.set_start_frame(start_frame) self._shot.set_end_frame(end_frame) # Remove cameras that does not belong to the shot camera_name = self._shot.get_camera() root_node = None all_cameras = tp.Dcc.get_all_cameras(full_path=True) or list() for camera in all_cameras: if not camera: continue base_name = tp.Dcc.node_short_name(camera) if base_name == camera_name: root_node = camera.split('|')[1] break if root_node: for camera in all_cameras: if not camera or not tp.Dcc.object_exists(camera): continue base_name = tp.Dcc.node_short_name(camera) if base_name == camera_name: continue reps = 0 node_to_delete = camera camera_parent = tp.Dcc.node_parent(camera) while camera_parent != '|{}'.format(root_node) and reps < 10: node_to_delete = camera_parent camera_parent = tp.Dcc.node_parent(node_to_delete) reps += 1 tp.Dcc.delete_object(node_to_delete) else: for camera in all_cameras: if not camera: continue base_name = tp.Dcc.node_short_name(camera) if base_name == camera_name: continue tp.Dcc.delete_object(camera) # Force look through to shot camera tp.Dcc.look_through_camera(camera_name) # Save scene tp.Dcc.save_current_scene(force=True) if tp.is_maya(): from tpDcc.dccs.maya.core import helpers helpers.clean_student_line() return True