def __init__(self, sequence): """Init the class """ sequence = utils.asString(sequence) if not hasattr(self, '_frameSet'): self._frameSet = None try: # the main case, padding characters in the path.1-100#.exr path, frames, self._pad, self._ext = SPLIT_RE.split( sequence, 1) self._dir, self._base = os.path.split(path) self._frameSet = FrameSet(frames) except ValueError: # edge case 1; we've got an invalid pad for placeholder in PAD_MAP.keys(): if placeholder in sequence: msg = "Failed to parse FileSequence: {0}" raise ParseException(msg.format(sequence)) # edge case 2; we've got a single frame of a sequence a_frame = DISK_RE.match(sequence) if a_frame: self._dir, self._base, frames, self._ext = a_frame.groups() # edge case 3: we've got a single versioned file, not a sequence if frames and not self._base.endswith('.'): self._base = self._base + frames self._pad = '' elif not frames: self._pad = '' self._frameSet = None else: self._frameSet = FrameSet(frames) if self._frameSet: self._pad = FileSequence.getPaddingChars( len(frames)) else: self._pad = '' self._frameSet = None # edge case 4; we've got a solitary file, not a sequence else: path, self._ext = os.path.splitext(sequence) self._dir, self._base = os.path.split(path) self._pad = '' if self._dir: self.setDirname(self._dir) self._zfill = self.__class__.getPaddingNum(self._pad)
def yield_sequences_in_list(paths): """ Yield the discrete sequences within paths. This does not try to determine if the files actually exist on disk, it assumes you already know that. :param paths: a list of paths :rtype: generator """ seqs = {} _check = DISK_RE.match for match in ifilter(None, imap(_check, paths)): dirname, basename, frame, ext = match.groups() if not basename and not ext: continue key = (dirname, basename, ext) seqs.setdefault(key, set()) if frame: seqs[key].add(frame) for (dirname, basename, ext), frames in seqs.iteritems(): # build the FileSequence behind the scenes, rather than dupe work seq = FileSequence.__new__(FileSequence) seq._dir = dirname or '' seq._base = basename or '' seq._ext = ext or '' if frames: seq._frameSet = FrameSet(set(imap(int, frames))) if frames else None seq._pad = FileSequence.getPaddingChars(min(imap(len, frames))) else: seq._frameSet = None seq._pad = '' seq.__init__(str(seq)) yield seq
def __getitem__(self, idx): """ Allows indexing and slicing into the underlying :class:`.FrameSet` When indexing, a string filepath is returns for the frame. When slicing, a new :class:`FileSequence` is returned. Slicing outside the range of the sequence results in an IndexError Args: idx (int or slice): the desired index Returns: str or :obj:`FileSequence`: Raises: :class:`IndexError`: If slice is outside the range of the sequence """ if not self._frameSet: return futils.native_str(self) frames = self._frameSet[idx] if not hasattr(idx, 'start'): return self.frame(frames) fset = FrameSet(frames) if fset.is_null: raise IndexError("slice is out of range and returns no frames") fs = self.copy() fs.setFrameSet(fset) return fs
def __getitem__(self, idx): """ Allows indexing and slicing into the underlying :class:`fileseq.FrameSet`. When indexing, a string filepath is returns for the frame. When slicing, a new :class:`FileSequence` is returned. Slicing outside the range of the sequence results in an IndexError :type idx: int or slice :param idx: the desired index :rtype: str or :obj:`FileSequence` """ if not self._frameSet: return str(self) frames = self._frameSet[idx] if not hasattr(idx, 'start'): return self.frame(frames) fset = FrameSet(frames) if fset.is_null: raise IndexError("slice is out of range and returns no frames") fs = self.copy() fs.setFrameSet(fset) return fs
def setFrameRange(self, frange): """ Set a new frame range for the sequence. :param frange: a properly formatted frame range, as per :class:`fileseq.frameset.FrameSet` :rtype: None """ self._frameSet = FrameSet(frange)
def setFrameRange(self, frange): """ Set a new frame range for the sequence. Args: frange (str): a properly formatted frame range, as per :class:`.FrameSet` """ self._frameSet = FrameSet(frange)
def frames_to_seq(frames, pad_length, decimal_places): seq = start_new_seq() seq._frameSet = FrameSet(sorted(decimal.Decimal(f) for f in frames)) seq._frame_pad = cls.getPaddingChars(pad_length, pad_style=pad_style) if decimal_places: seq._subframe_pad = cls.getPaddingChars(decimal_places, pad_style=pad_style) else: seq._subframe_pad = '' finish_new_seq(seq) return seq
def setFrameSet(self, frameSet): """ Set a new :class:`.FrameSet` for the sequence. Args: frameSet (:class:`.FrameSet`): the new :class:`.FrameSet` object """ if frameSet is not None and frameSet.hasSubFrames(): if all(isinstance(frame, decimal.Decimal) for frame in frameSet): frameSet = FrameSet([ utils.quantize(frame, self._decimal_places) for frame in frameSet ]) self._frameSet = frameSet
def __init__(self, sequence, pad_style=PAD_STYLE_DEFAULT, allow_subframes=False): """Init the class """ sequence = utils.asString(sequence) if not hasattr(self, '_frameSet'): self._frameSet = None if allow_subframes: split_re = self.SPLIT_SUB_RE disk_re = self.DISK_SUB_RE else: split_re = self.SPLIT_RE disk_re = self.DISK_RE try: # the main case, padding characters in the path.1-100#.exr path, frames, self._pad, self._ext = split_re.split( sequence, 1) self._frame_pad, _, self._subframe_pad = self._pad.partition( '.') self._dir, self._base = os.path.split(path) self._frameSet = FrameSet(frames) except ValueError: # edge case 1; we've got an invalid pad for placeholder in self.PAD_MAP: if placeholder in sequence: msg = "Failed to parse FileSequence: {!r}" raise ParseException(msg.format(sequence)) # edge case 2; we've got a single frame of a sequence a_frame = disk_re.match(sequence) if a_frame: self._dir, self._base, frames, self._ext = a_frame.groups() # edge case 3: we've got a single versioned file, not a sequence if frames and not self._base.endswith('.'): self._base = self._base + frames self._pad = '' self._frame_pad = '' self._subframe_pad = '' elif not frames: self._pad = '' self._frame_pad = '' self._subframe_pad = '' self._frameSet = None else: self._frameSet = FrameSet(frames) if self._frameSet: frame_num, _, subframe_num = frames.partition('.') self._frame_pad = self.getPaddingChars( len(frame_num), pad_style=pad_style) if subframe_num: self._subframe_pad = self.getPaddingChars( len(subframe_num), pad_style=pad_style) self._pad = '.'.join( [self._frame_pad, self._subframe_pad]) else: self._pad = self._frame_pad self._subframe_pad = '' else: self._pad = '' self._frame_pad = '' self._subframe_pad = '' self._frameSet = None # edge case 4; we've got a solitary file, not a sequence else: path, self._ext = os.path.splitext(sequence) self._dir, self._base = os.path.split(path) self._pad = '' self._frame_pad = '' self._subframe_pad = '' if self._dir: self.setDirname(self._dir) self._pad_style = pad_style self._zfill = self.getPaddingNum(self._frame_pad, pad_style=pad_style) self._decimal_places = self.getPaddingNum(self._subframe_pad, pad_style=pad_style) # Round subframes to match sequence if self._frameSet is not None and self._frameSet.hasSubFrames(): self._frameSet = FrameSet([ utils.quantize(frame, self._decimal_places) for frame in self._frameSet ])
def yield_sequences_in_list(cls, paths, using=None, pad_style=PAD_STYLE_DEFAULT, allow_subframes=False): """ Yield the discrete sequences within paths. This does not try to determine if the files actually exist on disk, it assumes you already know that. A template :obj:`FileSequence` object can also be provided via the ``using`` parameter. Given this template, the dirname, basename, and extension values will be used to extract the frame value from the paths instead of parsing each path from scratch. Examples: The ``using`` field can supply a template for extracting the frame component from the paths:: paths = [ '/dir/file_001.0001.ext', '/dir/file_002.0001.ext', '/dir/file_003.0001.ext', ] template = FileSequence('/dir/file_#.0001.ext') seqs = FileSequence.yield_sequences_in_list(paths, using) # [<FileSequence: '/dir/file_1-3@@@.0001.ext'>] Args: paths (list[str]): a list of paths using (:obj:`FileSequence`): Optional sequence to use as template pad_style (`.PAD_STYLE_DEFAULT` or `.PAD_STYLE_HASH1` or `.PAD_STYLE_HASH4`): padding style allow_subframes (bool): if True, handle subframe filenames Yields: :obj:`FileSequence`: """ seqs = {} if allow_subframes: _check = cls.DISK_SUB_RE.match else: _check = cls.DISK_RE.match using_template = isinstance(using, FileSequence) if using_template: dirname, basename, ext = using.dirname(), using.basename( ), using.extension() head = len(dirname + basename) tail = -len(ext) frames = set() for path in filter(None, map(utils.asString, paths)): frame = path[head:tail] try: int(frame) except ValueError: if not allow_subframes: continue try: decimal.Decimal(frame) except decimal.DecimalException: continue _, _, subframe = frame.partition(".") key = (dirname, basename, ext, len(subframe)) seqs.setdefault(key, frames).add(frame) else: for match in filter(None, map(_check, map(utils.asString, paths))): dirname, basename, frame, ext = match.groups() if not basename and not ext: continue if frame: _, _, subframe = frame.partition(".") key = (dirname, basename, ext, len(subframe)) else: key = (dirname, basename, ext, 0) seqs.setdefault(key, set()) if frame: seqs[key].add(frame) for (dirname, basename, ext, decimal_places), frames in iteritems(seqs): # build the FileSequence behind the scenes, rather than dupe work seq = cls.__new__(cls) seq._dir = dirname or '' seq._base = basename or '' seq._ext = ext or '' seq._pad_style = pad_style if frames: seq._frameSet = FrameSet(frames) frame_lengths = set() for frame in frames: frame_num, _, _ = frame.partition(".") frame_lengths.add(len(frame_num)) seq._frame_pad = cls.getPaddingChars(min(frame_lengths), pad_style=pad_style) if decimal_places: seq._subframe_pad = cls.getPaddingChars( decimal_places, pad_style=pad_style) else: seq._subframe_pad = '' else: seq._frameSet = None seq._frame_pad = '' seq._subframe_pad = '' if seq._subframe_pad: seq._pad = '.'.join([seq._frame_pad, seq._subframe_pad]) else: seq._pad = seq._frame_pad seq.__init__(utils.asString(seq)) yield seq