def __call__(self, *args, **kwargs): """Check that all arguments are present and load all tracks that are given as paths instead of track objects. Also checks for direct calls with generators.""" # Initialization # generator_call = False # Special switch for direct generator calls found_args = {} # Will contain a set of parameters extracted found_tracks = {} # Will contain a set of track parameters extracted found_generators = {} # Will contain a set of FeatureStream extra_args = {} # Will contain a set of parameters computed all_tracks = [] # Will contain all single tracks sent tracks_to_close = [] # Will contain single tracks to close virtual_tracks = [] # Will contain the results tracks rest_of_fields = [] # Will contain variable output fields when required ### Parse arguments ### for p in self.input_args: if p['key'] in kwargs: value = kwargs[p['key']] elif len(args) >= p['position']: value = args[p['position']-1] elif 'default' in p: value = p['default'] elif p.get('optional'): continue else: raise Exception("The argument '%s' is missing for the manipulation '%s'." \ % (p['key'], self.short_name)) # Cast it if it's not the right type # if not isinstance(value, p['type']): value = p['type'](value) # Add it to the dict # found_args[p['key']] = value ### Parse tracks ### for t in self.input_tracks: if t['key'] in kwargs: value = kwargs[t['key']] elif len(args) >= t['position']: value = args[t['position']-1] elif 'default' in t: value = t['default'] elif t.get('optional'): continue else: raise Exception("The argument '%s' is missing for the manipulation '%s'." \ % (t['key'], self.short_name)) # Check is track collection # if t.get('kind') == 'many': if not is_list(value): message = "The track collection '%s' for the manipulation '%s' is not a list: %s" raise Exception(message % (t['key'], self.short_name, value)) # Don't modify the input list # if t.get('kind') == 'many': value = value[:] # Check for generator case # if is_gen(value): generator_call = True if t.get('kind') == 'many' and is_gen(value[0]): generator_call = True if generator_call: found_tracks[t['key']] = value continue # Check is path # if isinstance(value, basestring): value = track.load(value, readonly=True) tracks_to_close.append(value) if t.get('kind') == 'many': for i,_ in enumerate(value): if isinstance(value[i], basestring): value[i] = track.load(value[i], readonly=True) tracks_to_close.append(value[i]) # Add to the list of all tracks # if t.get('kind') == 'many': all_tracks += [x for x in value] else: all_tracks += [value] # Track collection must be combined # if t.get('kind') == 'many': value = TrackCollection(value, self.fields_collapse, self.chroms_collapse) # Variable fields case (track collection must collapse fields) # if t['fields'][-1] == '...': first_fields = t['fields'][:-1] rest_of_fields = [f for f in value.fields if f not in first_fields] value.fields = first_fields + rest_of_fields # Specific fields case # else: value.fields = t['fields'] # What about track SimpleTrack case # pass #TODO # Add it to the dict # found_tracks[t['key']] = value # Check for generator case # if generator_call: return self.from_generator(found_tracks, found_args, args, kwargs) # Collapse chromosomes # if not self.chroms_collapse: chromosomes = all_tracks[0].chromosomes else: chromosomes = collapse(self.chroms_collapse, [t.chromosomes for t in all_tracks]) # Multiple output tracks disabled # t = self.output_tracks[0] # Make a new virtual track # vtrack = VirtualTrack() # Output chromosome metadata # for chrom in chromosomes: vtrack.chrmeta[chrom] = {'length': max([i.chrmeta[chrom]['length'] for i in all_tracks])} # Output attributes # if t.get('datatype'): vtrack.datatype = t['datatype'] # Output name # vtrack.name = self.long_name + ' on ' + andify_strings([i.name for i in all_tracks]) ### Iterate on chromosomes ### for chrom in chromosomes: # Get special input arguments # for p in self.input_meta: if p['kind'] == 'chrom_len': extra_args[p['key']] = vtrack.chrmeta[chrom]['length'] # Call read on tracks # for k,input_track in found_tracks.items(): if is_list(input_track): found_generators[k] = [i.read(chrom) for i in input_track] else: found_generators[k] = input_track.read(chrom) # What about track collapse and recursion # pass #TODO # Final argument list # final_args = {} for d in (found_args, found_generators, extra_args): final_args.update(d) # Call generate # data = self.generate(**final_args) # Variable fields case # if t['fields'][-1] == '...': fields = t['fields'][:-1] + rest_of_fields else: fields = t['fields'] # Make a FeatureStream # stream = FeatureStream(data, fields) # Add it to the virtual track # vtrack.write(chrom, stream) # Close tracks later # vtrack.tracks_to_close = tracks_to_close # Add it # virtual_tracks.append(vtrack) # Return one virutal track or list of virtual tracks # return len(virtual_tracks) == 1 and virtual_tracks[0] or virtual_tracks
def fields(self): return collapse(self.fields_collapse, [t.fields for t in self.tracks])
def chromosomes(self): if not hasattr(self.tracks[0], "chromosomes"): return [] chroms = collapse(self.chroms_collapse, [t.chromosomes for t in self.tracks]) chroms.sort(key=natural_sort) return chroms
def __call__(self, *args, **kwargs): """Check that all arguments are present and load all tracks that are given as paths instead of track objects. Also checks for direct calls with generators.""" # Initialization # generator_call = False # Special switch for direct generator calls found_args = {} # Will contain a set of parameters extracted found_tracks = {} # Will contain a set of track parameters extracted found_generators = {} # Will contain a set of FeatureStream extra_args = {} # Will contain a set of parameters computed all_tracks = [] # Will contain all single tracks sent tracks_to_close = [] # Will contain single tracks to close virtual_tracks = [] # Will contain the results tracks rest_of_fields = [ ] # Will contain variable output fields when required ### Parse arguments ### for p in self.input_args: if p['key'] in kwargs: value = kwargs[p['key']] elif len(args) >= p['position']: value = args[p['position'] - 1] elif 'default' in p: value = p['default'] elif p.get('optional'): continue else: raise Exception("The argument '%s' is missing for the manipulation '%s'." \ % (p['key'], self.short_name)) # Cast it if it's not the right type # if not isinstance(value, p['type']): value = p['type'](value) # Add it to the dict # found_args[p['key']] = value ### Parse tracks ### for t in self.input_tracks: if t['key'] in kwargs: value = kwargs[t['key']] elif len(args) >= t['position']: value = args[t['position'] - 1] elif 'default' in t: value = t['default'] elif t.get('optional'): continue else: raise Exception("The argument '%s' is missing for the manipulation '%s'." \ % (t['key'], self.short_name)) # Check is track collection # if t.get('kind') == 'many': if not is_list(value): message = "The track collection '%s' for the manipulation '%s' is not a list: %s" raise Exception(message % (t['key'], self.short_name, value)) # Don't modify the input list # if t.get('kind') == 'many': value = value[:] # Check for generator case # if is_gen(value): generator_call = True if t.get('kind') == 'many' and is_gen(value[0]): generator_call = True if generator_call: found_tracks[t['key']] = value continue # Check is path # if isinstance(value, basestring): value = track.load(value, readonly=True) tracks_to_close.append(value) if t.get('kind') == 'many': for i, _ in enumerate(value): if isinstance(value[i], basestring): value[i] = track.load(value[i], readonly=True) tracks_to_close.append(value[i]) # Add to the list of all tracks # if t.get('kind') == 'many': all_tracks += [x for x in value] else: all_tracks += [value] # Track collection must be combined # if t.get('kind') == 'many': value = TrackCollection(value, self.fields_collapse, self.chroms_collapse) # Variable fields case (track collection must collapse fields) # if t['fields'][-1] == '...': first_fields = t['fields'][:-1] rest_of_fields = [ f for f in value.fields if f not in first_fields ] value.fields = first_fields + rest_of_fields # Specific fields case # else: value.fields = t['fields'] # What about track SimpleTrack case # pass #TODO # Add it to the dict # found_tracks[t['key']] = value # Check for generator case # if generator_call: return self.from_generator(found_tracks, found_args, args, kwargs) # Collapse chromosomes # if not self.chroms_collapse: chromosomes = all_tracks[0].chromosomes else: chromosomes = collapse(self.chroms_collapse, [t.chromosomes for t in all_tracks]) # Multiple output tracks disabled # t = self.output_tracks[0] # Make a new virtual track # vtrack = VirtualTrack() # Output chromosome metadata # for chrom in chromosomes: vtrack.chrmeta[chrom] = { 'length': max([i.chrmeta[chrom]['length'] for i in all_tracks]) } # Output attributes # if t.get('datatype'): vtrack.datatype = t['datatype'] # Output name # vtrack.name = self.long_name + ' on ' + andify_strings( [i.name for i in all_tracks]) ### Iterate on chromosomes ### for chrom in chromosomes: # Get special input arguments # for p in self.input_meta: if p['kind'] == 'chrom_len': extra_args[p['key']] = vtrack.chrmeta[chrom]['length'] # Call read on tracks # for k, input_track in found_tracks.items(): if is_list(input_track): found_generators[k] = [i.read(chrom) for i in input_track] else: found_generators[k] = input_track.read(chrom) # What about track collapse and recursion # pass #TODO # Final argument list # final_args = {} for d in (found_args, found_generators, extra_args): final_args.update(d) # Call generate # data = self.generate(**final_args) # Variable fields case # if t['fields'][-1] == '...': fields = t['fields'][:-1] + rest_of_fields else: fields = t['fields'] # Make a FeatureStream # stream = FeatureStream(data, fields) # Add it to the virtual track # vtrack.write(chrom, stream) # Close tracks later # vtrack.tracks_to_close = tracks_to_close # Add it # virtual_tracks.append(vtrack) # Return one virutal track or list of virtual tracks # return len(virtual_tracks) == 1 and virtual_tracks[0] or virtual_tracks