3 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/changeset/a3ca6efab775/ changeset: a3ca6efab775 user: jgoecks date: 2012-06-03 17:08:45 summary: Enhance genome support: (a) make genome information available in Galaxy app and (b) refactor genome code out of visualization mixin and into Genome objects. affected #: 6 files diff -r 1890cb0d1cfbb3ef5a09affcdd18d2b8acf7d811 -r a3ca6efab775b82435770daea85c842617912727 lib/galaxy/app.py --- a/lib/galaxy/app.py +++ b/lib/galaxy/app.py @@ -12,6 +12,7 @@ from galaxy.objectstore import build_object_store_from_config import galaxy.quota from galaxy.tags.tag_handler import GalaxyTagHandler +from galaxy.visualization.genomes import Genomes from galaxy.tools.imp_exp import load_history_imp_exp_tools from galaxy.tools.genome_index import load_genome_index_tools from galaxy.sample_tracking import external_service_types @@ -70,6 +71,8 @@ self.security = security.SecurityHelper( id_secret=self.config.id_secret ) # Tag handler self.tag_handler = GalaxyTagHandler() + # Genomes + self.genomes = Genomes( self ) # Tool data tables self.tool_data_tables = galaxy.tools.data.ToolDataTableManager( self.config.tool_data_table_config_path ) # Initialize the tools, making sure the list of tool configs includes the reserved migrated_tools_conf.xml file. diff -r 1890cb0d1cfbb3ef5a09affcdd18d2b8acf7d811 -r a3ca6efab775b82435770daea85c842617912727 lib/galaxy/visualization/genomes.py --- /dev/null +++ b/lib/galaxy/visualization/genomes.py @@ -0,0 +1,289 @@ +import os, re, sys, glob +from bx.seq.twobit import TwoBitFile +from galaxy.util.json import from_json_string +from galaxy import model +from galaxy.util.bunch import Bunch + +# FIXME: copied from tracks.py +# Message strings returned to browser +messages = Bunch( + PENDING = "pending", + NO_DATA = "no data", + NO_CHROMOSOME = "no chromosome", + NO_CONVERTER = "no converter", + NO_TOOL = "no tool", + DATA = "data", + ERROR = "error", + OK = "ok" +) + +def decode_dbkey( dbkey ): + """ Decodes dbkey and returns tuple ( username, dbkey )""" + if ':' in dbkey: + return dbkey.split( ':' ) + else: + return None, dbkey + +class Genome( object ): + """ + Encapsulates information about a known genome/dbkey. + """ + def __init__( self, key, len_file=None, twobit_file=None ): + self.key = key + self.len_file = len_file + self.twobit_file = twobit_file + + +class Genomes( object ): + """ + Provides information about available genome data and methods for manipulating that data. + """ + + def __init__( self, app ): + # Create list of known genomes from len files. + self.genomes = {} + len_files = glob.glob( os.path.join( app.config.len_file_path, "*.len" ) ) + for f in len_files: + key = os.path.split( f )[1].split( ".len" )[0] + self.genomes[ key ] = Genome( key, len_file=f ) + + # Add genome data (twobit files) to genomes. + for line in open( os.path.join( app.config.tool_data_path, "twobit.loc" ) ): + if line.startswith("#"): continue + val = line.split() + if len( val ) == 2: + key, path = val + if key in self.genomes: + self.genomes[ key ].twobit_file = path + + def get_dbkeys_with_chrom_info( self, trans ): + """ Returns all valid dbkeys that have chromosome information. """ + + # All user keys have a len file. + user_keys = {} + user = trans.get_user() + if 'dbkeys' in user.preferences: + user_keys = from_json_string( user.preferences['dbkeys'] ) + + dbkeys = [ (v, k) for k, v in trans.db_builds if ( ( k in self.genomes and self.genomes[ k ].len_file ) or k in user_keys ) ] + return dbkeys + + def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): + """ + Returns a naturally sorted list of chroms/contigs for a given dbkey. + Use either chrom or low to specify the starting chrom in the return list. + """ + def check_int(s): + if s.isdigit(): + return int(s) + else: + return s + + def split_by_number(s): + return [ check_int(c) for c in re.split('([0-9]+)', s) ] + + # + # Parameter check, setting. + # + if num: + num = int( num ) + else: + num = sys.maxint + + if low: + low = int( low ) + if low < 0: + low = 0 + else: + low = 0 + + # If there is no dbkey owner, default to current user. + dbkey_owner, dbkey = decode_dbkey( dbkey ) + if dbkey_owner: + dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() + else: + dbkey_user = trans.user + + # + # Get len file. + # + len_file = None + len_ds = None + user_keys = {} + if dbkey_user and 'dbkeys' in dbkey_user.preferences: + user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) + if dbkey in user_keys: + dbkey_attributes = user_keys[ dbkey ] + if 'fasta' in dbkey_attributes: + build_fasta = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dbkey_attributes[ 'fasta' ] ) + len_file = build_fasta.get_converted_dataset( trans, 'len' ).file_name + # Backwards compatibility: look for len file directly. + elif 'len' in dbkey_attributes: + len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name + + if not len_file: + len_ds = trans.db_dataset_for( dbkey ) + if not len_ds: + len_file = os.path.join( trans.app.config.len_file_path, "%s.len" % dbkey ) + else: + len_file = len_ds.file_name + + # + # Get chroms data: + # (a) chrom name, len; + # (b) whether there are previous, next chroms; + # (c) index of start chrom. + # + len_file_enumerate = enumerate( open( len_file ) ) + chroms = {} + prev_chroms = False + start_index = 0 + if chrom: + # Use starting chrom to start list. + found = False + count = 0 + for line_num, line in len_file_enumerate: + if line.startswith("#"): + continue + name, len = line.split("\t") + if found: + chroms[ name ] = int( len ) + count += 1 + elif name == chrom: + # Found starting chrom. + chroms[ name ] = int ( len ) + count += 1 + found = True + start_index = line_num + if line_num != 0: + prev_chroms = True + if count >= num: + break + else: + # Use low to start list. + high = low + int( num ) + prev_chroms = ( low != 0 ) + start_index = low + + # Read chrom data from len file. + # TODO: this may be too slow for very large numbers of chroms/contigs, + # but try it out for now. + if not os.path.exists( len_file ): + return None + + for line_num, line in len_file_enumerate: + if line_num < low: + continue + if line_num >= high: + break + if line.startswith("#"): + continue + # LEN files have format: + # <chrom_name><tab><chrom_length> + fields = line.split("\t") + chroms[ fields[0] ] = int( fields[1] ) + + # Set flag to indicate whether there are more chroms after list. + next_chroms = False + try: + len_file_enumerate.next() + next_chroms = True + except: + # No more chroms to read. + pass + + to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()] + to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) )) + return { 'reference': self.has_reference_data( trans, dbkey, dbkey_user ), 'chrom_info': to_sort, + 'prev_chroms' : prev_chroms, 'next_chroms' : next_chroms, 'start_index' : start_index } + + def has_reference_data( self, trans, dbkey, dbkey_owner=None ): + """ + Returns true if there is reference data for the specified dbkey. If dbkey is custom, + dbkey_owner is needed to determine if there is reference data. + """ + # Look for key in built-in builds. + if dbkey in self.available_genomes: + # There is built-in reference data. + return True + + # Look for key in owner's custom builds. + if dbkey_owner and 'dbkeys' in dbkey_owner.preferences: + user_keys = from_json_string( dbkey_owner.preferences[ 'dbkeys' ] ) + if dbkey in user_keys: + dbkey_attributes = user_keys[ dbkey ] + if 'fasta' in dbkey_attributes: + # Fasta + converted datasets can provide reference data. + return True + + return False + + def reference( self, trans, dbkey, chrom, low, high, **kwargs ): + """ + Return reference data for a build. + """ + + # If there is no dbkey owner, default to current user. + dbkey_owner, dbkey = decode_dbkey( dbkey ) + if dbkey_owner: + dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() + else: + dbkey_user = trans.user + + if not self.has_reference_data( trans, dbkey, dbkey_user ): + return None + + # + # Get twobit file with reference data. + # + twobit_file_name = None + if dbkey in self.available_genomes: + # Built-in twobit. + twobit_file_name = self.available_genomes[dbkey] + else: + user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) + dbkey_attributes = user_keys[ dbkey ] + fasta_dataset = trans.app.model.HistoryDatasetAssociation.get( dbkey_attributes[ 'fasta' ] ) + error = self._convert_dataset( trans, fasta_dataset, 'twobit' ) + if error: + return error + else: + twobit_dataset = fasta_dataset.get_converted_dataset( trans, 'twobit' ) + twobit_file_name = twobit_dataset.file_name + + # Read and return reference data. + try: + twobit = TwoBitFile( open( twobit_file_name ) ) + if chrom in twobit: + seq_data = twobit[chrom].get( int(low), int(high) ) + return { 'dataset_type': 'refseq', 'data': seq_data } + except IOError: + return None + + ## FIXME: copied from tracks.py (tracks controller) - this should be consolidated when possible. + def _convert_dataset( self, trans, dataset, target_type ): + """ + Converts a dataset to the target_type and returns a message indicating + status of the conversion. None is returned to indicate that dataset + was converted successfully. + """ + + # Get converted dataset; this will start the conversion if necessary. + try: + converted_dataset = dataset.get_converted_dataset( trans, target_type ) + except NoConverterException: + return messages.NO_CONVERTER + except ConverterDependencyException, dep_error: + return { 'kind': messages.ERROR, 'message': dep_error.value } + + # Check dataset state and return any messages. + msg = None + if converted_dataset and converted_dataset.state == model.Dataset.states.ERROR: + job_id = trans.sa_session.query( trans.app.model.JobToOutputDatasetAssociation ) \ + .filter_by( dataset_id=converted_dataset.id ).first().job_id + job = trans.sa_session.query( trans.app.model.Job ).get( job_id ) + msg = { 'kind': messages.ERROR, 'message': job.stderr } + elif not converted_dataset or converted_dataset.state != model.Dataset.states.OK: + msg = messages.PENDING + + return msg \ No newline at end of file diff -r 1890cb0d1cfbb3ef5a09affcdd18d2b8acf7d811 -r a3ca6efab775b82435770daea85c842617912727 lib/galaxy/visualization/tracks/genomes.py --- a/lib/galaxy/visualization/tracks/genomes.py +++ /dev/null @@ -1,264 +0,0 @@ -import os, re, sys -from bx.seq.twobit import TwoBitFile -from galaxy.util.json import from_json_string -from galaxy import model -from galaxy.util.bunch import Bunch - -# FIXME: copied from tracks.py -# Message strings returned to browser -messages = Bunch( - PENDING = "pending", - NO_DATA = "no data", - NO_CHROMOSOME = "no chromosome", - NO_CONVERTER = "no converter", - NO_TOOL = "no tool", - DATA = "data", - ERROR = "error", - OK = "ok" -) - -def decode_dbkey( dbkey ): - """ Decodes dbkey and returns tuple ( username, dbkey )""" - if ':' in dbkey: - return dbkey.split( ':' ) - else: - return None, dbkey - - -class Genomes( object ): - """ - Provides information about available genome data and methods for manipulating that data. - """ - - def __init__( self, app ): - # Create list of available genomes. - self.available_genomes = None - avail_genomes = {} - for line in open( os.path.join( app.config.tool_data_path, "twobit.loc" ) ): - if line.startswith("#"): continue - val = line.split() - if len( val ) == 2: - key, path = val - avail_genomes[ key ] = path - self.available_genomes = avail_genomes - - def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): - """ - Returns a naturally sorted list of chroms/contigs for a given dbkey. - Use either chrom or low to specify the starting chrom in the return list. - """ - def check_int(s): - if s.isdigit(): - return int(s) - else: - return s - - def split_by_number(s): - return [ check_int(c) for c in re.split('([0-9]+)', s) ] - - # - # Parameter check, setting. - # - if num: - num = int( num ) - else: - num = sys.maxint - - if low: - low = int( low ) - if low < 0: - low = 0 - else: - low = 0 - - # If there is no dbkey owner, default to current user. - dbkey_owner, dbkey = decode_dbkey( dbkey ) - if dbkey_owner: - dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() - else: - dbkey_user = trans.user - - # - # Get len file. - # - len_file = None - len_ds = None - user_keys = {} - if dbkey_user and 'dbkeys' in dbkey_user.preferences: - user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) - if dbkey in user_keys: - dbkey_attributes = user_keys[ dbkey ] - if 'fasta' in dbkey_attributes: - build_fasta = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dbkey_attributes[ 'fasta' ] ) - len_file = build_fasta.get_converted_dataset( trans, 'len' ).file_name - # Backwards compatibility: look for len file directly. - elif 'len' in dbkey_attributes: - len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name - - if not len_file: - len_ds = trans.db_dataset_for( dbkey ) - if not len_ds: - len_file = os.path.join( trans.app.config.len_file_path, "%s.len" % dbkey ) - else: - len_file = len_ds.file_name - - # - # Get chroms data: - # (a) chrom name, len; - # (b) whether there are previous, next chroms; - # (c) index of start chrom. - # - len_file_enumerate = enumerate( open( len_file ) ) - chroms = {} - prev_chroms = False - start_index = 0 - if chrom: - # Use starting chrom to start list. - found = False - count = 0 - for line_num, line in len_file_enumerate: - if line.startswith("#"): - continue - name, len = line.split("\t") - if found: - chroms[ name ] = int( len ) - count += 1 - elif name == chrom: - # Found starting chrom. - chroms[ name ] = int ( len ) - count += 1 - found = True - start_index = line_num - if line_num != 0: - prev_chroms = True - if count >= num: - break - else: - # Use low to start list. - high = low + int( num ) - prev_chroms = ( low != 0 ) - start_index = low - - # Read chrom data from len file. - # TODO: this may be too slow for very large numbers of chroms/contigs, - # but try it out for now. - if not os.path.exists( len_file ): - return None - - for line_num, line in len_file_enumerate: - if line_num < low: - continue - if line_num >= high: - break - if line.startswith("#"): - continue - # LEN files have format: - # <chrom_name><tab><chrom_length> - fields = line.split("\t") - chroms[ fields[0] ] = int( fields[1] ) - - # Set flag to indicate whether there are more chroms after list. - next_chroms = False - try: - len_file_enumerate.next() - next_chroms = True - except: - # No more chroms to read. - pass - - to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()] - to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) )) - return { 'reference': self.has_reference_data( trans, dbkey, dbkey_user ), 'chrom_info': to_sort, - 'prev_chroms' : prev_chroms, 'next_chroms' : next_chroms, 'start_index' : start_index } - - def has_reference_data( self, trans, dbkey, dbkey_owner=None ): - """ - Returns true if there is reference data for the specified dbkey. If dbkey is custom, - dbkey_owner is needed to determine if there is reference data. - """ - # Look for key in built-in builds. - if dbkey in self.available_genomes: - # There is built-in reference data. - return True - - # Look for key in owner's custom builds. - if dbkey_owner and 'dbkeys' in dbkey_owner.preferences: - user_keys = from_json_string( dbkey_owner.preferences[ 'dbkeys' ] ) - if dbkey in user_keys: - dbkey_attributes = user_keys[ dbkey ] - if 'fasta' in dbkey_attributes: - # Fasta + converted datasets can provide reference data. - return True - - return False - - def reference( self, trans, dbkey, chrom, low, high, **kwargs ): - """ - Return reference data for a build. - """ - - # If there is no dbkey owner, default to current user. - dbkey_owner, dbkey = decode_dbkey( dbkey ) - if dbkey_owner: - dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() - else: - dbkey_user = trans.user - - if not self.has_reference_data( trans, dbkey, dbkey_user ): - return None - - # - # Get twobit file with reference data. - # - twobit_file_name = None - if dbkey in self.available_genomes: - # Built-in twobit. - twobit_file_name = self.available_genomes[dbkey] - else: - user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) - dbkey_attributes = user_keys[ dbkey ] - fasta_dataset = trans.app.model.HistoryDatasetAssociation.get( dbkey_attributes[ 'fasta' ] ) - error = self._convert_dataset( trans, fasta_dataset, 'twobit' ) - if error: - return error - else: - twobit_dataset = fasta_dataset.get_converted_dataset( trans, 'twobit' ) - twobit_file_name = twobit_dataset.file_name - - # Read and return reference data. - try: - twobit = TwoBitFile( open( twobit_file_name ) ) - if chrom in twobit: - seq_data = twobit[chrom].get( int(low), int(high) ) - return { 'dataset_type': 'refseq', 'data': seq_data } - except IOError: - return None - - ## FIXME: copied from tracks.py (tracks controller) - this should be consolidated when possible. - def _convert_dataset( self, trans, dataset, target_type ): - """ - Converts a dataset to the target_type and returns a message indicating - status of the conversion. None is returned to indicate that dataset - was converted successfully. - """ - - # Get converted dataset; this will start the conversion if necessary. - try: - converted_dataset = dataset.get_converted_dataset( trans, target_type ) - except NoConverterException: - return messages.NO_CONVERTER - except ConverterDependencyException, dep_error: - return { 'kind': messages.ERROR, 'message': dep_error.value } - - # Check dataset state and return any messages. - msg = None - if converted_dataset and converted_dataset.state == model.Dataset.states.ERROR: - job_id = trans.sa_session.query( trans.app.model.JobToOutputDatasetAssociation ) \ - .filter_by( dataset_id=converted_dataset.id ).first().job_id - job = trans.sa_session.query( trans.app.model.Job ).get( job_id ) - msg = { 'kind': messages.ERROR, 'message': job.stderr } - elif not converted_dataset or converted_dataset.state != model.Dataset.states.OK: - msg = messages.PENDING - - return msg - \ No newline at end of file diff -r 1890cb0d1cfbb3ef5a09affcdd18d2b8acf7d811 -r a3ca6efab775b82435770daea85c842617912727 lib/galaxy/web/base/controller.py --- a/lib/galaxy/web/base/controller.py +++ b/lib/galaxy/web/base/controller.py @@ -370,22 +370,6 @@ encoded_id = trans.security.encode_id( vis.id ) return { "vis_id": encoded_id, "url": url_for( action='browser', id=encoded_id ) } - def _get_dbkeys( self, trans ): - """ Returns all valid dbkeys that a user can use in a visualization. """ - - # Read len files. - if not self.len_files: - len_files = glob.glob( os.path.join(trans.app.config.len_file_path, "*.len") ) - self.len_files = [ os.path.split(f)[1].split(".len")[0] for f in len_files ] # get xxx.len - - user_keys = {} - user = trans.get_user() - if 'dbkeys' in user.preferences: - user_keys = from_json_string( user.preferences['dbkeys'] ) - - dbkeys = [ (v, k) for k, v in trans.db_builds if k in self.len_files or k in user_keys ] - return dbkeys - def get_visualization( self, trans, id, check_ownership=True, check_accessible=False ): """ Get a Visualization from the database by id, verifying ownership. """ # Load workflow from database diff -r 1890cb0d1cfbb3ef5a09affcdd18d2b8acf7d811 -r a3ca6efab775b82435770daea85c842617912727 lib/galaxy/web/controllers/tracks.py --- a/lib/galaxy/web/controllers/tracks.py +++ b/lib/galaxy/web/controllers/tracks.py @@ -173,10 +173,6 @@ histories_grid = HistorySelectionGrid() history_datasets_grid = HistoryDatasetsSelectionGrid() tracks_grid = TracksterSelectionGrid() - - def __init__(self, app ): - BaseUIController.__init__( self, app ) - self.genomes = Genomes( self.app ) @web.expose @web.require_login() @@ -188,7 +184,7 @@ @web.expose @web.require_login() def new_browser( self, trans, **kwargs ): - return trans.fill_template( "tracks/new_browser.mako", dbkeys=self._get_dbkeys( trans ), default_dbkey=kwargs.get("default_dbkey", None) ) + return trans.fill_template( "tracks/new_browser.mako", dbkeys=trans.app.genomes.get_dbkeys_with_chrom_info( trans ), default_dbkey=kwargs.get("default_dbkey", None) ) @web.json def add_track_async(self, trans, hda_id=None, ldda_id=None): diff -r 1890cb0d1cfbb3ef5a09affcdd18d2b8acf7d811 -r a3ca6efab775b82435770daea85c842617912727 lib/galaxy/web/controllers/visualization.py --- a/lib/galaxy/web/controllers/visualization.py +++ b/lib/galaxy/web/controllers/visualization.py @@ -377,7 +377,7 @@ from the visualization title, but can be edited. This field must contain only lowercase letters, numbers, and the '-' character.""" ) - .add_select( "visualization_dbkey", "Visualization DbKey/Build", value=visualization_dbkey, options=self._get_dbkeys( trans ), error=None) + .add_select( "visualization_dbkey", "Visualization DbKey/Build", value=visualization_dbkey, options=trans.app.genomes.get_dbkeys_with_chrom_info( trans ), error=None) .add_text( "visualization_annotation", "Visualization annotation", value=visualization_annotation, error=visualization_annotation_err, help="A description of the visualization; annotation is shown alongside published visualizations."), template="visualization/create.mako" ) https://bitbucket.org/galaxy/galaxy-central/changeset/4051e35d4cfd/ changeset: 4051e35d4cfd user: jgoecks date: 2012-06-03 18:19:30 summary: More support for genomes as first-class objects: (a) add genomes API; (b) fix bugs in providing genome data. affected #: 4 files diff -r a3ca6efab775b82435770daea85c842617912727 -r 4051e35d4cfd4f0f692b392553d9d99c9f388724 lib/galaxy/visualization/genomes.py --- a/lib/galaxy/visualization/genomes.py +++ b/lib/galaxy/visualization/genomes.py @@ -107,6 +107,8 @@ # # Get len file. # + + # Look first in user's custom builds. len_file = None len_ds = None user_keys = {} @@ -121,10 +123,11 @@ elif 'len' in dbkey_attributes: len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name + # Look in system builds. if not len_file: len_ds = trans.db_dataset_for( dbkey ) if not len_ds: - len_file = os.path.join( trans.app.config.len_file_path, "%s.len" % dbkey ) + len_file = self.genomes[ dbkey ].len_file else: len_file = len_ds.file_name @@ -203,7 +206,7 @@ dbkey_owner is needed to determine if there is reference data. """ # Look for key in built-in builds. - if dbkey in self.available_genomes: + if dbkey in self.genomes and self.genomes[ dbkey ].twobit_file: # There is built-in reference data. return True diff -r a3ca6efab775b82435770daea85c842617912727 -r 4051e35d4cfd4f0f692b392553d9d99c9f388724 lib/galaxy/web/api/genomes.py --- /dev/null +++ b/lib/galaxy/web/api/genomes.py @@ -0,0 +1,25 @@ +from galaxy import config, tools, web, util +from galaxy.web.base.controller import BaseController, BaseAPIController +from galaxy.util.bunch import Bunch + +class GenomesController( BaseAPIController ): + """ + RESTful controller for interactions with genome data. + """ + + @web.expose_api + def index( self, trans, **kwds ): + """ + GET /api/genomes: returns a list of installed genomes + """ + + return [] + + @web.json + def show( self, trans, id, num=None, chrom=None, low=None ): + """ + GET /api/genomes/{id} + + Returns information about build <id> + """ + return self.app.genomes.chroms( trans, dbkey=id, num=num, chrom=chrom, low=low ) \ No newline at end of file diff -r a3ca6efab775b82435770daea85c842617912727 -r 4051e35d4cfd4f0f692b392553d9d99c9f388724 lib/galaxy/web/buildapp.py --- a/lib/galaxy/web/buildapp.py +++ b/lib/galaxy/web/buildapp.py @@ -132,6 +132,7 @@ webapp.api_mapper.resource_with_deleted( 'quota', 'quotas', path_prefix='/api' ) webapp.api_mapper.resource( 'tool', 'tools', path_prefix='/api' ) webapp.api_mapper.resource_with_deleted( 'user', 'users', path_prefix='/api' ) + webapp.api_mapper.resource( 'genome', 'genomes', path_prefix='/api' ) webapp.api_mapper.resource( 'visualization', 'visualizations', path_prefix='/api' ) webapp.api_mapper.resource( 'workflow', 'workflows', path_prefix='/api' ) webapp.api_mapper.resource_with_deleted( 'history', 'histories', path_prefix='/api' ) diff -r a3ca6efab775b82435770daea85c842617912727 -r 4051e35d4cfd4f0f692b392553d9d99c9f388724 lib/galaxy/web/controllers/tracks.py --- a/lib/galaxy/web/controllers/tracks.py +++ b/lib/galaxy/web/controllers/tracks.py @@ -268,11 +268,11 @@ @web.json def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): - return self.genomes.chroms( trans, dbkey=dbkey, num=num, chrom=chrom, low=low ) + return self.app.genomes.chroms( trans, dbkey=dbkey, num=num, chrom=chrom, low=low ) @web.json def reference( self, trans, dbkey, chrom, low, high, **kwargs ): - return self.genomes.reference( trans, dbkey, chrom, low, high, **kwargs ) + return self.app.genomes.reference( trans, dbkey, chrom, low, high, **kwargs ) @web.json def raw_data( self, trans, dataset_id, chrom, low, high, **kwargs ): @@ -771,7 +771,7 @@ # Get genome info. dbkey = dataset.dbkey - chroms_info = self.genomes.chroms( trans, dbkey=dbkey ) + chroms_info = self.app.genomes.chroms( trans, dbkey=dbkey ) genome = { 'dbkey': dbkey, 'chroms_info': chroms_info } # Get summary tree data for dataset. https://bitbucket.org/galaxy/galaxy-central/changeset/ae4a2de89589/ changeset: ae4a2de89589 user: jgoecks date: 2012-06-03 19:52:12 summary: Enable Genome objects and chromosome information to be dictified. affected #: 1 file diff -r 4051e35d4cfd4f0f692b392553d9d99c9f388724 -r ae4a2de89589270d6d872eef6c99848168a97240 lib/galaxy/visualization/genomes.py --- a/lib/galaxy/visualization/genomes.py +++ b/lib/galaxy/visualization/genomes.py @@ -32,47 +32,12 @@ self.key = key self.len_file = len_file self.twobit_file = twobit_file - - -class Genomes( object ): - """ - Provides information about available genome data and methods for manipulating that data. - """ - - def __init__( self, app ): - # Create list of known genomes from len files. - self.genomes = {} - len_files = glob.glob( os.path.join( app.config.len_file_path, "*.len" ) ) - for f in len_files: - key = os.path.split( f )[1].split( ".len" )[0] - self.genomes[ key ] = Genome( key, len_file=f ) - - # Add genome data (twobit files) to genomes. - for line in open( os.path.join( app.config.tool_data_path, "twobit.loc" ) ): - if line.startswith("#"): continue - val = line.split() - if len( val ) == 2: - key, path = val - if key in self.genomes: - self.genomes[ key ].twobit_file = path - - def get_dbkeys_with_chrom_info( self, trans ): - """ Returns all valid dbkeys that have chromosome information. """ - - # All user keys have a len file. - user_keys = {} - user = trans.get_user() - if 'dbkeys' in user.preferences: - user_keys = from_json_string( user.preferences['dbkeys'] ) - - dbkeys = [ (v, k) for k, v in trans.db_builds if ( ( k in self.genomes and self.genomes[ k ].len_file ) or k in user_keys ) ] - return dbkeys - - def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): + + def to_dict( self, num=None, chrom=None, low=None ): """ - Returns a naturally sorted list of chroms/contigs for a given dbkey. - Use either chrom or low to specify the starting chrom in the return list. + Returns representation of self as a dictionary. """ + def check_int(s): if s.isdigit(): return int(s) @@ -97,47 +62,13 @@ else: low = 0 - # If there is no dbkey owner, default to current user. - dbkey_owner, dbkey = decode_dbkey( dbkey ) - if dbkey_owner: - dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() - else: - dbkey_user = trans.user - - # - # Get len file. - # - - # Look first in user's custom builds. - len_file = None - len_ds = None - user_keys = {} - if dbkey_user and 'dbkeys' in dbkey_user.preferences: - user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) - if dbkey in user_keys: - dbkey_attributes = user_keys[ dbkey ] - if 'fasta' in dbkey_attributes: - build_fasta = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dbkey_attributes[ 'fasta' ] ) - len_file = build_fasta.get_converted_dataset( trans, 'len' ).file_name - # Backwards compatibility: look for len file directly. - elif 'len' in dbkey_attributes: - len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name - - # Look in system builds. - if not len_file: - len_ds = trans.db_dataset_for( dbkey ) - if not len_ds: - len_file = self.genomes[ dbkey ].len_file - else: - len_file = len_ds.file_name - # # Get chroms data: # (a) chrom name, len; # (b) whether there are previous, next chroms; # (c) index of start chrom. # - len_file_enumerate = enumerate( open( len_file ) ) + len_file_enumerate = enumerate( open( self.len_file ) ) chroms = {} prev_chroms = False start_index = 0 @@ -169,11 +100,6 @@ start_index = low # Read chrom data from len file. - # TODO: this may be too slow for very large numbers of chroms/contigs, - # but try it out for now. - if not os.path.exists( len_file ): - return None - for line_num, line in len_file_enumerate: if line_num < low: continue @@ -197,9 +123,99 @@ to_sort = [{ 'chrom': chrom, 'len': length } for chrom, length in chroms.iteritems()] to_sort.sort(lambda a,b: cmp( split_by_number(a['chrom']), split_by_number(b['chrom']) )) - return { 'reference': self.has_reference_data( trans, dbkey, dbkey_user ), 'chrom_info': to_sort, - 'prev_chroms' : prev_chroms, 'next_chroms' : next_chroms, 'start_index' : start_index } + return { + 'id': self.key, + 'reference': self.twobit_file is not None, + 'chrom_info': to_sort, + 'prev_chroms' : prev_chroms, + 'next_chroms' : next_chroms, + 'start_index' : start_index + } + +class Genomes( object ): + """ + Provides information about available genome data and methods for manipulating that data. + """ + + def __init__( self, app ): + # Create list of known genomes from len files. + self.genomes = {} + len_files = glob.glob( os.path.join( app.config.len_file_path, "*.len" ) ) + for f in len_files: + key = os.path.split( f )[1].split( ".len" )[0] + self.genomes[ key ] = Genome( key, len_file=f ) + + # Add genome data (twobit files) to genomes. + for line in open( os.path.join( app.config.tool_data_path, "twobit.loc" ) ): + if line.startswith("#"): continue + val = line.split() + if len( val ) == 2: + key, path = val + if key in self.genomes: + self.genomes[ key ].twobit_file = path + + def get_build( self, dbkey ): + """ Returns build for the given key. """ + rval = None + if dbkey in self.genomes: + rval = self.genomes[ dbkey ] + return rval + + def get_dbkeys_with_chrom_info( self, trans ): + """ Returns all valid dbkeys that have chromosome information. """ + # All user keys have a len file. + user_keys = {} + user = trans.get_user() + if 'dbkeys' in user.preferences: + user_keys = from_json_string( user.preferences['dbkeys'] ) + + dbkeys = [ (v, k) for k, v in trans.db_builds if ( ( k in self.genomes and self.genomes[ k ].len_file ) or k in user_keys ) ] + return dbkeys + + def chroms( self, trans, dbkey=None, num=None, chrom=None, low=None ): + """ + Returns a naturally sorted list of chroms/contigs for a given dbkey. + Use either chrom or low to specify the starting chrom in the return list. + """ + + # If there is no dbkey owner, default to current user. + dbkey_owner, dbkey = decode_dbkey( dbkey ) + if dbkey_owner: + dbkey_user = trans.sa_session.query( trans.app.model.User ).filter_by( username=dbkey_owner ).first() + else: + dbkey_user = trans.user + + # + # Get/create genome object. + # + genome = None + + # Look first in user's custom builds. + if dbkey_user and 'dbkeys' in dbkey_user.preferences: + user_keys = from_json_string( dbkey_user.preferences['dbkeys'] ) + if dbkey in user_keys: + dbkey_attributes = user_keys[ dbkey ] + if 'fasta' in dbkey_attributes: + build_fasta = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( dbkey_attributes[ 'fasta' ] ) + len_file = build_fasta.get_converted_dataset( trans, 'len' ).file_name + # Backwards compatibility: look for len file directly. + elif 'len' in dbkey_attributes: + len_file = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( user_keys[ dbkey ][ 'len' ] ).file_name + if len_file: + genome = Genome( dbkey, len_file=len_file ) + + + # Look in system builds. + if not genome: + len_ds = trans.db_dataset_for( dbkey ) + if not len_ds: + genome = self.genomes[ dbkey ] + else: + gneome = Genome( dbkey, len_file=len_ds.file_name ) + + return genome.to_dict( num=num, chrom=chrom, low=low ) + def has_reference_data( self, trans, dbkey, dbkey_owner=None ): """ Returns true if there is reference data for the specified dbkey. If dbkey is custom, Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.