Merge branch 'dev' into feature/k8s_job_runner

This commit is contained in:
Pablo Moreno
2016-06-01 16:45:22 +02:00
131 changed files with 1586 additions and 992 deletions
+70 -39
View File
@@ -41,45 +41,82 @@ return Backbone.View.extend({
}).on( 'show hide ', function() {
self.buttonLoad.set( { 'toggle': this.visible, 'icon': this.visible && 'fa-eye' || 'fa-eye-slash' } );
});
this.history_cache = {};
},
/** Add a dataset to the frames */
addDataset: function( dataset_id ) {
var self = this;
var current_dataset = null;
if ( Galaxy && Galaxy.currHistoryPanel ) {
var history_id = Galaxy.currHistoryPanel.collection.historyId;
this.history_cache[ history_id ] = { name: Galaxy.currHistoryPanel.model.get( 'name' ), dataset_ids: [] };
Galaxy.currHistoryPanel.collection.each( function( model ) {
!model.get( 'deleted' ) && model.get( 'visible' ) && self.history_cache[ history_id ].dataset_ids.push( model.get( 'id' ) );
});
}
var _findDataset = function( dataset, offset ) {
if ( dataset ) {
var history_details = self.history_cache[ dataset.get( 'history_id' ) ];
if ( history_details && history_details.dataset_ids ) {
var dataset_list = history_details.dataset_ids;
var pos = dataset_list.indexOf( dataset.get( 'id' ) );
if ( pos !== -1 && pos + offset >= 0 && pos + offset < dataset_list.length ) {
return dataset_list[ pos + offset ];
}
}
}
};
var _loadDatasetOffset = function( dataset, offset, frame ) {
var new_dataset_id = _findDataset( dataset, offset );
if ( new_dataset_id ) {
self._loadDataset( new_dataset_id, function( new_dataset, config ) {
current_dataset = new_dataset;
frame.model.set( config );
});
} else {
frame.model.trigger( 'change' );
}
}
this._loadDataset( dataset_id, function( dataset, config ) {
current_dataset = dataset;
self.add( _.extend( { menu: [ { icon : 'fa fa-chevron-circle-left',
tooltip : 'Previous in History',
onclick : function( frame ) { _loadDatasetOffset( current_dataset, -1, frame ) },
disabled : function() { return !_findDataset( current_dataset, -1 ) } },
{ icon : 'fa fa-chevron-circle-right',
tooltip : 'Next in History',
onclick : function( frame ) { _loadDatasetOffset( current_dataset, 1, frame ) },
disabled : function() { return !_findDataset( current_dataset, 1 ) } } ] }, config ) )
});
},
_loadDataset: function( dataset_id, callback ) {
var self = this;
require([ 'mvc/dataset/data' ], function( DATA ) {
var dataset = new DATA.Dataset( { id : dataset_id } );
$.when( dataset.fetch() ).then( function() {
// Construct frame config based on dataset's type.
var frame_config = {
title: dataset.get('name')
},
// HACK: For now, assume 'tabular' and 'interval' are the only
// modules that contain tabular files. This needs to be replaced
// will a is_datatype() function.
is_tabular = _.find( [ 'tabular', 'interval' ] , function( data_type ) {
return dataset.get( 'data_type' ).indexOf( data_type ) !== -1;
});
// Use tabular chunked display if dataset is tabular; otherwise load via URL.
if ( is_tabular ) {
var tabular_dataset = new DATA.TabularDataset( dataset.toJSON() );
_.extend( frame_config, {
content: function( parent_elt ) {
DATA.createTabularDatasetChunkedView({
model : tabular_dataset,
parent_elt : parent_elt,
embedded : true,
height : '100%'
});
}
});
var is_tabular = _.find( [ 'tabular', 'interval' ] , function( data_type ) {
return dataset.get( 'data_type' ).indexOf( data_type ) !== -1;
});
var title = dataset.get( 'name' );
var history_details = self.history_cache[ dataset.get( 'history_id' ) ];
if ( history_details ) {
title = history_details.name + ': ' + title;
}
else {
_.extend( frame_config, {
url: Galaxy.root + 'datasets/' + dataset.id + '/display/?preview=True'
});
}
self.add( frame_config );
callback( dataset, is_tabular ? {
title : title,
url : null,
content : DATA.createTabularDatasetChunkedView({
model : new DATA.TabularDataset( dataset.toJSON() ),
embedded : true,
height : '100%'
}).$el
} : {
title : title,
url : Galaxy.root + 'datasets/' + dataset_id + '/display/?preview=True',
content : null
} );
});
});
},
@@ -136,15 +173,9 @@ return Backbone.View.extend({
window.location = options.url;
} else if ( !this.active ) {
var $galaxy_main = $( window.parent.document ).find( '#galaxy_main' );
if ( options.target == 'galaxy_main' || options.target == 'center' ){
if ( $galaxy_main.length === 0 ){
var href = options.url;
if ( href.indexOf( '?' ) == -1 )
href += '?';
else
href += '&';
href += 'use_panels=True';
window.location = href;
if ( options.target == 'galaxy_main' || options.target == 'center' ) {
if ( $galaxy_main.length === 0 ) {
window.location = options.url + ( href.indexOf( '?' ) == -1 ? '?' : '&' ) + 'use_panels=True';
} else {
$galaxy_main.attr( 'src', options.url );
}
@@ -435,6 +435,7 @@ var ControlledFetchMixin = {
_.each( filters, function( v, k ){
if( v === true ){ v = 'True'; }
if( v === false ){ v = 'False'; }
if( v === null ){ v = 'None'; }
filterMap.q.push( k );
filterMap.qv.push( v );
});
@@ -522,6 +523,11 @@ var HistoryCollection = Backbone.Collection
deleted : false,
purged : false,
};
} else {
defaults.filters = {
// TODO: for bypassing defaults on current API
deleted : null,
};
}
return defaults;
},
@@ -1,46 +1,40 @@
/**
This is the run workflow tool form.
*/
define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-data', 'mvc/tool/tool-form-base' ],
function( Utils, Ui, Form, FormData, ToolFormBase ) {
/** This is the run workflow tool form view. */
define([ 'utils/utils', 'utils/deferred', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-data', 'mvc/tool/tool-form-base' ],
function( Utils, Deferred, Ui, Form, FormData, ToolFormBase ) {
var View = Backbone.View.extend({
initialize: function( options ) {
this.model = options && options.model || new Backbone.Model( options );
this.deferred = new Deferred();
this.setElement( $( '<div/>' ).addClass( 'ui-form-composite' )
.append( this.$message = $( '<div/>' ) )
.append( this.$header = $( '<div/>' ) )
.append( this.$parameters = $( '<div/>' ) )
.append( this.$steps = $( '<div/>' ) )
.append( this.$history = $( '<div/>' ) )
.append( this.$execute = $( '<div/>' ) ) );
$( 'body' ).append( this.$el );
this._configure();
this.render();
},
/** Configures form/step options for each workflow step */
_configure: function() {
var self = this;
this.workflow_id = options.id;
this.forms = [];
this.steps = [];
this.links = [];
// initialize elements
this.setElement( '<div class="ui-form-composite"/>' );
this.$header = $( '<div/>' ).addClass( 'ui-form-header' );
this.$header.append( new Ui.Label({
title : 'Workflow: ' + options.name
}).$el );
this.$header.append( new Ui.Button({
title : 'Collapse',
icon : 'fa-angle-double-up',
onclick : function() { _.each( self.forms, function( form ) { form.portlet.collapse() }) }
}).$el );
this.$header.append( new Ui.Button({
title : 'Expand all',
icon : 'fa-angle-double-down',
onclick : function() { _.each( self.forms, function( form ) { form.portlet.expand() }) }
}).$el );
this.$el.append( this.$header );
// initialize steps and configure connections
_.each( options.steps, function( step, i ) {
this.parms = [];
_.each( this.model.get( 'steps' ), function( step, i ) {
Galaxy.emit.debug( 'tool-form-composite::initialize()', i + ' : Preparing workflow step.' );
step = Utils.merge( {
index : i,
name : 'Step ' + ( parseInt( i ) + 1 ) + ': ' + step.name,
icon : '',
help : null,
description : step.annotation && ' - ' + step.annotation || step.description,
citations : null,
needs_update : true,
collapsible : true,
collapsed : i > 0,
collapsed : i > 0 && !self._isDataStep( step ),
sustain_version : true,
sustain_repeats : true,
sustain_conditionals : true,
@@ -48,155 +42,256 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-d
text_enable : 'Edit',
text_disable : 'Undo',
cls_enable : 'fa fa-edit',
cls_disable : 'fa fa-undo'
cls_disable : 'fa fa-undo',
errors : step.messages,
initial_errors : true
}, step );
// convert all connected data inputs to hidden fields with proper labels
_.each( options.steps, function( sub_step ) {
self.steps[ i ] = step;
self.links[ i ] = [];
self.parms[ i ] = {}
});
// build linear index of step input pairs
_.each( this.steps, function( step, i ) {
FormData.visitInputs( step.inputs, function( input, name ) {
self.parms[ i ][ name ] = input;
});
});
// iterate through data input modules and collect linked sub steps
_.each( this.steps, function( step, i ) {
_.each( step.output_connections, function( output_connection ) {
_.each( self.steps, function( sub_step, j ) {
sub_step.step_id === output_connection.input_step_id && self.links[ i ].push( sub_step );
});
});
});
// convert all connected data inputs to hidden fields with proper labels,
// and track the linked source step
_.each( this.steps, function( step, i ) {
_.each( self.steps, function( sub_step, j ) {
var connections_by_name = {};
_.each( step.output_connections, function( connection ) {
sub_step.step_id === connection.input_step_id && ( connections_by_name[ connection.input_name ] = connection );
});
FormData.matchIds( sub_step.inputs, connections_by_name, function( connection, input ) {
if ( !input.linked ) {
input.linked = step.step_type;
_.each( self.parms[ j ], function( input, name ) {
var connection = connections_by_name[ name ];
if ( connection ) {
input.type = 'hidden';
input.help = '';
} else {
input.help += ', ';
}
input.help += 'Output dataset \'' + connection.output_name + '\' from step ' + ( parseInt( i ) + 1 );
});
});
self.steps[ i ] = step;
self.links[ i ] = [];
});
// finalize configuration and build forms
_.each( self.steps, function( step, i ) {
var form = null;
if ( String( step.step_type ).startsWith( 'data' ) ) {
form = new Form( Utils.merge({
title : '<b>' + step.name + '</b>',
onchange: function() {
var input_value = form.data.create().input;
_.each( self.links[ i ], function( link ) {
link.input.value ( input_value );
link.form.trigger( 'change' );
});
}
}, step ));
} else if ( step.step_type == 'tool' ) {
// select fields are shown for dynamic fields if all putative data inputs are available
function visitInputs( inputs, data_resolved ) {
data_resolved === undefined && ( data_resolved = true );
_.each( inputs, function ( input ) {
if ( _.isObject( input ) ) {
if ( input.type ) {
var is_data_input = [ 'data', 'data_collection' ].indexOf( input.type ) !== -1;
var is_workflow_parameter = self._isWorkflowParameter( input.value );
is_data_input && input.linked && !input.linked.startsWith( 'data' ) && ( data_resolved = false );
input.options && ( ( input.options.length == 0 && !data_resolved ) || is_workflow_parameter ) && ( input.is_workflow = true );
input.value && input.value.__class__ == 'RuntimeValue' && ( input.value = null );
if ( !is_data_input && input.type !== 'hidden' && !is_workflow_parameter ) {
if ( input.optional || ( !Utils.isEmpty( input.value ) && input.value !== '' ) ) {
input.collapsible_value = input.value;
input.collapsible_preview = true;
}
}
}
visitInputs( input, data_resolved );
}
});
};
visitInputs( step.inputs );
// or if a particular reference is specified and available
FormData.matchContext( step.inputs, 'data_ref', function( input, reference ) {
input.is_workflow = ( reference.linked && !reference.linked.startsWith( 'data' ) ) || self._isWorkflowParameter( input.value );
});
form = new ToolFormBase( step );
}
self.forms[ i ] = form;
});
// create index of data output links
_.each( this.steps, function( step, i ) {
_.each( step.output_connections, function( output_connection ) {
_.each( self.forms, function( form ) {
if ( form.options.step_id === output_connection.input_step_id ) {
var matched_input = form.field_list[ form.data.match( output_connection.input_name ) ];
matched_input && self.links[ i ].push( { input: matched_input, form: form } );
input.help = input.step_linked ? input.help + ', ' : '';
input.help += 'Output dataset \'' + connection.output_name + '\' from step ' + ( parseInt( i ) + 1 );
input.step_linked = input.step_linked || [];
input.step_linked.push( step );
}
});
});
});
// build workflow parameters
var wp_fields = {};
var wp_inputs = {};
// identify and configure workflow parameters
var wp_count = 0;
var wp_style = function( wp_field, wp_color, wp_cls ) {
var $wp_input = wp_field.$( 'input' );
$wp_input.length === 0 && ( $wp_input = wp_field.$el );
$wp_input.addClass( wp_cls ).css({ 'color': wp_color, 'border-color': wp_color });
this.wp_inputs = {};
function _handleWorkflowParameter( value, callback ) {
var wp_name = self._isWorkflowParameter( value );
wp_name && callback( self.wp_inputs[ wp_name ] = self.wp_inputs[ wp_name ] || {
label : wp_name,
name : wp_name,
type : 'text',
color : 'hsl( ' + ( ++wp_count * 100 ) + ', 70%, 30% )',
style : 'ui-form-wp-source',
links : []
});
}
_.each( this.steps, function( step, i ) {
_.each( step.inputs, function( input ) {
var wp_name = self._isWorkflowParameter( input.value );
if ( wp_name ) {
var wp_field = self.forms[ i ].field_list[ input.id ];
var wp_element = self.forms[ i ].element_list[ input.id ];
wp_fields[ wp_name ] = wp_fields[ wp_name ] || [];
wp_fields[ wp_name ].push( wp_field );
wp_field.value( wp_name );
wp_element.disable( true );
wp_inputs[ wp_name ] = wp_inputs[ wp_name ] || {
type : input.type,
is_workflow : input.options,
label : wp_name,
name : wp_name,
color : 'hsl( ' + ( ++wp_count * 100 ) + ', 70%, 30% )'
};
wp_style( wp_field, wp_inputs[ wp_name ].color, 'ui-form-wp-target' );
}
_.each( self.parms[ i ], function( input, name ) {
_handleWorkflowParameter( input.value, function( wp_input ) {
wp_input.links.push( step );
input.wp_linked = wp_input.name;
input.color = wp_input.color;
input.type = 'text';
input.value = null;
input.backdrop = true;
input.style = 'ui-form-wp-target';
});
});
_.each( step.post_job_actions, function( pja ) {
_.each( pja.action_arguments, function( arg ) {
_handleWorkflowParameter( arg, function() {} );
});
});
});
if ( !_.isEmpty( wp_inputs ) ) {
var wp_form = new Form({ title: '<b>Workflow Parameters</b>', inputs: wp_inputs, onchange: function() {
_.each( wp_form.data.create(), function( wp_value, wp_name ) {
_.each( wp_fields[ wp_name ], function( wp_field ) {
wp_field.value( Utils.sanitize( wp_value ) || wp_name );
// select fields are shown for dynamic fields if all putative data inputs are available,
// or if an explicit reference is specified as data_ref and available
_.each( this.steps, function( step, i ) {
if ( step.step_type == 'tool' ) {
var data_resolved = true;
FormData.visitInputs( step.inputs, function ( input, name, context ) {
var is_data_input = ([ 'data', 'data_collection' ]).indexOf( input.type ) != -1;
var data_ref = context[ input.data_ref ];
input.step_linked && !self._isDataStep( input.step_linked ) && ( data_resolved = false );
input.options && ( ( input.options.length == 0 && !data_resolved ) || input.wp_linked ) && ( input.is_workflow = true );
data_ref && ( input.is_workflow = ( data_ref.step_linked && !self._isDataStep( data_ref.step_linked ) ) || input.wp_linked );
( is_data_input || ( input.value && input.value.__class__ == 'RuntimeValue' && !input.step_linked ) ) && ( step.collapsed = false );
input.value && input.value.__class__ == 'RuntimeValue' && ( input.value = null );
input.flavor = 'workflow';
if ( !is_data_input && input.type !== 'hidden' && !input.wp_linked ) {
if ( input.optional || ( !Utils.isEmpty( input.value ) && input.value !== '' ) ) {
input.collapsible_value = input.value;
input.collapsible_preview = true;
}
}
});
}
});
},
render: function() {
var self = this;
this.deferred.reset();
this._renderHeader();
this._renderMessage();
this._renderParameters();
this._renderHistory();
_.each ( this.steps, function( step, i ) { self._renderStep( step, i ) } );
this.deferred.execute( function() { self._renderExecute() } );
},
/** Render header */
_renderHeader: function() {
var self = this;
this.$header.addClass( 'ui-form-header' ).empty()
.append( new Ui.Label({
title : 'Workflow: ' + this.model.get( 'name' ) }).$el )
.append( new Ui.Button({
title : 'Collapse',
icon : 'fa-angle-double-up',
onclick : function() { _.each( self.forms, function( form ) { form.portlet.collapse() }) } }).$el )
.append( new Ui.Button({
title : 'Expand all',
icon : 'fa-angle-double-down',
onclick : function() { _.each( self.forms, function( form ) { form.portlet.expand() }) } }).$el );
},
/** Render message */
_renderMessage: function() {
this.$message.empty();
if ( this.model.get( 'has_upgrade_messages' ) ) {
this.$message.append( new Ui.Message( {
message : 'Some tools in this workflow may have changed since it was last saved or some errors were found. The workflow may still run, but any new options will have default values. Please review the messages below to make a decision about whether the changes will affect your analysis.',
status : 'warning',
persistent : true
} ).$el );
}
},
/** Render workflow parameters */
_renderParameters: function() {
var self = this;
this.wp_form = null;
if ( !_.isEmpty( this.wp_inputs ) ) {
this.wp_form = new Form({ title: '<b>Workflow Parameters</b>', inputs: this.wp_inputs, onchange: function() {
_.each( self.wp_form.input_list, function( input_def, i ) {
_.each( input_def.links, function( step ) {
self._refreshStep( step );
});
});
}});
_.each( wp_form.field_list, function( wp_field, i ) {
wp_style( wp_field, wp_form.input_list[ i ].color, 'ui-form-wp-source' );
});
this.$el.append( '<p/>' ).addClass( 'ui-margin-top' );
this.$el.append( wp_form.$el );
this._append( this.$parameters.empty(), this.wp_form.$el );
}
},
// append elements
_.each( this.steps, function( step, i ) {
var form = self.forms[ i ];
self.$el.append( '<p/>' ).addClass( 'ui-margin-top' ).append( form.$el );
if ( step.post_job_actions && step.post_job_actions.length ) {
form.portlet.append( $( '<div/>' ).addClass( 'ui-form-footer-info fa fa-bolt' ).append(
_.reduce( step.post_job_actions, function( memo, value ) {
return memo + ' ' + value.short_str;
}, '' ))
);
/** Render step */
_renderStep: function( step, i ) {
var self = this;
var form = null;
var current = null;
this.deferred.execute( function( promise ) {
current = promise;
if ( self._isDataStep( step ) ) {
_.each( step.inputs, function( input ) { input.flavor = 'module' } );
form = new Form( Utils.merge({
title : '<b>' + step.name + '</b>',
onchange : function() { _.each( self.links[ i ], function( link ) { self._refreshStep( link ) } ) }
}, step ) );
self._append( self.$steps, form.$el );
} else if ( step.step_type == 'tool' ) {
form = new ToolFormBase( step );
if ( step.post_job_actions && step.post_job_actions.length ) {
form.portlet.append( $( '<div/>' ).addClass( 'ui-form-element-disabled' )
.append( $( '<div/>' ).addClass( 'ui-form-title' ).html( 'Job Post Actions' ) )
.append( $( '<div/>' ).addClass( 'ui-form-preview' ).html(
_.reduce( step.post_job_actions, function( memo, value ) {
return memo + ' ' + value.short_str;
}, '' ) ) )
);
}
self._append( self.$steps, form.$el );
}
self.forms[ i ] = form;
self._refreshStep( step );
Galaxy.emit.debug( 'tool-form-composite::initialize()', i + ' : Workflow step state ready.', step );
});
self._resolve( form.deferred, promise );
} );
},
// add history form
/** This helps with rendering lazy loaded steps */
_resolve: function( deferred, promise ) {
var self = this;
setTimeout( function() {
if ( deferred && deferred.ready() || !deferred ) {
promise.resolve();
} else {
self._resolve( deferred, promise );
}
}, 0 );
},
/** Refreshes step values from source step values */
_refreshStep: function( step ) {
var self = this;
var form = this.forms[ step.index ];
if ( form ) {
_.each( self.parms[ step.index ], function( input, name ) {
if ( input.step_linked || input.wp_linked ) {
var field = form.field_list[ form.data.match( name ) ];
if ( field ) {
var new_value = undefined;
if ( input.step_linked ) {
new_value = { values: [] };
_.each( input.step_linked, function( source_step ) {
if ( self._isDataStep( source_step ) ) {
value = self.forms[ source_step.index ].data.create().input;
value && _.each( value.values, function( v ) { new_value.values.push( v ) } );
}
});
if ( !input.multiple && new_value.values.length > 0 ) {
new_value = { values: [ new_value.values[ 0 ] ] };
}
} else if ( input.wp_linked ) {
var wp_field = self.wp_form.field_list[ self.wp_form.data.match( input.wp_linked ) ];
wp_field && ( new_value = wp_field.value() );
}
if ( new_value !== undefined ) {
field.value( new_value );
}
}
}
});
form.trigger( 'change' );
}
},
/** Render history form */
_renderHistory: function() {
this.history_form = null;
if ( !options.history_id ) {
if ( !this.model.get( 'history_id' ) ) {
this.history_form = new Form({
inputs : [{
type : 'conditional',
name : 'new_history',
test_param : {
name : 'new_history',
name : 'check',
label : 'Send results to a new history',
type : 'boolean',
value : 'false',
@@ -205,20 +300,21 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-d
cases : [{
value : 'true',
inputs : [{
name : 'new_history_name',
name : 'name',
label : 'History name',
type : 'text',
value : options.name
value : this.model.get( 'name' )
}]
}]
}]
});
this.$el.append( '<p/>' ).addClass( 'ui-margin-top' );
this.$el.append( this.history_form.$el );
this._append( this.$history.empty(), this.history_form.$el );
}
},
// add execute button
this.$el.append( '<p/>' ).addClass( 'ui-margin-top' );
/** Render execute button */
_renderExecute: function() {
var self = this;
this.execute_btn = new Ui.Button({
icon : 'fa-check',
title : 'Run workflow',
@@ -226,81 +322,84 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-d
floating : 'clear',
onclick : function() { self._execute() }
});
this.$el.append( this.execute_btn.$el );
$( 'body' ).append( this.$el );
this._append( this.$execute.empty(), this.execute_btn.$el );
},
/** Execute workflow
*/
/** Execute workflow */
_execute: function() {
var self = this;
var job_def = {
inputs : {},
parameters : {}
new_history_name : this.history_form.data.create()[ 'new_history|name' ],
wf_parm : this.wp_form ? this.wp_form.data.create() : {},
inputs : {}
};
var validated = true;
_.each( this.forms, function( form, i ) {
for ( var i in this.forms ) {
var form = this.forms[ i ];
var job_inputs = form.data.create();
var step = self.steps[ i ];
var step_id = step.step_id;
var step_type = step.step_type;
var order_index = step.order_index;
job_def.parameters[ step_id ] = {};
form.trigger( 'reset' );
for ( var job_input_id in job_inputs ) {
var input_value = job_inputs[ job_input_id ];
var input_id = form.data.match( job_input_id );
var input_field = form.field_list[ input_id ];
var input_def = form.input_list[ input_id ];
if ( String( step_type ).startsWith( 'data' ) ) {
if ( input_value && input_value.values && input_value.values.length > 0 ) {
job_def.inputs[ order_index ] = input_value.values[ 0 ];
} else if ( validated ) {
if ( !input_def.step_linked ) {
if ( this._isDataStep( step ) ) {
validated = input_value && input_value.values && input_value.values.length > 0;
} else {
validated = input_def.optional || ( input_def.is_workflow && input_value !== '' ) || ( !input_def.is_workflow && input_value !== null );
}
if ( !validated ) {
form.highlight( input_id );
validated = false;
}
} else {
if ( !String( input_def.type ).startsWith( 'data' ) ) {
if ( input_def.optional || input_def.is_workflow || input_value != null ) {
job_def.parameters[ step_id ][ job_input_id ] = input_value;
} else {
form.highlight( input_id );
validated = false;
}
break;
}
job_def.inputs[ step_id ] = job_def.inputs[ step_id ] || {};
job_def.inputs[ step_id ][ job_input_id ] = job_inputs[ job_input_id ];
}
}
});
console.log( JSON.stringify( job_def ) );
if ( !validated ) {
break;
}
}
if ( !validated ) {
self._enabled( true );
Galaxy.emit.debug( 'tool-form-composite::submit()', 'Validation failed.', job_def );
} else {
self._enabled( false );
Galaxy.emit.debug( 'tools-form-composite::submit()', 'Validation complete.', job_def );
Galaxy.emit.debug( 'tool-form-composite::submit()', 'Validation complete.', job_def );
Utils.request({
type : 'POST',
url : Galaxy.root + 'api/workflows/' + this.workflow_id + '/invocations',
data : job_def,
success : function( response ) {
Galaxy.emit.debug( 'tool-form-composite::submit', 'Submission successful.', response );
self.$el.empty().append( self._templateSuccess( response ) );
parent.Galaxy && parent.Galaxy.currHistoryPanel && parent.Galaxy.currHistoryPanel.refreshContents();
console.log( response );
},
error : function( response ) {
console.log( response );
Galaxy.emit.debug( 'tool-form-composite::submit', 'Submission failed.', response );
if ( response && response.err_data ) {
var error_messages = form.data.matchResponse( response.err_data );
for ( var input_id in error_messages ) {
form.highlight( input_id, error_messages[ input_id ] );
break;
for ( var i in self.forms ) {
var form = self.forms[ i ];
var step_related_errors = response.err_data[ form.options.step_id ];
if ( step_related_errors ) {
var error_messages = form.data.matchResponse( step_related_errors );
for ( var input_id in error_messages ) {
form.highlight( input_id, error_messages[ input_id ] );
break;
}
}
}
} else {
Galaxy.modal && Galaxy.modal.show({
var modal = parent.Galaxy.modal;
modal && modal.show({
title : 'Job submission failed',
body : ( response && response.err_msg ) || ToolTemplate.error( options.job_def ),
body : self._templateError( response && response.err_msg || job_def ),
buttons : {
'Close' : function() {
Galaxy.modal.hide();
modal.hide();
}
}
});
@@ -313,23 +412,69 @@ define([ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-d
}
},
/** Set enabled/disabled state
*/
/** Append new dom to body */
_append: function( $container, $el ) {
$container.append( '<p/>' ).addClass( 'ui-margin-top' ).append( $el );
},
/** Set enabled/disabled state */
_enabled: function( enabled ) {
if ( enabled ) { this.execute_btn.unwait() } else { this.execute_btn.wait() }
if ( enabled ) { this.history_form.portlet.enable() } else { this.history_form.portlet.disable() }
_.each( this.forms, function( form ) { if ( enabled ) { form.portlet.enable() } else { form.portlet.disable() } });
},
/** Handle workflow parameter
*/
/** Handle workflow parameter */
_isWorkflowParameter: function( value ) {
if ( String( value ).substring( 0, 1 ) === '$' ) {
return Utils.sanitize( value.substring( 2, value.length - 1 ) )
}
},
/** Is data input module/step */
_isDataStep: function( steps ) {
lst = $.isArray( steps ) ? steps : [ steps ] ;
for ( var i = 0; i < lst.length; i++ ) {
var step = lst[ i ];
if ( !step || !step.step_type || !step.step_type.startsWith( 'data' ) ) {
return false;
}
}
return true;
},
/** Templates */
_templateSuccess: function( response ) {
if ( response && response.length > 0 ) {
var $message = $( '<div/>' ).addClass( 'donemessagelarge' )
.append( $( '<p/>' ).text( 'Successfully ran workflow \'' + this.model.get( 'name' ) + '\'. The following datasets have been added to the queue:' ) );
for ( var i in response ) {
var invocation = response[ i ];
var $invocation = $( '<div/>' ).addClass( 'workflow-invocation-complete' );
invocation.history && $invocation.append( $( '<p/>' ).text( 'These datasets will appear in a new history: ' )
.append( $( '<a/>' ).addClass( 'new-history-link' )
.attr( 'data-history-id', invocation.history.id )
.attr( 'target', '_top' )
.attr( 'href', '/history/switch_to_history?hist_id=' + invocation.history.id )
.text( invocation.history.name ) ) );
_.each( invocation.outputs, function( output ) {
$invocation.append( $( '<div/>' ).addClass( 'messagerow' ).html( '<b>' + output.hid + '</b>: ' + output.name ) );
});
$message.append( $invocation );
}
return $message;
} else {
return this._templateError( response );
}
},
_templateError: function( response ) {
return $( '<div/>' ).addClass( 'errormessagelarge' )
.append( $( '<p/>' ).text( 'The server could not complete the request. Please contact the Galaxy Team if this error persists.' ) )
.append( $( '<pre/>' ).text( JSON.stringify( response, null, 4 ) ) );
}
});
return {
View: View
};
});
});
+98 -102
View File
@@ -1,50 +1,91 @@
/** Scratchbook viewer */
define([], function() {
/** Frame view */
var FrameView = Backbone.View.extend({
initialize: function( options ) {
var self = this;
this.model = options && options.model || new Backbone.Model( options );
this.setElement( $( '<div/>' ).addClass( 'corner frame' ) );
this.$el.append( $( '<div/>' ).addClass( 'f-header corner' )
.append( $( '<div/>' ).addClass( 'f-title' ) )
.append( $( '<div/>' ).addClass( 'f-icon f-close fa fa-close' )
.tooltip( { title: 'Close', placement: 'bottom' } ) ) )
.append( $( '<div/>' ).addClass( 'f-content' ) )
.append( $( '<div/>' ).addClass( 'f-resize f-icon corner fa fa-expand' ).tooltip( { title: 'Resize' } ) )
.append( $( '<div/>' ).addClass( 'f-cover' ) );
this.$header = this.$( '.f-header' );
this.$title = this.$( '.f-title' );
this.$content = this.$( '.f-content' );
this.render();
this.listenTo( this.model, 'change', this.render, this );
},
render: function() {
var self = this;
var options = this.model.attributes;
this.$title.html( options.title || '' );
this.$header.find( '.f-icon-left' ).remove();
_.each( options.menu, function( option ) {
var $option = $( '<div/>' ).addClass( 'f-icon-left' ).addClass( option.icon );
if ( _.isFunction( option.disabled ) && option.disabled() ) {
$option.attr( 'disabled', true );
} else {
$option.on( 'click', function() { option.onclick( self ) } )
.tooltip( { title: option.tooltip, placement: 'bottom' } );
}
self.$header.append( $option );
} );
if ( options.url ) {
this.$content.html( $ ( '<iframe/>' ).addClass( 'f-iframe' )
.attr( 'scrolling', 'auto' )
.attr( 'src', options.url + ( options.url.indexOf( '?' ) === -1 ? '?' : '&' ) + 'widget=True' ) );
} else if ( options.content ) {
_.isFunction( options.content ) ? options.content( self.$content ) : self.$content.html( options.content );
}
}
});
/** Scratchbook viewer */
var View = Backbone.View.extend({
defaultOptions: {
frame: { // default frame size in cells
frame: { // default frame size in cells
cols : 6,
rows : 3
},
rows : 1000, // maximum number of rows
cell : 130, // cell size in px
margin : 5,
scroll : 5, // scroll speed
top_min : 40, // top margin
frame_max : 9, // maximum number of frames
visible : true, // initial visibility
rows : 1000, // maximum number of rows
cell : 130, // cell size in px
margin : 5, // margin between frames
scroll : 5, // scroll speed
top_min : 40, // top margin
frame_max : 9, // maximum number of frames
visible : true, // initial visibility
},
cols : 0, // number of columns
top : 0, // scroll/element top
top_max : 0, // viewport scrolling state
frame_z : 0, // frame z-index
frame_counter : 0, // frame counter
frame_uid : 0,
frame_list : {}, // list of all frames
frame_shadow : null,
visible : false,
event : {},
cols : 0, // number of columns
top : 0, // scroll/element top
top_max : 0, // viewport scrolling state
frame_z : 0, // frame z-index
frame_counter : 0, // frame counter
frame_uid : 0, // unique frame id counter
frame_list : {}, // list of all frames
frame_shadow : null, // frame shown as placeholder when moving active frames
visible : false, // flag indicating if scratchbook viewer is visible or not
event : {}, // dictionary keeping track of current event
initialize : function( options ) {
var self = this;
this.options = _.defaults( options || {}, this.defaultOptions );
this.visible = this.options.visible;
this.top = this.top_max = this.options.top_min;
this.setElement( $( '<div/>' ).addClass( 'galaxy-frame' ) );
this.$el.append( $( '<div/>' ).addClass( 'frame-background' ) );
this.$el.append( $( '<div/>' ).addClass( 'frame-menu frame-scroll-up fa fa-chevron-up fa-2x' ) );
this.$el.append( $( '<div/>' ).addClass( 'frame-menu frame-scroll-down fa fa-chevron-down fa-2x' ) );
this.$el.append( $( '<div/>' ).addClass( 'frame-shadow corner' ).attr( 'id', 'frame-shadow' ) );
this.setElement( $( '<div/>' ).addClass( 'galaxy-frame' )
.append( $( '<div/>' ).addClass( 'frame-background' ) )
.append( $( '<div/>' ).addClass( 'frame-menu frame-scroll-up fa fa-chevron-up fa-2x' ) )
.append( $( '<div/>' ).addClass( 'frame-menu frame-scroll-down fa fa-chevron-down fa-2x' ) ) );
// initialize shadow to guiding drag/resize events
this.frame_shadow = {
id : '#frame-shadow',
screen_location : {},
grid_location : {},
grid_rank : null,
grid_lock : false
};
this.frame_shadow = new Backbone.View({ el: $( '<div/>' ).addClass( 'corner frame-shadow' ) } );
this.$el.append( this.frame_shadow.$el );
this._frameInit( this.frame_shadow, '#frame-shadow' );
this._frameResize( this.frame_shadow, { width: 0, height: 0 } );
this.frame_list[ '#frame-shadow' ] = this.frame_shadow;
@@ -87,38 +128,18 @@ var View = Backbone.View.extend({
} else {
// initialize new frame elements
this.top = this.options.top_min;
var $frame_el = $( this._frameTemplate( frame_id.substring( 1 ), options.title ) );
var $frame_content = $frame_el.find( '.f-content' );
this.$el.append( $frame_el );
// configure content
if ( options.url ) {
$frame_content.append(
$ ( '<iframe/>' ).addClass( 'f-iframe' )
.attr( 'scrolling', 'auto' )
.attr( 'src', options.url + ( options.url.indexOf( '?' ) === -1 ? '?' : '&' ) + 'widget=True' )
);
} else if ( options.content ) {
_.isFunction( options.content ) ? options.content( $frame_content ) : $frame_content.append( options.content );
}
// construct a new frame
var frame = {
id : frame_id,
screen_location : {},
grid_location : {},
grid_rank : null,
grid_lock : false
};
var frame = new FrameView( options );
this.$el.append( frame.$el );
// set dimensions
options.width = this._toPixelCoord( 'width', this.options.frame.cols );
options.height = this._toPixelCoord( 'height', this.options.frame.rows );
// set default z-index and add to ui and frame list
this.frame_z = parseInt( $( frame.id ).css( 'z-index' ) );
this.frame_z = parseInt( frame.$el.css( 'z-index' ) );
this.frame_list[ frame_id ] = frame;
this.frame_counter++;
this._frameInit( frame, frame_id );
this._frameResize( frame, { width: options.width, height: options.height } );
this._frameInsert( frame, { top: 0, left: 0 }, true );
!this.visible && this.show();
@@ -128,12 +149,12 @@ var View = Backbone.View.extend({
},
/** Remove a frame */
del: function( frame_id ) {
del: function( frame ) {
var self = this;
var $frame = this.$( frame_id );
var $frame = frame.$el;
$frame.fadeOut( 'fast', function() {
$frame.remove();
delete self.frame_list[ frame_id ];
delete self.frame_list[ frame.id ];
self.frame_counter--;
self._panelRefresh( true );
self._panelAnimationComplete();
@@ -178,12 +199,12 @@ var View = Backbone.View.extend({
'mousedown .frame-background' : '_eventHide',
'mousedown .frame-scroll-up' : '_eventPanelScroll_up',
'mousedown .frame-scroll-down' : '_eventPanelScroll_down',
'mousedown .f-close' : '_eventFrameClose',
'mousedown .f-pin' : '_eventFrameLock'
'mousedown .f-close' : '_eventFrameClose'
},
/** Start drag/resize event */
_eventFrameMouseDown: function ( e ) {
$( '.tooltip' ).hide();
if ( !this.event.type ) {
if ( $( e.target ).hasClass( 'f-header' ) || $( e.target ).hasClass( 'f-title' ) ) {
this.event.type = 'drag';
@@ -194,10 +215,6 @@ var View = Backbone.View.extend({
if ( this.event.type ) {
e.preventDefault();
this.event.target = this._frameIdentify( e.target );
if ( this.event.target.grid_lock ) {
this.event.type = null;
return;
}
this.event.xy = {
x: e.originalEvent.pageX,
y: e.originalEvent.pageY
@@ -267,22 +284,7 @@ var View = Backbone.View.extend({
_eventFrameClose: function ( e ) {
if ( !this.event.type ) {
e.preventDefault();
this.del( this._frameIdentify( e.target ).id );
}
},
/** Lock/Unlock the frame location */
_eventFrameLock: function ( e ) {
if ( !this.event.type ) {
e.preventDefault();
var frame = this._frameIdentify( e.target );
var locked = frame.grid_lock = !frame.grid_lock;
var $el = $( frame.id );
$el.find( '.f-pin' ) [ locked && 'addClass' || 'removeClass' ]( 'toggle' );
$el.find( '.f-header' ) [ locked && 'removeClass' || 'addClass' ]( 'f-not-allowed' );
$el.find( '.f-title' ) [ locked && 'removeClass' || 'addClass' ]( 'f-not-allowed' );
$el.find( '.f-resize' ) [ locked && 'hide' || 'show' ]();
$el.find( '.f-close' ) [ locked && 'hide' || 'show' ]();
this.del( this._frameIdentify( e.target ) );
}
},
@@ -338,7 +340,7 @@ var View = Backbone.View.extend({
this._frameResize( this.frame_shadow, p );
this._frameGrid( this.frame_shadow, frame.grid_location );
frame.grid_location = null;
$( this.frame_shadow.id ).show();
this.frame_shadow.$el.show();
$( '.f-cover' ).show();
},
@@ -349,7 +351,7 @@ var View = Backbone.View.extend({
this._frameResize( frame, p );
this._frameGrid( frame, this.frame_shadow.grid_location, true );
this.frame_shadow.grid_location = null;
$( this.frame_shadow.id ).hide();
this.frame_shadow.$el.hide();
$( '.f-cover' ).hide();
this._panelAnimationComplete();
},
@@ -458,6 +460,15 @@ var View = Backbone.View.extend({
FRAME FUNCTIONS
*/
/** Initialize a new frame */
_frameInit: function( frame, id ) {
frame.id = id
frame.screen_location = {};
frame.grid_location = {};
frame.grid_rank = null;
frame.$el.attr( 'id', id.substring( 1 ) );
},
/** Insert frame at given location */
_frameInsert: function( frame, new_loc, animate ) {
var self = this;
@@ -467,7 +478,7 @@ var View = Backbone.View.extend({
place_list.push( [ frame, this._locationRank( new_loc ) ] );
}
_.each( this.frame_list, function( f ) {
if ( f.grid_location !== null && !f.grid_lock ) {
if ( f.grid_location !== null ) {
f.grid_location = null;
place_list.push( [ f, f.grid_rank ] );
}
@@ -516,7 +527,7 @@ var View = Backbone.View.extend({
/** Handle frame focussing */
_frameFocus: function( frame, has_focus ) {
$( frame.id ).css( 'z-index', this.frame_z + ( has_focus ? 1 : 0 ) );
frame.$el.css( 'z-index', this.frame_z + ( has_focus ? 1 : 0 ) );
},
/** New left/top position frame */
@@ -526,17 +537,17 @@ var View = Backbone.View.extend({
if ( animate ) {
this._frameFocus( frame, true );
var self = this;
$( frame.id ).animate({ top: p.top, left: p.left }, 'fast', function() {
frame.$el.animate({ top: p.top, left: p.left }, 'fast', function() {
self._frameFocus( frame, false );
});
} else {
$( frame.id ).css( { top: p.top, left: p.left } );
frame.$el.css( { top: p.top, left: p.left } );
}
},
/** Resize frame */
_frameResize: function( frame, p ) {
$( frame.id ).css( { width: p.width, height: p.height } );
frame.$el.css( { width: p.width, height: p.height } );
frame.screen_location.width = p.width;
frame.screen_location.height = p.height;
},
@@ -552,21 +563,6 @@ var View = Backbone.View.extend({
_frameScreen: function( frame ) {
var p = frame.screen_location;
return { top: p.top, left: p.left, width: p.width, height: p.height };
},
/** Regular frame template */
_frameTemplate: function( id, title ) {
return '<div id="' + id + '" class="frame corner">' +
'<div class="f-header corner">' +
'<span class="f-title">' + ( title || '' ) + '</span>' +
'<span class="f-icon f-close fa fa-close"/>' +
'<span class="f-icon f-pin fa fa-thumb-tack"/>' +
'</div>' +
'<div class="f-content">' +
'<div class="f-cover"/>' +
'</div>' +
'<span class="f-resize f-icon corner fa fa-expand"/>' +
'</div>';
}
});
+18 -14
View File
@@ -97,13 +97,22 @@
border : 1px solid @black;
background : @base-color-1;
color : @white;
.f-icon-left{
cursor : pointer;
font-size : 15px;
margin-left : 3px;
float : left;
&[disabled] {
opacity : 0.25;
}
}
}
.f-title {
position : absolute;
top : 2px;
left : 16px;
right : 16px;
left : 32px;
right : 32px;
font-size : 12px;
font-family : @font-family-sans-serif;
text-align : center;
@@ -113,27 +122,22 @@
frame icons
*/
.f-icon{
position : absolute;
cursor : pointer;
font-size : 14px;
}
.f-not-allowed{
cursor : not-allowed;
}
.f-close{
cursor : pointer;
position : absolute;
font-size : 15px;
right : 5px;
top : 3px;
}
.f-pin{
left : 6px;
top : 3px;
top : 2px;
}
.f-resize{
cursor : pointer;
position : absolute;
font-size : 15px;
right : 0px;
bottom : 0px;
background : @white;
+6 -3
View File
@@ -4,7 +4,7 @@ How Do I...
This section contains a number of smaller topics with links and examples meant
to provide relatively concrete answers for specific Galaxy development scenarios.
... interact with the Galaxy codebase interactively?
... interact with the Galaxy database interactively?
----------------------------------------------------
This can be done with either IPython/Jupyter or a plain python console, depending on your preferences::
@@ -14,12 +14,15 @@ This can be done with either IPython/Jupyter or a plain python console, dependin
... build Galaxy Javascript frontend client?
--------------------------------------------
We've added a makefile which will let you do this. If you have nodejs and npm installed, you can simple run::
We've added a makefile which will let you do this. You can simple run::
make grunt
make client
If you prefer docker and aren't a JS developer primarily, you can run
make grunt-docker
Please see the ``Makefile`` itself for details and other options. There is also a readme at
``client/README.md``.
+2 -2
View File
@@ -135,7 +135,7 @@ class LDAP(AuthProvider):
# parse results
if suser is None or len(suser) == 0:
log.warn('LDAP authenticate: search returned no results')
log.warning('LDAP authenticate: search returned no results')
return (failure_mode, '', '')
dn, attrs = suser[0]
log.debug(("LDAP authenticate: dn is %s" % dn))
@@ -169,7 +169,7 @@ class LDAP(AuthProvider):
if whoami is None:
raise RuntimeError('LDAP authenticate: anonymous bind')
except Exception:
log.warn('LDAP authenticate: bind exception', exc_info=True)
log.warning('LDAP authenticate: bind exception', exc_info=True)
return (failure_mode, '', '')
log.debug('LDAP authentication successful')
+4 -2
View File
@@ -19,7 +19,8 @@ log = logging.getLogger(__name__)
class Amos( data.Text ):
"""Class describing the AMOS assembly file """
edam_format = "format_2561"
edam_data = "data_0925"
edam_format = "format_3582"
file_ext = 'afg'
def sniff( self, filename ):
@@ -68,11 +69,12 @@ class Amos( data.Text ):
class Sequences( sequence.Fasta ):
"""Class describing the Sequences file generated by velveth """
edam_data = "data_0925"
def sniff( self, filename ):
"""
Determines whether the file is a velveth produced fasta format
The id line has 3 fields separated by tabs: sequence_name sequence_index cataegory::
The id line has 3 fields separated by tabs: sequence_name sequence_index category::
>SEQUENCE_0_length_35 1 1
GGATATAGGGCCAACCCAACTCAACGGCCTGTCTT
+30 -12
View File
@@ -87,6 +87,8 @@ class Binary( data.Data ):
class Ab1( Binary ):
"""Class describing an ab1 binary sequence file"""
file_ext = "ab1"
edam_format = "format_3000"
edam_data = "data_0924"
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
@@ -108,6 +110,8 @@ Binary.register_unsniffable_binary_ext("ab1")
class Idat( Binary ):
"""Binary data in idat format"""
file_ext = "idat"
edam_format = "format_2058"
edam_data = "data_2603"
def sniff( self, filename ):
try:
@@ -174,6 +178,8 @@ Binary.register_unsniffable_binary_ext("zip")
class GenericAsn1Binary( Binary ):
"""Class for generic ASN.1 binary format"""
file_ext = "asn1-binary"
edam_format = "format_1966"
edam_data = "data_0849"
Binary.register_unsniffable_binary_ext("asn1-binary")
@@ -182,6 +188,7 @@ Binary.register_unsniffable_binary_ext("asn1-binary")
class Bam( Binary ):
"""Class describing a BAM binary file"""
edam_format = "format_2572"
edam_data = "data_0863"
file_ext = "bam"
track_type = "ReadTrack"
data_sources = { "data": "bai", "index": "bigwig" }
@@ -489,6 +496,7 @@ Binary.register_sniffable_binary_format("bam", "bam", Bam)
class CRAM( Binary ):
file_ext = "cram"
edam_format = "format_3462"
edam_data = "format_0863"
MetadataElement( name="cram_version", default=None, desc="CRAM Version", param=MetadataParameter, readonly=True, visible=False, optional=False, no_value=None )
MetadataElement( name="cram_index", desc="CRAM Index File", param=metadata.FileParameter, file_ext="crai", readonly=True, no_value=None, visible=False, optional=True )
@@ -509,7 +517,7 @@ class CRAM( Binary ):
header = fh.read(6)
return ord( header[4] ), ord( header[5] )
except Exception as exc:
log.warn( '%s, get_cram_version Exception: %s', self, exc )
log.warning( '%s, get_cram_version Exception: %s', self, exc )
return -1, -1
def set_index_file(self, dataset, index_file):
@@ -530,10 +538,10 @@ class CRAM( Binary ):
return index_file.file_name
else:
os.unlink( dataset_symlink )
log.warn( '%s, expected crai index not created for: %s', self, dataset.file_name )
log.warning( '%s, expected crai index not created for: %s', self, dataset.file_name )
return False
except Exception as exc:
log.warn( '%s, set_index_file Exception: %s', self, exc )
log.warning( '%s, set_index_file Exception: %s', self, exc )
return False
def set_peek( self, dataset, is_multi_byte=False ):
@@ -559,6 +567,7 @@ Binary.register_sniffable_binary_format('cram', 'cram', CRAM)
class Bcf( Binary):
"""Class describing a BCF file"""
edam_format = "format_3020"
edam_data = "data_3498"
file_ext = "bcf"
MetadataElement( name="bcf_index", desc="BCF Index File", param=metadata.FileParameter, file_ext="csi", readonly=True, no_value=None, visible=False, optional=True )
@@ -618,6 +627,7 @@ class H5( Binary ):
False
"""
file_ext = "h5"
edam_format = "format_3590"
def __init__( self, **kwd ):
Binary.__init__( self, **kwd )
@@ -653,6 +663,7 @@ Binary.register_sniffable_binary_format("h5", "h5", H5)
class Scf( Binary ):
"""Class describing an scf binary sequence file"""
edam_format = "format_1632"
edam_data = "data_0924"
file_ext = "scf"
def set_peek( self, dataset, is_multi_byte=False ):
@@ -675,6 +686,7 @@ Binary.register_unsniffable_binary_ext("scf")
class Sff( Binary ):
""" Standard Flowgram Format (SFF) """
edam_format = "format_3284"
edam_data = "data_0924"
file_ext = "sff"
def sniff( self, filename ):
@@ -712,6 +724,7 @@ class BigWig(Binary):
http://bioinformatics.oxfordjournals.org/cgi/content/abstract/btq351v1
"""
edam_format = "format_3006"
edam_data = "data_3002"
track_type = "LineTrack"
data_sources = { "data_standalone": "bigwig" }
@@ -750,6 +763,7 @@ Binary.register_sniffable_binary_format("bigwig", "bigwig", BigWig)
class BigBed(BigWig):
"""BigBed support from UCSC."""
edam_format = "format_3004"
edam_data = "data_3002"
data_sources = { "data_standalone": "bigbed" }
def __init__( self, **kwd ):
@@ -763,6 +777,7 @@ Binary.register_sniffable_binary_format("bigbed", "bigbed", BigBed)
class TwoBit (Binary):
"""Class describing a TwoBit format nucleotide file"""
edam_format = "format_3009"
edam_data = "data_0848"
file_ext = "twobit"
def sniff(self, filename):
@@ -800,6 +815,7 @@ class SQlite ( Binary ):
MetadataElement( name="table_columns", default={}, param=DictParameter, desc="Database Table Columns", readonly=True, visible=True, no_value={} )
MetadataElement( name="table_row_count", default={}, param=DictParameter, desc="Database Table Row Count", readonly=True, visible=True, no_value={} )
file_ext = "sqlite"
edam_format = "format_3621"
def init_meta( self, dataset, copy_from=None ):
Binary.init_meta( self, dataset, copy_from=copy_from )
@@ -821,18 +837,18 @@ class SQlite ( Binary ):
cols = [col[0] for col in cur.description]
columns[table] = cols
except Exception as exc:
log.warn( '%s, set_meta Exception: %s', self, exc )
log.warning( '%s, set_meta Exception: %s', self, exc )
for table in tables:
try:
row_query = "SELECT count(*) FROM %s" % table
rowcounts[table] = c.execute(row_query).fetchone()[0]
except Exception as exc:
log.warn( '%s, set_meta Exception: %s', self, exc )
log.warning( '%s, set_meta Exception: %s', self, exc )
dataset.metadata.tables = tables
dataset.metadata.table_columns = columns
dataset.metadata.table_row_count = rowcounts
except Exception as exc:
log.warn( '%s, set_meta Exception: %s', self, exc )
log.warning( '%s, set_meta Exception: %s', self, exc )
def sniff( self, filename ):
# The first 16 bytes of any SQLite3 database file is 'SQLite format 3\0', and the file is binary. For details
@@ -891,6 +907,8 @@ class GeminiSQLite( SQlite ):
MetadataElement( name="gemini_version", default='0.10.0', param=MetadataParameter, desc="Gemini Version",
readonly=True, visible=True, no_value='0.10.0' )
file_ext = "gemini.sqlite"
edam_format = "format_3622"
edam_data = "data_3498"
def set_meta( self, dataset, overwrite=True, **kwd ):
super( GeminiSQLite, self ).set_meta( dataset, overwrite=overwrite, **kwd )
@@ -903,7 +921,7 @@ class GeminiSQLite( SQlite ):
dataset.metadata.gemini_version = version
# TODO: Can/should we detect even more attributes, such as use of PED file, what was input annotation type, etc.
except Exception as e:
log.warn( '%s, set_meta Exception: %s', self, e )
log.warning( '%s, set_meta Exception: %s', self, e )
def sniff( self, filename ):
if super( GeminiSQLite, self ).sniff( filename ):
@@ -920,7 +938,7 @@ class GeminiSQLite( SQlite ):
return False
return True
except Exception as e:
log.warn( '%s, sniff Exception: %s', self, e )
log.warning( '%s, sniff Exception: %s', self, e )
return False
def set_peek( self, dataset, is_multi_byte=False ):
@@ -959,7 +977,7 @@ class MzSQlite( SQlite ):
return False
return True
except Exception as e:
log.warn( '%s, sniff Exception: %s', self, e )
log.warning( '%s, sniff Exception: %s', self, e )
return False
@@ -994,7 +1012,7 @@ class IdpDB( SQlite ):
return False
return True
except Exception as e:
log.warn( '%s, sniff Exception: %s', self, e )
log.warning( '%s, sniff Exception: %s', self, e )
return False
def set_peek( self, dataset, is_multi_byte=False ):
@@ -1274,7 +1292,7 @@ class SearchGuiArchive ( CompressedArchive ):
fh.close()
tempzip.close()
except Exception as e:
log.warn( '%s, set_meta Exception: %s', self, e )
log.warning( '%s, set_meta Exception: %s', self, e )
def sniff( self, filename ):
try:
@@ -1284,7 +1302,7 @@ class SearchGuiArchive ( CompressedArchive ):
tempzip.close()
return is_searchgui
except Exception as e:
log.warn( '%s, sniff Exception: %s', self, e )
log.warning( '%s, sniff Exception: %s', self, e )
return False
def set_peek( self, dataset, is_multi_byte=False ):
+25
View File
@@ -0,0 +1,25 @@
"""Module proxies :module:`galaxy.util.checkers` for backward compatibility.
External datatypes may make use of these functions.
"""
from galaxy.util.checkers import (
check_binary,
check_bz2,
check_gzip,
check_html,
check_image,
check_zip,
is_gzip,
is_bz2,
)
__all__ = [
'check_binary',
'check_bz2',
'check_gzip',
'check_html',
'check_image',
'check_zip',
'is_gzip',
'is_bz2',
]
+5
View File
@@ -64,6 +64,7 @@ class Data( object ):
<class 'galaxy.model.metadata.MetadataParameter'>
"""
edam_data = "data_0006"
edam_format = "format_1915"
# Data is not chunkable by default.
CHUNKABLE = False
@@ -867,6 +868,8 @@ class Text( Data ):
class GenericAsn1( Text ):
"""Class for generic ASN.1 text format"""
edam_data = "data_0849"
edam_format = "format_1966"
file_ext = 'asn1'
@@ -880,6 +883,7 @@ class LineCount( Text ):
class Newick( Text ):
"""New Hampshire/Newick Format"""
edam_data = "data_0872"
edam_format = "format_1910"
file_ext = "nhx"
@@ -904,6 +908,7 @@ class Newick( Text ):
class Nexus( Text ):
"""Nexus format as used By Paup, Mr Bayes, etc"""
edam_data = "data_0872"
edam_format = "format_1912"
file_ext = "nex"
+16
View File
@@ -37,6 +37,7 @@ log = logging.getLogger(__name__)
class Image( data.Data ):
"""Class describing an image"""
edam_data = 'data_2968'
edam_format = "format_3547"
def set_peek( self, dataset, is_multi_byte=False ):
@@ -64,6 +65,7 @@ class Image( data.Data ):
class Jpg( Image ):
edam_format = "format_3579"
file_ext = "jpg"
def sniff(self, filename, image=None):
@@ -72,6 +74,7 @@ class Jpg( Image ):
class Png( Image ):
edam_format = "format_3603"
file_ext = "png"
def sniff(self, filename, image=None):
@@ -80,6 +83,7 @@ class Png( Image ):
class Tiff( Image ):
edam_format = "format_3591"
file_ext = "tiff"
def sniff(self, filename, image=None):
@@ -88,6 +92,7 @@ class Tiff( Image ):
class Bmp( Image ):
edam_format = "format_3592"
file_ext = "bmp"
def sniff(self, filename, image=None):
@@ -105,6 +110,7 @@ class Gif( Image ):
class Im( Image ):
edam_format = "format_3593"
file_ext = "im"
def sniff(self, filename, image=None):
@@ -113,6 +119,7 @@ class Im( Image ):
class Pcd( Image ):
edam_format = "format_3594"
file_ext = "pcd"
def sniff(self, filename, image=None):
@@ -121,6 +128,7 @@ class Pcd( Image ):
class Pcx( Image ):
edam_format = "format_3595"
file_ext = "pcx"
def sniff(self, filename, image=None):
@@ -129,6 +137,7 @@ class Pcx( Image ):
class Ppm( Image ):
edam_format = "format_3596"
file_ext = "ppm"
def sniff(self, filename, image=None):
@@ -137,6 +146,7 @@ class Ppm( Image ):
class Psd( Image ):
edam_format = "format_3597"
file_ext = "psd"
def sniff(self, filename, image=None):
@@ -145,6 +155,7 @@ class Psd( Image ):
class Xbm( Image ):
edam_format = "format_3598"
file_ext = "xbm"
def sniff(self, filename, image=None):
@@ -153,6 +164,7 @@ class Xbm( Image ):
class Xpm( Image ):
edam_format = "format_3599"
file_ext = "xpm"
def sniff(self, filename, image=None):
@@ -161,6 +173,7 @@ class Xpm( Image ):
class Rgb( Image ):
edam_format = "format_3600"
file_ext = "rgb"
def sniff(self, filename, image=None):
@@ -169,6 +182,7 @@ class Rgb( Image ):
class Pbm( Image ):
edam_format = "format_3601"
file_ext = "pbm"
def sniff(self, filename, image=None):
@@ -177,6 +191,7 @@ class Pbm( Image ):
class Pgm( Image ):
edam_format = "format_3602"
file_ext = "pgm"
def sniff(self, filename, image=None):
@@ -194,6 +209,7 @@ class Eps( Image ):
class Rast( Image ):
edam_format = "format_3605"
file_ext = "rast"
def sniff(self, filename, image=None):
+8 -7
View File
@@ -50,6 +50,7 @@ VIEWPORT_MAX_READS_PER_LINE = 10
@dataproviders.decorators.has_dataproviders
class Interval( Tabular ):
"""Tab delimited data containing interval information"""
edam_data = "data_3002"
edam_format = "format_3475"
file_ext = "interval"
line_class = "region"
@@ -375,7 +376,7 @@ class Interval( Tabular ):
class BedGraph( Interval ):
"""Tab delimited chrom/start/end/datavalue dataset"""
edam_format = "format_3583"
file_ext = "bedgraph"
track_type = "LineTrack"
data_sources = { "data": "bigwig", "index": "bigwig" }
@@ -582,7 +583,7 @@ class Bed( Interval ):
class BedStrict( Bed ):
"""Tab delimited data in strict BED format - no non-standard columns allowed"""
edam_format = "format_3584"
file_ext = "bedstrict"
# no user change of datatype allowed
@@ -613,13 +614,13 @@ class BedStrict( Bed ):
class Bed6( BedStrict ):
"""Tab delimited data in strict BED format - no non-standard columns allowed; column count forced to 6"""
edam_format = "format_3585"
file_ext = "bed6"
class Bed12( BedStrict ):
"""Tab delimited data in strict BED format - no non-standard columns allowed; column count forced to 12"""
edam_format = "format_3586"
file_ext = "bed12"
@@ -641,6 +642,7 @@ class _RemoteCallMixin:
@dataproviders.decorators.has_dataproviders
class Gff( Tabular, _RemoteCallMixin ):
"""Tab delimited data in Gff format"""
edam_data = "data_1255"
edam_format = "format_2305"
file_ext = "gff"
column_names = [ 'Seqname', 'Source', 'Feature', 'Start', 'End', 'Score', 'Strand', 'Frame', 'Group' ]
@@ -1288,6 +1290,7 @@ class Wiggle( Tabular, _RemoteCallMixin ):
class CustomTrack ( Tabular ):
"""UCSC CustomTrack"""
edam_format = "format_3588"
file_ext = "customtrack"
def __init__(self, **kwd):
@@ -1440,7 +1443,7 @@ class ENCODEPeak( Interval ):
This format is used to provide called peaks of signal enrichment based on
pooled, normalized (interpreted) data. It is a BED6+4 format.
'''
edam_format = "format_3612"
file_ext = "encodepeak"
column_names = [ 'Chrom', 'Start', 'End', 'Name', 'Score', 'Strand', 'SignalValue', 'pValue', 'qValue', 'Peak' ]
data_sources = { "data": "tabix", "index": "bigwig" }
@@ -1460,11 +1463,9 @@ class ChromatinInteractions( Interval ):
'''
Chromatin interactions obtained from 3C/5C/Hi-C experiments.
'''
file_ext = "chrint"
track_type = "DiagonalHeatmapTrack"
data_sources = { "data": "tabix", "index": "bigwig" }
column_names = [ 'Chrom1', 'Start1', 'End1', 'Chrom2', 'Start2', 'End2', 'Value' ]
"""Add metadata elements"""
+2 -2
View File
@@ -301,7 +301,7 @@ class DistanceMatrix(Text):
dataset.metadata.sequence_count = int(''.join(line)) # seq count sometimes preceded by tab
break
except Exception as e:
log.warn("DistanceMatrix set_meta %s" % e)
log.warning("DistanceMatrix set_meta %s" % e)
class LowerTriangleDistanceMatrix(DistanceMatrix):
@@ -902,7 +902,7 @@ class SffFlow(Tabular):
flow_values = int(headers[0][0])
dataset.metadata.flow_values = flow_values
except Exception as e:
log.warn("SffFlow set_meta %s" % e)
log.warning("SffFlow set_meta %s" % e)
def make_html_table(self, dataset, skipchars=[]):
"""Create HTML table, used for displaying peek"""
+6
View File
@@ -11,6 +11,8 @@ log = logging.getLogger(__name__)
class Hmmer( Text ):
edam_data = "data_1364"
edam_format = "format_1370"
file_ext = "hmm"
def set_peek(self, dataset, is_multi_byte=False):
@@ -29,6 +31,7 @@ class Hmmer( Text ):
class Hmmer2( Hmmer ):
edam_format = "format_3328"
def sniff(self, filename):
"""HMMER2 files start with HMMER2.0
@@ -39,6 +42,7 @@ class Hmmer2( Hmmer ):
class Hmmer3( Hmmer ):
edam_format = "format_3329"
def sniff(self, filename):
"""HMMER3 files start with HMMER3/f
@@ -85,6 +89,8 @@ Binary.register_unsniffable_binary_ext("hmmpress")
class Stockholm_1_0( Text ):
edam_data = "data_0863"
edam_format = "format_1961"
file_ext = "stockholm"
MetadataElement( name="number_of_models", default=0, desc="Number of multiple alignments", readonly=True, visible=True, optional=True, no_value=0 )
+19 -4
View File
@@ -18,6 +18,8 @@ log = logging.getLogger(__name__)
class Wiff(Binary):
"""Class for wiff files."""
edam_data = "data_2536"
edam_format = "format_3710"
file_ext = 'wiff'
allow_datatype_change = False
composite_type = 'auto_primary_file'
@@ -55,6 +57,7 @@ Binary.register_sniffable_binary_format("wiff", "wiff", Wiff )
class PepXmlReport(Tabular):
"""pepxml converted to tabular report"""
edam_data = "data_2536"
file_ext = "tsv"
def __init__(self, **kwd):
@@ -68,6 +71,7 @@ class PepXmlReport(Tabular):
class ProtXmlReport(Tabular):
"""protxml converted to tabular report"""
edam_data = "data_2536"
file_ext = "tsv"
comment_lines = 1
@@ -93,6 +97,8 @@ class ProtXmlReport(Tabular):
class ProteomicsXml(GenericXml):
""" An enhanced XML datatype used to reuse code across several
proteomic/mass-spec datatypes. """
edam_data = "data_2536"
edam_format = "format_2032"
def sniff(self, filename):
""" Determines whether the file is the correct XML type. """
@@ -117,6 +123,7 @@ class ProteomicsXml(GenericXml):
class PepXml(ProteomicsXml):
"""pepXML data"""
edam_format = "format_3655"
file_ext = "pepxml"
blurb = 'pepXML data'
root = "msms_pipeline_analysis"
@@ -124,8 +131,8 @@ class PepXml(ProteomicsXml):
class MzML(ProteomicsXml):
"""mzML data"""
file_ext = "mzml"
edam_format = "format_3244"
file_ext = "mzml"
blurb = 'mzML Mass Spectrometry data'
root = "(mzML|indexedmzML)"
@@ -139,28 +146,29 @@ class ProtXML(ProteomicsXml):
class MzXML(ProteomicsXml):
"""mzXML data"""
edam_format = "format_3654"
file_ext = "mzxml"
blurb = "mzXML Mass Spectrometry data"
root = "mzXML"
class MzIdentML(ProteomicsXml):
file_ext = "mzid"
edam_format = "format_3247"
file_ext = "mzid"
blurb = "XML identified peptides and proteins."
root = "MzIdentML"
class TraML(ProteomicsXml):
file_ext = "traml"
edam_format = "format_3246"
file_ext = "traml"
blurb = "TraML transition list"
root = "TraML"
class MzQuantML(ProteomicsXml):
file_ext = "mzq"
edam_format = "format_3248"
file_ext = "mzq"
blurb = "XML quantification data"
root = "MzQuantML"
@@ -184,6 +192,7 @@ class IdXML(ProteomicsXml):
class TandemXML(ProteomicsXml):
edam_format = "format_3711"
file_ext = "tandem"
blurb = "X!Tandem search results file"
root = "bioml"
@@ -197,6 +206,8 @@ class UniProtXML(ProteomicsXml):
class Mgf(Text):
"""Mascot Generic Format data"""
edam_data = "data_2536"
edam_format = "format_3651"
file_ext = "mgf"
def set_peek(self, dataset, is_multi_byte=False):
@@ -223,6 +234,8 @@ class Mgf(Text):
class MascotDat(Text):
"""Mascot search results """
edam_data = "data_2536"
edam_format = "format_3713"
file_ext = "mascotdat"
def set_peek(self, dataset, is_multi_byte=False):
@@ -249,6 +262,8 @@ class MascotDat(Text):
class ThermoRAW(Binary):
"""Class describing a Thermo Finnigan binary RAW file"""
edam_data = "data_2536"
edam_format = "format_3712"
file_ext = "raw"
def sniff(self, filename):
+6
View File
@@ -11,6 +11,8 @@ class QualityScore ( data.Text ):
"""
until we know more about quality score formats
"""
edam_data = "data_2048"
edam_format = "format_3606"
file_ext = "qual"
@@ -18,6 +20,7 @@ class QualityScoreSOLiD ( QualityScore ):
"""
until we know more about quality score formats
"""
edam_format = "format_3610"
file_ext = "qualsolid"
def sniff( self, filename ):
@@ -75,6 +78,7 @@ class QualityScore454 ( QualityScore ):
"""
until we know more about quality score formats
"""
edam_format = "format_3611"
file_ext = "qual454"
def sniff( self, filename ):
@@ -116,6 +120,7 @@ class QualityScoreSolexa ( QualityScore ):
"""
until we know more about quality score formats
"""
edam_format = "format_3608"
file_ext = "qualsolexa"
@@ -123,4 +128,5 @@ class QualityScoreIllumina ( QualityScore ):
"""
until we know more about quality score formats
"""
edam_format = "format_3609"
file_ext = "qualillumina"
+15 -4
View File
@@ -129,7 +129,11 @@ class Registry( object ):
make_subclass = galaxy.util.string_as_bool( elem.get( 'subclass', False ) )
edam_format = elem.get( 'edam_format', None )
if edam_format and not make_subclass:
self.log.warn("Cannot specify edam_format without setting subclass to True, skipping datatype.")
self.log.warning("Cannot specify edam_format without setting subclass to True, skipping datatype.")
continue
edam_data = elem.get( 'edam_data', None )
if edam_data and not make_subclass:
self.log.warning("Cannot specify edam_data without setting subclass to True, skipping datatype.")
continue
# Proprietary datatypes included in installed tool shed repositories will include two special attributes
# (proprietary_path and proprietary_datatype_module) if they depend on proprietary datatypes classes.
@@ -230,6 +234,8 @@ class Registry( object ):
datatype_class = type( datatype_class_name, ( datatype_class, ), {} )
if edam_format:
datatype_class.edam_format = edam_format
if edam_data:
datatype_class.edam_data = edam_data
self.datatypes_by_extension[ extension ] = datatype_class()
if mimetype is None:
# Use default mimetype per datatype specification.
@@ -816,9 +822,14 @@ class Registry( object ):
def edam_formats( self ):
"""
"""
mapping = {}
for k, v in self.datatypes_by_extension.iteritems():
mapping[k] = v.edam_format
mapping = dict((k, v.edam_format) for k, v in self.datatypes_by_extension.items())
return mapping
@property
def edam_data( self ):
"""
"""
mapping = dict((k, v.edam_data) for k, v in self.datatypes_by_extension.items())
return mapping
@property
+12 -7
View File
@@ -38,6 +38,8 @@ class SequenceSplitLocations( data.Text ):
]}
"""
file_ext = "fqtoc"
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
try:
@@ -52,8 +54,6 @@ class SequenceSplitLocations( data.Text ):
dataset.peek = 'file does not exist'
dataset.blurb = 'file purged from disk'
file_ext = "fqtoc"
def sniff( self, filename ):
if os.path.getsize(filename) < 50000:
try:
@@ -70,6 +70,7 @@ class SequenceSplitLocations( data.Text ):
class Sequence( data.Text ):
"""Class describing a sequence"""
edam_data = "data_2044"
"""Add metadata elements"""
MetadataElement( name="sequences", default=0, desc="Number of sequences", readonly=True, visible=False, optional=True, no_value=0 )
@@ -294,6 +295,7 @@ class Sequence( data.Text ):
class Alignment( data.Text ):
"""Class describing an alignment"""
edam_data = "data_0863"
"""Add metadata elements"""
MetadataElement( name="species", desc="Species", default=[], param=metadata.SelectParameter, multiple=True, readonly=True, no_value=None )
@@ -498,7 +500,7 @@ class Fasta( Sequence ):
class csFasta( Sequence ):
""" Class representing the SOLID Color-Space sequence ( csfasta ) """
edam_format = "format_1929"
edam_format = "format_3589"
file_ext = "csfasta"
def sniff( self, filename ):
@@ -841,11 +843,12 @@ class MafCustomTrack( data.Text ):
class Axt( data.Text ):
"""Class describing an axt alignment"""
# gvk- 11/19/09 - This is really an alignment, but we no longer have tools that use this data type, and it is
# here simply for backward compatibility ( although it is still in the datatypes registry ). Subclassing
# from data.Text eliminates managing metadata elements inherited from the Alignemnt class.
edam_data = "data_0863"
edam_format = "format_3013"
file_ext = "axt"
def sniff( self, filename ):
@@ -895,13 +898,14 @@ class Axt( data.Text ):
class Lav( data.Text ):
"""Class describing a LAV alignment"""
edam_format = "format_3014"
file_ext = "lav"
# gvk- 11/19/09 - This is really an alignment, but we no longer have tools that use this data type, and it is
# here simply for backward compatibility ( although it is still in the datatypes registry ). Subclassing
# from data.Text eliminates managing metadata elements inherited from the Alignemnt class.
edam_data = "data_0863"
edam_format = "format_3014"
file_ext = "lav"
def sniff( self, filename ):
"""
Determines whether the file is in lav format
@@ -963,6 +967,7 @@ class RNADotPlotMatrix( data.Data ):
class DotBracket ( Sequence ):
edam_data = "data_0880"
edam_format = "format_1457"
file_ext = "dbn"
+1
View File
@@ -408,6 +408,7 @@ class Taxonomy( Tabular ):
@dataproviders.decorators.has_dataproviders
class Sam( Tabular ):
edam_format = "format_2573"
edam_data = "data_0863"
file_ext = 'sam'
track_type = "ReadTrack"
data_sources = { "data": "bam", "index": "bigwig" }
+5 -2
View File
@@ -260,6 +260,7 @@ class Obo( Text ):
OBO file format description
http://www.geneontology.org/GO.format.obo-1_2.shtml
"""
edam_data = "data_0582"
edam_format = "format_2549"
file_ext = "obo"
@@ -295,6 +296,7 @@ class Arff( Text ):
An ARFF (Attribute-Relation File Format) file is an ASCII text file that describes a list of instances sharing a set of attributes.
http://weka.wikispaces.com/ARFF
"""
edam_format = "format_3581"
file_ext = "arff"
"""Add metadata elements"""
@@ -393,6 +395,7 @@ class Arff( Text ):
class SnpEffDb( Text ):
"""Class describing a SnpEff genome build"""
edam_format = "format_3624"
file_ext = "snpeffdb"
MetadataElement( name="genome_version", default=None, desc="Genome Version", readonly=True, visible=True, no_value=None )
MetadataElement( name="snpeff_version", default="SnpEff4.0", desc="SnpEff Version", readonly=True, visible=True, no_value=None )
@@ -525,14 +528,14 @@ class SnpSiftDbNSFP( Text ):
headers = lines[0].split('\t')
dataset.metadata.annotation = headers[4:]
except Exception as e:
log.warn("set_meta fname: %s %s" % (fname, str(e)))
log.warning("set_meta fname: %s %s" % (fname, str(e)))
finally:
fh.close()
if fname.endswith('.tbi'):
dataset.metadata.index = fname
self.regenerate_primary_file(dataset)
except Exception as e:
log.warn("set_meta fname: %s %s" % (dataset.file_name if dataset and dataset.file_name else 'Unkwown', str(e)))
log.warning("set_meta fname: %s %s" % (dataset.file_name if dataset and dataset.file_name else 'Unkwown', str(e)))
def set_peek( self, dataset, is_multi_byte=False ):
if not dataset.dataset.purged:
+1
View File
@@ -12,6 +12,7 @@ log = logging.getLogger(__name__)
class GeneTrack( binary.Binary ):
edam_data = "data_3002"
edam_format = "format_2919"
file_ext = "genetrack"
+1
View File
@@ -14,6 +14,7 @@ class Triples( data.Text ):
"""
The abstract base class for the file format that can contain triples
"""
edam_data = "data_0582"
edam_format = "format_2376"
file_ext = "triples"
+2
View File
@@ -94,6 +94,8 @@ class CisML( GenericXml ):
class Phyloxml( GenericXml ):
"""Format for defining phyloxml data http://www.phyloxml.org/"""
edam_data = "data_0872"
edam_format = "format_3159"
file_ext = "phyloxml"
def set_peek( self, dataset, is_multi_byte=False ):
+2 -2
View File
@@ -80,7 +80,7 @@ class ExternalServiceAction( object ):
return handled_results
def perform_action( self, param_dict ):
raise 'Abstract Method'
raise Exception( 'Abstract Method' )
class ExternalServiceResult( object ):
@@ -90,7 +90,7 @@ class ExternalServiceResult( object ):
@property
def content( self ):
raise 'Abstract Method'
raise Exception( 'Abstract Method' )
class ExternalServiceWebAPIActionResult( ExternalServiceResult ):
+1 -1
View File
@@ -21,7 +21,7 @@ class ExternalServiceParameter( object ):
self.parent = parent
def get_value( self, param_dict ):
raise 'Abstract Method'
raise Exception( 'Abstract Method' )
class ExternalServiceTemplateParameter( ExternalServiceParameter ):
+1 -1
View File
@@ -218,7 +218,7 @@ class PopulatedExternalService( object ):
elif isinstance( item, ExternalServiceActionsGroup ):
item.prepare_actions( param_dict, param_dict, action_list )
else:
raise 'unknown item type found'
raise Exception( 'unknown item type found' )
self.param_dict = param_dict
self.actions = action_list
+1 -1
View File
@@ -69,7 +69,7 @@ class FormDefinitionFieldFactory( object ):
type = None
def __get_stored_field_type( self, **kwds ):
raise 'not implemented'
raise Exception( 'not implemented' )
def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None ):
"""
+16 -4
View File
@@ -1133,12 +1133,21 @@ class JobWrapper( object ):
self.app.config, key, default
)
def finish( self, stdout, stderr, tool_exit_code=None, remote_working_directory=None ):
def finish(
self,
stdout,
stderr,
tool_exit_code=None,
remote_working_directory=None,
remote_metadata_directory=None,
):
"""
Called to indicate that the associated command has been run. Updates
the output datasets based on stderr and stdout from the command, and
the contents of the output files.
"""
# remote_working_directory not used with updated (7.0+ pulsar and 16.04+
# originated Galaxy job - keep for a few releases for older jobs)
finish_timer = util.ExecutionTimer()
# default post job setup
@@ -1266,12 +1275,15 @@ class JobWrapper( object ):
output_filename = self.external_output_metadata.get_output_filenames_by_dataset( dataset, self.sa_session ).filename_out
def path_rewriter( path ):
if not remote_working_directory or not path:
if not path:
return path
normalized_remote_working_directory = os.path.normpath( remote_working_directory )
normalized_remote_working_directory = remote_working_directory and os.path.normpath( remote_working_directory )
normalized_remote_metadata_directory = remote_metadata_directory and os.path.normpath( remote_metadata_directory )
normalized_path = os.path.normpath( path )
if normalized_path.startswith( normalized_remote_working_directory ):
if remote_working_directory and normalized_path.startswith( normalized_remote_working_directory ):
return normalized_path.replace( normalized_remote_working_directory, self.working_directory, 1 )
if remote_metadata_directory and normalized_path.startswith( normalized_remote_metadata_directory ):
return normalized_path.replace( normalized_remote_metadata_directory, self.working_directory, 1 )
return path
dataset.metadata.from_JSON_dict( output_filename, path_rewriter=path_rewriter )
@@ -185,7 +185,7 @@ class CollectlProcessSummarizer( object ):
if column == "AccumT":
# Only thing that makes sense is sum
if statistic_type != "max":
log.warn( "Only statistic max makes sense for AccumT" )
log.warning( "Only statistic max makes sense for AccumT" )
continue
value = sum( [ v.max for v in self.process_accum_statistics.itervalues() ] )
+2 -2
View File
@@ -58,8 +58,8 @@ class CondorJobRunner( AsynchronousJobRunner ):
# get destination params
query_params = submission_params(prefix="", **job_destination.params)
container = None
universe = query_params.get('universe', False)
if universe.strip().lower() == 'docker':
universe = query_params.get('universe', None)
if universe and universe.strip().lower() == 'docker':
container = self.find_container( job_wrapper )
if container:
# HTCondor needs the image as 'docker_image'
+1 -1
View File
@@ -107,7 +107,7 @@ class LocalJobRunner( BaseJobRunner ):
try:
exit_code = int( open( exit_code_path, 'r' ).read() )
except Exception:
log.warn( "Failed to read exit code from path %s" % exit_code_path )
log.warning( "Failed to read exit code from path %s" % exit_code_path )
pass
stdout_file.seek( 0 )
stderr_file.seek( 0 )
+5 -3
View File
@@ -377,7 +377,7 @@ class PulsarJobRunner( AsynchronousJobRunner ):
for key, value in self.destination_defaults.iteritems():
if key in params:
if value is PARAMETER_SPECIFICATION_IGNORED:
log.warn( "Pulsar runner in selected configuration ignores parameter %s" % key )
log.warning( "Pulsar runner in selected configuration ignores parameter %s" % key )
continue
# if self.runner_params.get( key, None ):
# # Let plugin define defaults for some parameters -
@@ -451,6 +451,7 @@ class PulsarJobRunner( AsynchronousJobRunner ):
client = self.get_client_from_state(job_state)
run_results = client.full_status()
remote_working_directory = run_results.get("working_directory", None)
remote_metadata_directory = run_results.get("metadata_directory", None)
stdout = run_results.get('stdout', '')
stderr = run_results.get('stderr', '')
exit_code = run_results.get('returncode', None)
@@ -482,7 +483,8 @@ class PulsarJobRunner( AsynchronousJobRunner ):
stdout,
stderr,
exit_code,
remote_working_directory=remote_working_directory
remote_working_directory=remote_working_directory,
remote_metadata_directory=remote_metadata_directory,
)
except Exception:
log.exception("Job wrapper finish method failed")
@@ -666,7 +668,7 @@ class PulsarJobRunner( AsynchronousJobRunner ):
if PulsarJobRunner.__use_remote_datatypes_conf( client ):
remote_datatypes_config = remote_system_properties.get('galaxy_datatypes_config_file', None)
if not remote_datatypes_config:
log.warn(NO_REMOTE_DATATYPES_CONFIG)
log.warning(NO_REMOTE_DATATYPES_CONFIG)
remote_datatypes_config = os.path.join(remote_galaxy_home, 'datatypes_conf.xml')
metadata_kwds['datatypes_config'] = remote_datatypes_config
else:
+17 -18
View File
@@ -39,8 +39,8 @@ class SlurmJobRunner( DRMAAJobRunner ):
return dict( JobState='NOT_FOUND' )
raise Exception( '`%s` returned %s, stderr: %s' % ( ' '.join( cmd ), p.returncode, stderr ) )
return dict( [ out_param.split( '=', 1 ) for out_param in stdout.split() ] )
if drmaa_state == self.drmaa_job_states.FAILED:
try:
try:
if drmaa_state == self.drmaa_job_states.FAILED:
job_info = __get_jobinfo()
sleep = 1
while job_info['JobState'] == 'COMPLETING':
@@ -86,22 +86,21 @@ class SlurmJobRunner( DRMAAJobRunner ):
ajs.stop_job = False
self.work_queue.put( ( self.fail_job, ajs ) )
return
except Exception as e:
log.exception( '(%s/%s) Unable to inspect failed slurm job using scontrol, job will be unconditionally failed: %s', ajs.job_wrapper.get_id_tag(), ajs.job_id, e )
return super( SlurmJobRunner, self )._complete_terminal_job( ajs, drmaa_state=drmaa_state )
if drmaa_state == self.drmaa_job_states.DONE:
with open(ajs.error_file, 'r+') as f:
lines = f.readlines()
f.seek(0)
for line in lines:
stripped_line = line.strip()
if any([_ in stripped_line for _ in SLURM_MEMORY_LIMIT_EXCEEDED_PARTIAL_WARNINGS]):
log.debug( '(%s/%s) Job completed, removing SLURM exceeded memory warning: "%s"', ajs.job_wrapper.get_id_tag(), ajs.job_id, stripped_line )
else:
f.write(line)
f.truncate()
# by default, finish as if the job was successful.
super( SlurmJobRunner, self )._complete_terminal_job( ajs, drmaa_state=drmaa_state )
if drmaa_state == self.drmaa_job_states.DONE:
with open(ajs.error_file, 'r+') as f:
lines = f.readlines()
f.seek(0)
for line in lines:
stripped_line = line.strip()
if any([_ in stripped_line for _ in SLURM_MEMORY_LIMIT_EXCEEDED_PARTIAL_WARNINGS]):
log.debug( '(%s/%s) Job completed, removing SLURM exceeded memory warning: "%s"', ajs.job_wrapper.get_id_tag(), ajs.job_id, stripped_line )
else:
f.write(line)
f.truncate()
except Exception:
log.exception( '(%s/%s) Failure in SLURM _complete_terminal_job(), job final state will be: %s', ajs.job_wrapper.get_id_tag(), ajs.job_id, drmaa_state )
# by default, finish the job with the state from drmaa
return super( SlurmJobRunner, self )._complete_terminal_job( ajs, drmaa_state=drmaa_state )
def __check_memory_limit( self, efile_path ):
"""
+1 -1
View File
@@ -65,7 +65,7 @@ def parse_citation( elem, directory, citation_manager ):
citation_type = elem.attrib.get( 'type', None )
citation_class = CITATION_CLASSES.get( citation_type, None )
if not citation_class:
log.warn("Unknown or unspecified citation type: %s" % citation_type)
log.warning("Unknown or unspecified citation type: %s" % citation_type)
return None
return citation_class( elem, directory, citation_manager )
+1 -1
View File
@@ -79,7 +79,7 @@ class HistoryManager( sharable.SharableModelManager, deletable.PurgableManagerMi
"""
if self.user_manager.is_anonymous( user ):
return None if ( not current_history or current_history.deleted ) else current_history
desc_update_time = self.model_class.table.c.update_time
desc_update_time = desc( self.model_class.table.c.update_time )
filters = self._munge_filters( filters, self.model_class.user_id == user.id )
# TODO: normalize this return value
return self.query( filters=filters, order_by=desc_update_time, limit=1, **kwargs ).first()
+1 -1
View File
@@ -136,7 +136,7 @@ class TagManager( object ):
# Create tag; if None, skip the tag (and log error).
tag = self._get_or_create_tag( lc_name )
if not tag:
log.warn( "Failed to create tag with name %s" % lc_name )
log.warning( "Failed to create tag with name %s" % lc_name )
return
# Create tag association based on item class.
item_tag_assoc_class = self.get_tag_assoc_class( item.__class__ )
+5 -5
View File
@@ -1572,7 +1572,7 @@ class LibraryPermissions( object ):
if isinstance( library_item, Library ):
self.library = library_item
else:
raise "Invalid Library specified: %s" % library_item.__class__.__name__
raise Exception( "Invalid Library specified: %s" % library_item.__class__.__name__ )
self.role = role
@@ -1582,7 +1582,7 @@ class LibraryFolderPermissions( object ):
if isinstance( library_item, LibraryFolder ):
self.folder = library_item
else:
raise "Invalid LibraryFolder specified: %s" % library_item.__class__.__name__
raise Exception( "Invalid LibraryFolder specified: %s" % library_item.__class__.__name__ )
self.role = role
@@ -1592,7 +1592,7 @@ class LibraryDatasetPermissions( object ):
if isinstance( library_item, LibraryDataset ):
self.library_dataset = library_item
else:
raise "Invalid LibraryDataset specified: %s" % library_item.__class__.__name__
raise Exception( "Invalid LibraryDataset specified: %s" % library_item.__class__.__name__ )
self.role = role
@@ -1602,7 +1602,7 @@ class LibraryDatasetDatasetAssociationPermissions( object ):
if isinstance( library_item, LibraryDatasetDatasetAssociation ):
self.library_dataset_dataset_association = library_item
else:
raise "Invalid LibraryDatasetDatasetAssociation specified: %s" % library_item.__class__.__name__
raise Exception( "Invalid LibraryDatasetDatasetAssociation specified: %s" % library_item.__class__.__name__ )
self.role = role
@@ -2079,7 +2079,7 @@ class DatasetInstance( object ):
return fake_hda
def clear_associated_files( self, metadata_safe=False, purge=False ):
raise 'Unimplemented'
raise Exception( "Unimplemented" )
def get_child_by_designation(self, designation):
for child in self.children:
@@ -274,7 +274,7 @@ class DatasetInstance( object ):
return valid
def clear_associated_files( self, metadata_safe=False, purge=False ):
raise 'Unimplemented'
raise Exception( 'Unimplemented' )
def get_child_by_designation(self, designation):
for child in self.children:
@@ -37,7 +37,7 @@ def upgrade(migrate_engine):
try:
table.create()
except:
log.warn( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
log.warning( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
def downgrade(migrate_engine):
@@ -37,7 +37,7 @@ def upgrade(migrate_engine):
try:
table.create()
except:
log.warn( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
log.warning( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
def downgrade(migrate_engine):
@@ -26,7 +26,7 @@ def upgrade(migrate_engine):
try:
table.create()
except:
log.warn( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
log.warning( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
def downgrade(migrate_engine):
@@ -38,7 +38,7 @@ def upgrade(migrate_engine):
try:
table.create()
except:
log.warn( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
log.warning( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
def downgrade(migrate_engine):
+36 -36
View File
@@ -48,97 +48,97 @@ class RBACAgent:
return self.permitted_actions.__dict__.values()
def get_item_actions( self, action, item ):
raise 'No valid method of retrieving action (%s) for item %s.' % ( action, item )
raise Exception( 'No valid method of retrieving action (%s) for item %s.' % ( action, item ) )
def guess_derived_permissions_for_datasets( self, datasets=[] ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def can_access_dataset( self, roles, dataset ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def can_manage_dataset( self, roles, dataset ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def can_access_library( self, roles, library ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def can_add_library_item( self, roles, item ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def can_modify_library_item( self, roles, item ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def can_manage_library_item( self, roles, item ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def associate_components( self, **kwd ):
raise 'No valid method of associating provided components: %s' % kwd
raise Exception( 'No valid method of associating provided components: %s' % kwd )
def create_private_user_role( self, user ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_private_user_role( self, user ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_accessible_request_types( self, trans, user ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def user_set_default_permissions( self, user, permissions={}, history=False, dataset=False ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def history_set_default_permissions( self, history, permissions=None, dataset=False, bypass_manage_permission=False ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def set_all_dataset_permissions( self, dataset, permissions, new=False ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def set_dataset_permission( self, dataset, permission ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def set_all_library_permissions( self, trans, dataset, permissions ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def set_library_item_permission( self, library_item, permission ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def library_is_public( self, library ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def make_library_public( self, library ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_accessible_libraries( self, trans, user ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_permitted_libraries( self, trans, user, actions ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def folder_is_public( self, library ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def make_folder_public( self, folder, count=0 ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def dataset_is_public( self, dataset ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def make_dataset_public( self, dataset ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_permissions( self, library_dataset ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_all_roles( self, trans, cntrller ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_legitimate_roles( self, trans, item, cntrller ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def derive_roles_from_access( self, trans, item_id, cntrller, library=False, **kwd ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_component_associations( self, **kwd ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def components_are_associated( self, **kwd ):
return bool( self.get_component_associations( **kwd ) )
@@ -736,7 +736,7 @@ class GalaxyRBACAgent( RBACAgent ):
if 'action' in kwd:
if 'dataset' in kwd and 'role' in kwd:
return self.associate_action_dataset_role( kwd['action'], kwd['dataset'], kwd['role'] )
raise 'No valid method of associating provided components: %s' % kwd
raise Exception( 'No valid method of associating provided components: %s' % kwd )
def associate_user_group( self, user, group ):
assoc = self.model.UserGroupAssociation( user, group )
@@ -1300,8 +1300,8 @@ class GalaxyRBACAgent( RBACAgent ):
self.sa_session.add( lp )
self.sa_session.flush()
else:
raise 'Invalid class (%s) specified for target_library_item (%s)' % \
( target_library_item.__class__, target_library_item.__class__.__name__ )
raise Exception( 'Invalid class (%s) specified for target_library_item (%s)' %
( target_library_item.__class__, target_library_item.__class__.__name__ ) )
def get_permitted_libraries( self, trans, user, actions ):
"""
@@ -1435,7 +1435,7 @@ class GalaxyRBACAgent( RBACAgent ):
elif 'group' in kwd:
if 'role' in kwd:
return self.sa_session.query( self.model.GroupRoleAssociation ).filter_by( role_id=kwd['role'].id, group_id=kwd['group'].id ).first()
raise 'No valid method of associating provided components: %s' % kwd
raise Exception( 'No valid method of associating provided components: %s' % kwd )
def check_folder_contents( self, user, roles, folder, hidden_folder_ids='' ):
"""
@@ -1567,7 +1567,7 @@ class HostAgent( RBACAgent ):
log.debug( 'Allowing access to private dataset with hda: %i. Remote server is: %s.' % ( hda.id, server ) )
return True
else:
raise 'The dataset access permission is the only valid permission in the host security agent.'
raise Exception( 'The dataset access permission is the only valid permission in the host security agent.' )
def set_dataset_permissions( self, hda, user, site ):
hdadaa = self.sa_session.query( self.model.HistoryDatasetAssociationDisplayAtAuthorization ) \
+11 -4
View File
@@ -428,7 +428,7 @@ class Tool( object, Dictifiable ):
if self.profile >= 16.04 and VERSION_MAJOR < self.profile:
template = "The tool %s targets version %s of Galaxy, you should upgrade Galaxy to ensure proper functioning of this tool."
message = template % (self.id, self.profile)
log.warn(message)
log.warning(message)
# Get the (user visible) name of the tool
self.name = tool_source.parse_name()
@@ -443,6 +443,9 @@ class Tool( object, Dictifiable ):
else:
raise Exception( "Missing tool 'version' for tool with id '%s' at '%s'" % (self.id, tool_source) )
self.edam_operations = tool_source.parse_edam_operations()
self.edam_topics = tool_source.parse_edam_topics()
# Support multi-byte tools
self.is_multi_byte = tool_source.parse_is_multi_byte()
# Legacy feature, ignored by UI.
@@ -1240,9 +1243,10 @@ class Tool( object, Dictifiable ):
if error:
if update_values:
try:
previous_value = value
value = input.get_initial_value( request_context, context )
if not prefixed_name.startswith( '__' ):
messages[ prefixed_name ] = '%s Using default: \'%s\'.' % ( error, value )
messages[ prefixed_name ] = error if previous_value == value else '%s Using default: \'%s\'.' % ( error, value )
parent[ input.name ] = value
except:
messages[ prefixed_name ] = 'Attempt to replace invalid value for \'%s\' failed.' % ( prefixed_label )
@@ -1538,6 +1542,9 @@ class Tool( object, Dictifiable ):
# Basic information
tool_dict = super( Tool, self ).to_dict()
tool_dict["edam_operations"] = self.edam_operations
tool_dict["edam_topics"] = self.edam_topics
# Fill in ToolShedRepository info
if hasattr(self, 'tool_shed') and self.tool_shed:
tool_dict['tool_shed_repository'] = {
@@ -1573,7 +1580,7 @@ class Tool( object, Dictifiable ):
return tool_dict
def to_json( self, trans, kwd={}, job=None, workflow_mode=False ):
def to_json( self, trans, kwd={}, job=None, workflow_building_mode=False ):
"""
Recursively creates a tool dictionary containing repeats, dynamic options and updated states.
"""
@@ -1590,7 +1597,7 @@ class Tool( object, Dictifiable ):
raise exceptions.MessageException( '[history_id=%s] Failed to retrieve history. %s.' % ( history_id, str( e ) ) )
# build request context
request_context = WorkRequestContext( app=trans.app, user=trans.user, history=history, workflow_building_mode=workflow_mode )
request_context = WorkRequestContext( app=trans.app, user=trans.user, history=history, workflow_building_mode=workflow_building_mode )
# load job parameters into incoming
tool_message = ''
+1 -1
View File
@@ -78,7 +78,7 @@ class DefaultToolAction( object ):
data = new_data
if not trans.app.security_agent.can_access_dataset( current_user_roles, data.dataset ):
raise "User does not have permission to use a dataset (%s) provided for input." % data.id
raise Exception( "User does not have permission to use a dataset (%s) provided for input." % data.id )
return data
if isinstance( input, DataToolParameter ):
if isinstance( value, list ):
+3 -3
View File
@@ -340,7 +340,7 @@ class TabularToolDataTable( ToolDataTable, Dictifiable ):
self._update_version()
else:
self.missing_index_file = filename
log.warn( "Cannot find index file '%s' for tool data table '%s'" % ( filename, self.name ) )
log.warning( "Cannot find index file '%s' for tool data table '%s'" % ( filename, self.name ) )
if filename not in self.filenames or not self.filenames[ filename ][ 'found' ]:
self.filenames[ filename ] = dict( found=found, filename=filename, from_shed_config=from_shed_config, tool_data_path=tool_data_path,
@@ -461,7 +461,7 @@ class TabularToolDataTable( ToolDataTable, Dictifiable ):
line_error = "Line %i in tool data table '%s' is invalid (HINT: '%s' characters must be used to separate fields):\n%s" % ( ( i + 1 ), self.name, separator_char, line )
if errors is not None:
errors.append( line_error )
log.warn( line_error )
log.warning( line_error )
return rval
def get_column_name_list( self ):
@@ -590,7 +590,7 @@ class TabularToolDataTable( ToolDataTable, Dictifiable ):
values = self._replace_field_separators( values )
self.filter_file_fields( filename, values )
else:
log.warn( "Cannot find index file '%s' for tool data table '%s'" % ( filename, self.name ) )
log.warning( "Cannot find index file '%s' for tool data table '%s'" % ( filename, self.name ) )
self.reload_from_files()
+3 -3
View File
@@ -78,9 +78,9 @@ class DependencyManager( object ):
in `base_paths`. The default base path is app.config.tool_dependency_dir.
"""
if not os.path.exists( default_base_path ):
log.warn( "Path '%s' does not exist, ignoring", default_base_path )
log.warning( "Path '%s' does not exist, ignoring", default_base_path )
if not os.path.isdir( default_base_path ):
log.warn( "Path '%s' is not directory, ignoring", default_base_path )
log.warning( "Path '%s' is not directory, ignoring", default_base_path )
self.extra_config = extra_config
self.default_base_path = os.path.abspath( default_base_path )
self.resolver_classes = self.__resolvers_dict()
@@ -98,7 +98,7 @@ class DependencyManager( object ):
**kwds )
dependency_commands = dependency.shell_commands( requirement )
if not dependency_commands:
log.warn( "Failed to resolve dependency on '%s', ignoring", requirement.name )
log.warning( "Failed to resolve dependency on '%s', ignoring", requirement.name )
else:
commands.append( dependency_commands )
return commands
+22 -2
View File
@@ -7,6 +7,11 @@ from galaxy.util import which
STDOUT_INDICATOR = "-"
try:
from shlex import quote as shell_quote
except ImportError:
from pipes import quote as shell_quote
def redirecting_io(sys=_sys):
"""Predicate to determine if we are redicting I/O in process."""
@@ -70,14 +75,27 @@ def execute(cmds):
Return the standard output if the commands are successful
"""
return _wait(cmds, shell=False)
return _wait(cmds, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
def argv_to_str(command_argv, quote=True):
"""Convert an argv command list to a string for shell subprocess.
If None appears in the command list it is simply excluded.
Arguments are quoted with shlex.quote. That said, this method is not meant to be
used in security critical paths of code and should not be used to sanitize
code.
"""
map_func = shell_quote if quote else lambda x: x
return " ".join([map_func(c) for c in command_argv if c is not None])
def _wait(cmds, **popen_kwds):
p = subprocess.Popen(cmds, **popen_kwds)
stdout, stderr = p.communicate()
if p.returncode != 0:
raise CommandLineException(" ".join(cmds), stdout, stderr)
raise CommandLineException(argv_to_str(cmds), stdout, stderr)
return stdout
@@ -127,6 +145,7 @@ class CommandLineException(Exception):
__all__ = [
'argv_to_str',
'CommandLineException',
'download_command',
'execute',
@@ -134,5 +153,6 @@ __all__ = [
'redirecting_io',
'shell',
'shell_process',
'shell_quote',
'which',
]
+24 -1
View File
@@ -23,6 +23,7 @@ CONDA_LICENSE = "http://docs.continuum.io/anaconda/eula"
VERSIONED_ENV_DIR_NAME = re.compile(r"__package__(.*)@__version__(.*)")
UNVERSIONED_ENV_DIR_NAME = re.compile(r"__package__(.*)@__unversioned__")
USE_PATH_EXEC_DEFAULT = False
CONDA_VERSION = "3.19.3"
def conda_link():
@@ -264,7 +265,8 @@ def install_conda(conda_context=None):
os.close(f)
download_cmd = " ".join(commands.download_command(conda_link(), to=script_path, quote_url=True))
install_cmd = "bash '%s' -b -p '%s'" % (script_path, conda_context.conda_prefix)
full_command = "%s; %s" % (download_cmd, install_cmd)
fix_version_cmd = "%s install -y -q conda=%s " % (os.path.join(conda_context.conda_prefix, 'bin/conda'), CONDA_VERSION)
full_command = "%s && %s && %s" % (download_cmd, install_cmd, fix_version_cmd)
try:
return conda_context.shell_exec(full_command)
finally:
@@ -284,6 +286,27 @@ def install_conda_target(conda_target, conda_context=None):
conda_context.exec_create(create_args)
def is_target_available(conda_target, conda_context=None):
""" Checks if a specified target is available for installation.
If the package name exists return "True". If in addition the version matches exactly return "exact".
Otherwise return False.
"""
conda_context = _ensure_conda_context(conda_context)
conda_context.ensure_channels_configured()
search_cmd = [conda_context.conda_exec, "search", "--full-name", "--json", conda_target.package]
res = commands.execute(search_cmd)
hits = json.loads(res).get(conda_target.package, [])
if len(hits) > 0:
if conda_target.version:
for hit in hits:
if hit['version'] == conda_target.version:
return 'exact'
return True
else:
return False
def is_conda_target_installed(conda_target, conda_context=None):
conda_context = _ensure_conda_context(conda_context)
return conda_context.has_env(conda_target.install_environment)
+52 -36
View File
@@ -1,4 +1,9 @@
"""Utilities for building up Docker commands...
...using common defaults and configuration mechanisms.
"""
import os
from .commands import argv_to_str, shell_quote
DEFAULT_DOCKER_COMMAND = "docker"
DEFAULT_SUDO = True
@@ -54,6 +59,22 @@ class DockerVolume(object):
return ":".join([self.from_path, self.to_path, self.how])
def kill_command(
container,
signal=None,
**kwds
):
args = (["-s", signal] if signal else []) + [container]
return command_list("kill", args, **kwds)
def logs_command(
container,
**kwds
):
return command_list("logs", **kwds)
def build_command(
image,
docker_build_path,
@@ -61,9 +82,7 @@ def build_command(
):
if os.path.isfile(docker_build_path):
docker_build_path = os.path.dirname(os.path.abspath(docker_build_path))
build_command_parts = __docker_prefix(**kwds)
build_command_parts.extend(["build", "-t", image, docker_build_path])
return build_command_parts
return command_list("build", ["-t", image, docker_build_path], **kwds)
def build_save_image_command(
@@ -71,47 +90,33 @@ def build_save_image_command(
destination,
**kwds
):
build_command_parts = __docker_prefix(**kwds)
build_command_parts.extend(["save", "-o", destination, image])
return build_command_parts
return command_list("save", ["-o", destination, image], **kwds)
def build_pull_command(
tag,
**kwds
):
build_command_parts = __docker_prefix(**kwds)
build_command_parts.extend(["pull", tag])
return build_command_parts
return command_list("pull", [tag], **kwds)
def build_docker_cache_command(
image,
**kwds
):
inspect_command_parts = __docker_prefix(**kwds)
inspect_command_parts.extend(["inspect", image])
inspect_image_command = " ".join(inspect_command_parts)
pull_command_parts = __docker_prefix(**kwds)
pull_command_parts.extend(["pull", image])
pull_image_command = " ".join(pull_command_parts)
inspect_image_command = command_shell("inspect", [image], **kwds)
pull_image_command = command_shell("pull", [image], **kwds)
cache_command = "%s > /dev/null 2>&1\n[ $? -ne 0 ] && %s > /dev/null 2>&1\n" % (inspect_image_command, pull_image_command)
return cache_command
def build_docker_images_command(truncate=True, **kwds):
images_command_parts = __docker_prefix(**kwds)
images_command_parts.append("images")
if not truncate:
images_command_parts.append("--no-trunc")
return " ".join(images_command_parts)
args = ["--no-trunc"] if not truncate else[]
return command_shell("images", args, **kwds)
def build_docker_load_command(**kwds):
load_command_parts = __docker_prefix(**kwds)
load_command_parts.append("load")
return " ".join(load_command_parts)
return command_shell("load", [])
def build_docker_run_command(
@@ -135,7 +140,7 @@ def build_docker_run_command(
set_user=DEFAULT_SET_USER,
host=DEFAULT_HOST,
):
command_parts = __docker_prefix(
command_parts = _docker_prefix(
docker_cmd=docker_cmd,
sudo=sudo,
sudo_cmd=sudo_cmd,
@@ -147,19 +152,19 @@ def build_docker_run_command(
if terminal:
command_parts.append("-t")
for env_directive in env_directives:
command_parts.extend(["-e", env_directive])
command_parts.extend(["-e", shell_quote(env_directive)])
for volume in volumes:
command_parts.extend(["-v", str(volume)])
command_parts.extend(["-v", shell_quote(str(volume))])
if volumes_from:
command_parts.extend(["--volumes-from", str(volumes_from)])
command_parts.extend(["--volumes-from", shell_quote(str(volumes_from))])
if memory:
command_parts.extend(["-m", memory])
command_parts.extend(["-m", shell_quote(memory)])
if name:
command_parts.extend(["-name", name])
command_parts.extend(["--name", shell_quote(name)])
if working_directory:
command_parts.extend(["-w", working_directory])
command_parts.extend(["-w", shell_quote(working_directory)])
if net:
command_parts.extend(["--net", net])
command_parts.extend(["--net", shell_quote(net)])
if auto_rm:
command_parts.append("--rm")
if run_extra_arguments:
@@ -172,20 +177,31 @@ def build_docker_run_command(
full_image = image
if tag:
full_image = "%s:%s" % (full_image, tag)
command_parts.append(full_image)
command_parts.append(shell_quote(full_image))
command_parts.append(container_command)
return " ".join(command_parts)
def __docker_prefix(
def command_list(command, command_args=[], **kwds):
"""Return Docker command as an argv list."""
command_parts = _docker_prefix(**kwds)
command_parts.extend(command_parts)
return command_parts
def command_shell(command, command_args=[], **kwds):
"""Return Docker command as a string for a shell."""
return argv_to_str(command_list(command, command_args, **kwds))
def _docker_prefix(
docker_cmd=DEFAULT_DOCKER_COMMAND,
sudo=DEFAULT_SUDO,
sudo_cmd=DEFAULT_SUDO_COMMAND,
host=DEFAULT_HOST,
**kwds
):
""" Prefix to issue a docker command.
"""
"""Prefix to issue a docker command."""
command_parts = []
if sudo:
command_parts.append(sudo_cmd)
+1 -1
View File
@@ -102,7 +102,7 @@ class CondaDependencyResolver(DependencyResolver, ListableDependencyResolver, In
job_directory = kwds.get("job_directory", None)
if job_directory is None:
log.warn("Conda dependency resolver not sent job directory.")
log.warning("Conda dependency resolver not sent job directory.")
return INDETERMINATE_DEPENDENCY
exact = not self.versionless or version is None
@@ -97,7 +97,7 @@ class GalaxyPackageDependency(Dependency):
def shell_commands( self, requirement ):
base_path = self.path
if self.script is None and base_path is None:
log.warn( "Failed to resolve dependency on '%s', ignoring", requirement.name )
log.warning( "Failed to resolve dependency on '%s', ignoring", requirement.name )
commands = None
elif requirement.type == 'package' and self.script is None:
commands = 'PACKAGE_BASE=%s; export PACKAGE_BASE; PATH="%s/bin:$PATH"; export PATH' % ( base_path, base_path )
+1 -1
View File
@@ -74,7 +74,7 @@ class DirectoryModuleChecker(object):
self.module_dependency_resolver = module_dependency_resolver
self.directories = modulepath.split(pathsep)
if prefetch:
log.warn("Created module dependency resolver with prefetch enabled, but directory module checker does not support this.")
log.warning("Created module dependency resolver with prefetch enabled, but directory module checker does not support this.")
def has_module(self, module, version):
has_module = False
+2 -2
View File
@@ -109,7 +109,7 @@ class ToolExecutionTracker( object ):
def record_error( self, error ):
self.failed_jobs += 1
message = "There was a failure executing a job for tool [%s] - %s"
log.warn(message, self.tool.id, error)
log.warning(message, self.tool.id, error)
self.execution_errors.append( error )
def create_output_collections( self, trans, history, params ):
@@ -137,7 +137,7 @@ class ToolExecutionTracker( object ):
if not len( structure ) == len( outputs ):
# Output does not have the same structure, if all jobs were
# successfully submitted this shouldn't have happened.
log.warn( "Problem matching up datasets while attempting to create implicit dataset collections")
log.warning( "Problem matching up datasets while attempting to create implicit dataset collections")
continue
output = self.tool.outputs[ output_name ]
element_identifiers = structure.element_identifiers_for_outputs( trans, outputs )
+1 -1
View File
@@ -26,7 +26,7 @@ CWL_EXTENSIONS = YAML_EXTENSIONS + [".cwl"]
def load_exception_handler(path, exc_info):
"""Default exception handler for use by load_tool_elements_from_path."""
log.warn(LOAD_FAILURE_ERROR % path, exc_info=exc_info)
log.warning(LOAD_FAILURE_ERROR % path, exc_info=exc_info)
def find_possible_tools_from_path(
+44 -46
View File
@@ -25,9 +25,12 @@ from .dataset_matcher import DatasetCollectionMatcher
from galaxy.web import url_for
from galaxy.util.dictifiable import Dictifiable
import galaxy.model
from galaxy.util.bunch import Bunch
log = logging.getLogger(__name__)
workflow_building_modes = Bunch( DISABLED=False, ENABLED=True, USE_HISTORY=1 )
WORKFLOW_PARAMETER_REGULAR_EXPRESSION = re.compile( '''\$\{.+?\}''' )
@@ -171,7 +174,9 @@ class ToolParameter( object, Dictifiable ):
Convert a value to a text representation suitable for displaying to
the user
"""
return unicodify( value )
if value:
return unicodify( value )
return "Not available."
def to_param_dict_string( self, value, other_values={} ):
"""Called via __str__ when used in the Cheetah template"""
@@ -264,7 +269,7 @@ class TextToolParameter( ToolParameter ):
def validate( self, value, trans=None ):
search = self.type == "text"
if not ( trans and trans.workflow_building_mode and contains_workflow_parameter(value, search=search) ):
if not ( trans and trans.workflow_building_mode is workflow_building_modes.ENABLED and contains_workflow_parameter(value, search=search) ):
return super( TextToolParameter, self ).validate( value, trans )
def get_initial_value( self, trans, other_values ):
@@ -331,11 +336,11 @@ class IntegerToolParameter( TextToolParameter ):
try:
return int( value )
except:
if contains_workflow_parameter( value ) and trans.workflow_building_mode:
if contains_workflow_parameter( value ) and trans.workflow_building_mode is workflow_building_modes.ENABLED:
return value
if not value and self.optional:
return ""
if trans.workflow_building_mode:
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
raise ValueError( "An integer or workflow parameter e.g. ${name} is required" )
else:
raise ValueError( "An integer is required" )
@@ -411,11 +416,11 @@ class FloatToolParameter( TextToolParameter ):
try:
return float( value )
except:
if contains_workflow_parameter( value ) and trans.workflow_building_mode:
if contains_workflow_parameter( value ) and trans.workflow_building_mode is workflow_building_modes.ENABLED:
return value
if not value and self.optional:
return ""
if trans and trans.workflow_building_mode:
if trans and trans.workflow_building_mode is workflow_building_modes.ENABLED:
raise ValueError( "A real number or workflow parameter e.g. ${name} is required" )
else:
raise ValueError( "A real number is required" )
@@ -986,7 +991,9 @@ class SelectToolParameter( ToolParameter ):
for t, v, s in options:
if v in value:
rval.append( t )
return "\n".join( rval )
if rval:
return "\n".join( rval )
return "Nothing selected."
def get_dependencies( self ):
"""
@@ -1001,15 +1008,7 @@ class SelectToolParameter( ToolParameter ):
d = super( SelectToolParameter, self ).to_dict( trans )
# Get options, value.
options = []
try:
options = self.get_options( trans, other_values )
except AssertionError:
# we dont/cant set other_values (the {} above), so params that require other params to be filled will error:
# required dependency in filter_options
# associated DataToolParam in get_column_list
pass
options = self.get_options( trans, other_values )
d[ 'options' ] = options
if options:
value = options[0][1]
@@ -1191,10 +1190,8 @@ class ColumnListParameter( SelectToolParameter ):
Generate a select list containing the columns of the associated
dataset (if found).
"""
# No value indicates a configuration error
assert self.data_ref in other_values, "Value for associated data reference not found (data_ref)."
# Get the value of the associated data reference (a dataset)
dataset = other_values[ self.data_ref ]
dataset = other_values.get( self.data_ref, None )
# Check if a dataset is selected
if not dataset:
return []
@@ -1228,8 +1225,7 @@ class ColumnListParameter( SelectToolParameter ):
"""
options = []
if self.usecolnames: # read first row - assume is a header with metadata useful for making good choices
assert self.data_ref in other_values, "Value for associated data reference not found (data_ref)."
dataset = other_values[ self.data_ref ]
dataset = other_values.get( self.data_ref, None )
try:
head = open( dataset.get_file_name(), 'r' ).readline()
cnames = head.rstrip().split( '\t' )
@@ -1256,6 +1252,8 @@ class ColumnListParameter( SelectToolParameter ):
return SelectToolParameter.get_initial_value( self, trans, other_values )
def get_legal_values( self, trans, other_values ):
if self.data_ref not in other_values:
raise ValueError( "Value for associated data reference not found (data_ref)." )
return set( self.get_column_list( trans, other_values ) )
def get_dependencies( self ):
@@ -1484,15 +1482,16 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
value = value.split( "\n" )
return value
if not value and not self.optional:
raise ValueError( "An invalid option was selected for %s, 'None', please verify" % (self.name) )
raise ValueError( "An invalid option was selected for %s, please verify." % (self.name) )
if not value:
return None
if not isinstance( value, list ):
value = [ value ]
if not( self.repeat ) and len( value ) > 1:
assert self.multiple, "Multiple values provided but parameter %s is not expecting multiple values" % self.name
if not self.repeat and len( value ) > 1 and not self.multiple:
raise ValueError( "Multiple values provided but parameter %s is not expecting multiple values." % self.name )
rval = []
assert legal_values, "Parameter %s requires a value, but has no legal values defined" % self.name
if not legal_values:
raise ValueError( "Parameter %s requires a value, but has no legal values defined." % self.name )
for val in value:
if val not in legal_values:
raise ValueError( "An invalid option was selected for %s, %r, please verify" % ( self.name, val ) )
@@ -1529,9 +1528,8 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
for val in value:
options = get_options_list( val )
rval.extend( options )
if len( rval ) > 1:
if not self.repeat:
assert self.multiple, "Multiple values provided but parameter is not expecting multiple values"
if not self.repeat and len( rval ) > 1 and not self.multiple:
raise ValueError( "Multiple values provided but parameter %s is not expecting multiple values." % self.name )
rval = self.separator.join( map( value_map, rval ) )
if self.tool is None or self.tool.options.sanitize:
if self.sanitizer:
@@ -1583,7 +1581,9 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
rval = []
for val in value:
rval.append( get_option_display( val, self.options ) or val )
return "\n".join( map( str, rval ) )
if rval:
return "\n".join( map( str, rval ) )
return "Nothing selected."
def get_dependencies( self ):
"""
@@ -1594,15 +1594,7 @@ class DrillDownSelectToolParameter( SelectToolParameter ):
def to_dict( self, trans, view='collection', value_mapper=None, other_values={} ):
# skip SelectToolParameter (the immediate parent) bc we need to get options in a different way here
d = ToolParameter.to_dict( self, trans )
options = []
try:
options = self.get_options( trans=trans, other_values=other_values )
except KeyError:
# will sometimes error if self.is_dynamic and self.filtered
# bc we dont/cant fill out other_values above ({})
pass
d['options'] = options
d['options'] = self.get_options( trans=trans, other_values=other_values )
d['display'] = self.display
return d
@@ -1871,7 +1863,7 @@ class DataToolParameter( BaseDataToolParameter ):
return ''
def from_json( self, value, trans, other_values={} ):
if trans.workflow_building_mode:
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
return None
if not value and not self.optional:
raise ValueError( "History does not include a dataset of the required format / build" )
@@ -1937,8 +1929,11 @@ class DataToolParameter( BaseDataToolParameter ):
raise ValueError( "The previously selected dataset has entered an unusable state" )
if not self.multiple:
if len( values ) > 1:
raise ValueError( "More than one dataset supplied to single input dataset parameter.")
rval = values[ 0 ]
raise ValueError( "More than one dataset supplied to single input dataset parameter." )
if len( values ) > 0:
rval = values[ 0 ]
else:
raise ValueError( "Invalid dataset supplied to single input dataset parameter." )
return rval
def to_param_dict_string( self, value, other_values={} ):
@@ -1954,7 +1949,7 @@ class DataToolParameter( BaseDataToolParameter ):
return ", ".join( [ "%s: %s" % ( item.hid, item.name ) for item in value ] )
except:
pass
return "No dataset"
return "No dataset."
def validate( self, value, trans=None ):
dataset_count = 0
@@ -2035,10 +2030,13 @@ class DataToolParameter( BaseDataToolParameter ):
d = super( DataToolParameter, self ).to_dict( trans )
extensions = self.extensions
all_edam_formats = self._datatypes_registery( trans, self.tool ).edam_formats
all_edam_data = self._datatypes_registery( trans, self.tool ).edam_data
edam_formats = map(lambda ext: all_edam_formats.get(ext, None),
extensions)
edam_data = map(lambda ext: all_edam_data.get(ext, None), extensions)
d['extensions'] = extensions
d['edam_formats'] = edam_formats
d['edam'] = {'edam_formats': edam_formats, 'edam_data': edam_data}
d['multiple'] = self.multiple
if self.multiple:
# For consistency, should these just always be in the dict?
@@ -2048,7 +2046,7 @@ class DataToolParameter( BaseDataToolParameter ):
# return dictionary without options if context is unavailable
history = trans.history
if history is None or trans.workflow_building_mode:
if history is None or trans.workflow_building_mode is workflow_building_modes.ENABLED:
return d
# prepare dataset/collection matching
@@ -2149,7 +2147,7 @@ class DataCollectionToolParameter( BaseDataToolParameter ):
return field
def from_json( self, value, trans, other_values={} ):
if trans.workflow_building_mode:
if trans.workflow_building_mode is workflow_building_modes.ENABLED:
return None
if not value and not self.optional:
raise ValueError( "History does not include a dataset collection of the correct type or containing the correct types of datasets" )
@@ -2210,7 +2208,7 @@ class DataCollectionToolParameter( BaseDataToolParameter ):
# return dictionary without options if context is unavailable
history = trans.history
if history is None or trans.workflow_building_mode or other_values is None:
if history is None or trans.workflow_building_mode is workflow_building_modes.ENABLED or other_values is None:
return d
# prepare dataset/collection matching
@@ -124,7 +124,6 @@ class DataMetaFilter( Filter ):
if self.multiple:
return dataset_value in file_value.split( self.separator )
return file_value == dataset_value
assert self.ref_name in other_values or ( trans is not None and trans.workflow_building_mode), "Required dependency '%s' not found in incoming values" % self.ref_name
ref = other_values.get( self.ref_name, None )
is_data = isinstance( ref, galaxy.tools.wrappers.DatasetFilenameWrapper )
is_data_list = isinstance( ref, galaxy.tools.wrappers.DatasetListWrapper ) or isinstance( ref, list )
@@ -146,7 +145,7 @@ class DataMetaFilter( Filter ):
else:
meta_value = ref.metadata.get( self.key, None )
if meta_value is None: # assert meta_value is not None, "Required metadata value '%s' not found in referenced dataset" % self.key
if meta_value is None:
return [ ( disp_name, optval, selected ) for disp_name, optval, selected in options ]
if self.column is not None:
@@ -208,7 +207,6 @@ class ParamValueFilter( Filter ):
def filter_options( self, options, trans, other_values ):
if trans is not None and trans.workflow_building_mode:
return []
assert self.ref_name in other_values, "Required dependency '%s' not found in incoming values" % self.ref_name
ref = other_values.get( self.ref_name, None )
for ref_attribute in self.ref_attribute:
if not hasattr( ref, ref_attribute ):
@@ -381,7 +379,6 @@ class RemoveValueFilter( Filter ):
def filter_options( self, options, trans, other_values ):
if trans is not None and trans.workflow_building_mode:
return options
assert self.value is not None or ( self.ref_name is not None and self.ref_name in other_values ) or (self.meta_ref is not None and self.meta_ref in other_values ) or ( trans is not None and trans.workflow_building_mode), Exception( "Required dependency '%s' or '%s' not found in incoming values" % ( self.ref_name, self.meta_ref ) )
def compare_value( option_value, filter_value ):
if isinstance( filter_value, list ):
@@ -494,7 +491,7 @@ class DynamicOptions( object ):
self.missing_index_file = self.tool_data_table.missing_index_file
else:
self.missing_tool_data_table_name = tool_data_table_name
log.warn( "Data table named '%s' is required by tool but not configured" % tool_data_table_name )
log.warning( "Data table named '%s' is required by tool but not configured" % tool_data_table_name )
# Options are defined by parsing tabular text data from a data file
# on disk, a dataset, or the value of another parameter
elif data_file is not None or dataset_file is not None or from_parameter is not None:
@@ -559,7 +556,7 @@ class DynamicOptions( object ):
except AttributeError:
name = "a configuration file"
# Perhaps this should be an error, but even a warning is useful.
log.warn( "Inconsistent number of fields (%i vs %i) in %s using separator %r, check line: %r" %
log.warning( "Inconsistent number of fields (%i vs %i) in %s using separator %r, check line: %r" %
( field_count, len( fields ), name, self.separator, line ) )
rval.append( fields )
return rval
@@ -582,7 +579,6 @@ class DynamicOptions( object ):
if self.dataset_ref_name:
dataset = other_values.get( self.dataset_ref_name, None )
if not dataset or not hasattr( dataset, 'file_name' ):
log.warn( "Required dataset '%s' missing from input" % self.dataset_ref_name )
return [] # no valid dataset in history
# Ensure parsing dynamic options does not consume more than a megabyte worth memory.
path = dataset.file_name
@@ -591,7 +587,7 @@ class DynamicOptions( object ):
else:
# Pass just the first megabyte to parse_file_fields.
import StringIO
log.warn( "Attempting to load options from large file, reading just first megabyte" )
log.warning( "Attempting to load options from large file, reading just first megabyte" )
contents = open( path, 'r' ).read( 1048576 )
options = self.parse_file_fields( StringIO.StringIO( contents ) )
elif self.tool_data_table:
@@ -62,6 +62,8 @@ class ToolOutput( ToolOutputBase ):
if format and format != "input" and app:
edam_format = app.datatypes_registry.edam_formats.get(self.format)
as_dict["edam_format"] = edam_format
edam_data = app.datatypes_registry.edam_data.get(self.format)
as_dict["edam_data"] = edam_data
return as_dict
+28 -14
View File
@@ -78,6 +78,18 @@ class XmlToolSource(ToolSource):
def parse_name(self):
return self.root.get( "name" )
def parse_edam_operations(self):
edam_ops = self.root.find("edam_operations")
if edam_ops is None:
return []
return [ edam_op.text for edam_op in edam_ops.findall("edam_operation") ]
def parse_edam_topics(self):
edam_topics = self.root.find("edam_topics")
if edam_topics is None:
return []
return [ edam_topic.text for edam_topic in edam_topics.findall("edam_topic") ]
def parse_description(self):
return xml_text(self.root, "description")
@@ -117,7 +129,7 @@ class XmlToolSource(ToolSource):
command_el = self._command_el
interpreter = (command_el is not None) and command_el.get("interpreter", None)
if not self.legacy_defaults:
log.warn("Deprecated interpeter attribute on command element is now ignored.")
log.warning("Deprecated interpeter attribute on command element is now ignored.")
interpreter = None
return interpreter
@@ -426,7 +438,11 @@ def __parse_element_tests( parent_element ):
def __parse_test_attributes( output_elem, attrib, parse_elements=False ):
assert_list = __parse_assert_list( output_elem )
file = attrib.pop( 'file', None )
# Allow either file or value to specify a target file to compare result with
# file was traditionally used by outputs and value by extra files.
file = attrib.pop( 'file', attrib.pop( 'value', None ) )
# File no longer required if an list of assertions was present.
attributes = {}
# Method of comparison
@@ -445,16 +461,19 @@ def __parse_test_attributes( output_elem, attrib, parse_elements=False ):
for metadata_elem in output_elem.findall( 'metadata' ):
metadata[ metadata_elem.get('name') ] = metadata_elem.get( 'value' )
md5sum = attrib.get("md5", None)
checksum = attrib.get("checksum", None)
element_tests = {}
if parse_elements:
element_tests = __parse_element_tests( output_elem )
if not (assert_list or file or extra_files or metadata or md5sum or element_tests):
raise Exception( "Test output defines nothing to check (e.g. must have a 'file' check against, assertions to check, metadata or md5 tests, etc...)")
has_checksum = md5sum or checksum
if not (assert_list or file or extra_files or metadata or has_checksum or element_tests):
raise Exception( "Test output defines nothing to check (e.g. must have a 'file' check against, assertions to check, metadata or checksum tests, etc...)")
attributes['assert_list'] = assert_list
attributes['extra_files'] = extra_files
attributes['metadata'] = metadata
attributes['md5'] = md5sum
attributes['checksum'] = checksum
attributes['elements'] = element_tests
return file, attributes
@@ -484,20 +503,15 @@ def __parse_assert_list_from_elem( assert_elem ):
return assert_list
def __parse_extra_files_elem( extra ):
def __parse_extra_files_elem(extra):
# File or directory, when directory, compare basename
# by basename
extra_type = extra.get( 'type', 'file' )
extra_name = extra.get( 'name', None )
attrib = dict(extra.attrib)
extra_type = attrib.pop('type', 'file')
extra_name = attrib.pop('name', None)
assert extra_type == 'directory' or extra_name is not None, \
'extra_files type (%s) requires a name attribute' % extra_type
extra_value = extra.get( 'value', None )
assert extra_value is not None, 'extra_files requires a value attribute'
extra_attributes = {}
extra_attributes['compare'] = extra.get( 'compare', 'diff' ).lower()
extra_attributes['delta'] = extra.get( 'delta', '0' )
extra_attributes['lines_diff'] = int( extra.get( 'lines_diff', '0' ) )
extra_attributes['sort'] = string_as_bool( extra.get( 'sort', False ) )
extra_value, extra_attributes = __parse_test_attributes(extra, attrib)
return extra_type, extra_value, extra_name, extra_attributes
+6
View File
@@ -33,6 +33,12 @@ class YamlToolSource(ToolSource):
def parse_description(self):
return self.root_dict.get("description", "")
def parse_edam_operations(self):
return self.root_dict.get("edam_operations", [])
def parse_edam_topics(self):
return self.root_dict.get("edam_topics", [])
def parse_is_multi_byte(self):
return self.root_dict.get("is_multi_byte", self.default_is_multi_byte)
+10 -6
View File
@@ -23,19 +23,23 @@ def get_observer_class(config_value, default, monitor_what_str):
config_value = config_value or default
config_value = str(config_value).lower()
if config_value in ("true", "yes", "on", "auto"):
expect_observer = config_value != "auto"
expect_observer = True
observer_class = Observer
elif config_value == "polling":
expect_observer = True
observer_class = PollingObserver
else:
elif config_value in ('false', 'no', 'off'):
expect_observer = False
observer_class = None
else:
message = "Unrecognized value for watch_tools config option: %s" % config_value
raise Exception(message)
if observer_class is None:
message = "Watchdog library unavailble, cannot monitor %s." % monitor_what_str
log.info(message)
if expect_observer:
if expect_observer and observer_class is None:
message = "Watchdog library unavailable, cannot monitor %s." % monitor_what_str
if config_value == "auto":
log.info(message)
else:
raise Exception(message)
return observer_class
+289
View File
@@ -0,0 +1,289 @@
"""Module of utilities for verifying test results."""
import difflib
import filecmp
import hashlib
import logging
import os
import re
import shutil
import subprocess
import tempfile
from .asserts import verify_assertions
from .test_data import TestDataResolver
log = logging.getLogger(__name__)
DEFAULT_TEST_DATA_RESOLVER = TestDataResolver()
def verify(
item_label,
output_content,
attributes,
filename=None,
get_filename=None,
keep_outputs_dir=None,
verify_extra_files=None,
):
"""Verify the content of a test output using test definitions described by attributes.
Throw an informative assertion error if any of these tests fail.
"""
if get_filename is None:
get_filename = DEFAULT_TEST_DATA_RESOLVER.get_filename
# Check assertions...
assertions = attributes.get("assert_list", None)
if attributes is not None and assertions is not None:
try:
verify_assertions(output_content, attributes["assert_list"])
except AssertionError as err:
errmsg = '%s different than expected\n' % (item_label)
errmsg += str( err )
raise AssertionError( errmsg )
# Verify checksum attributes...
# works with older Galaxy style md5=<expected_sum> or cwltest
# style checksum=<hash_type>$<hash>.
expected_checksum_type = None
expected_checksum = None
if attributes is not None and attributes.get("md5", None) is not None:
expected_checksum_type = "md5"
expected_checksum = attributes.get("md5")
elif attributes is not None and attributes.get("checksum", None) is not None:
checksum_value = attributes.get("checksum", None)
expected_checksum_type, expected_checksum = checksum_value.split("$", 1)
if expected_checksum_type:
try:
_verify_checksum(output_content, expected_checksum_type, expected_checksum)
except AssertionError as err:
errmsg = '%s different than expected\n' % (item_label)
errmsg += str( err )
raise AssertionError( errmsg )
if filename is not None:
local_name = get_filename(filename)
temp_name = make_temp_fname(fname=filename)
with open(temp_name, 'wb') as f:
f.write(output_content)
# if the server's env has GALAXY_TEST_SAVE, save the output file to that dir
if keep_outputs_dir:
ofn = os.path.join(keep_outputs_dir, os.path.basename(local_name))
log.debug('keep_outputs_dir: %s, ofn: %s', keep_outputs_dir, ofn)
try:
shutil.copy( temp_name, ofn )
except Exception as exc:
error_log_msg = 'Could not save output file %s to %s: ' % (temp_name, ofn)
error_log_msg += str(exc)
log.error(error_log_msg, exc_info=True)
else:
log.debug('## GALAXY_TEST_SAVE=%s. saved %s' % (keep_outputs_dir, ofn))
try:
if attributes is None:
attributes = {}
compare = attributes.get('compare', 'diff')
if attributes.get('ftype', None) == 'bam':
local_fh, temp_name = _bam_to_sam(local_name, temp_name)
local_name = local_fh.name
if compare == 'diff':
files_diff(local_name, temp_name, attributes=attributes)
elif compare == 're_match':
files_re_match( local_name, temp_name, attributes=attributes )
elif compare == 're_match_multiline':
files_re_match_multiline( local_name, temp_name, attributes=attributes )
elif compare == 'sim_size':
delta = attributes.get('delta', '100')
s1 = len(output_content)
s2 = os.path.getsize(local_name)
if abs(s1 - s2) > int(delta):
raise AssertionError( 'Files %s=%db but %s=%db - compare by size (delta=%s) failed' % (temp_name, s1, local_name, s2, delta) )
elif compare == "contains":
files_contains( local_name, temp_name, attributes=attributes )
else:
raise Exception( 'Unimplemented Compare type: %s' % compare )
if verify_extra_files:
extra_files = attributes.get('extra_files', None)
if extra_files:
verify_extra_files(extra_files)
except AssertionError as err:
errmsg = '%s different than expected, difference (using %s):\n' % ( item_label, compare )
errmsg += "( %s v. %s )\n" % ( local_name, temp_name )
errmsg += str( err )
raise AssertionError( errmsg )
finally:
if 'GALAXY_TEST_NO_CLEANUP' not in os.environ:
os.remove( temp_name )
def make_temp_fname(fname=None):
"""Safe temp name - preserve the file extension for tools that interpret it."""
suffix = os.path.split(fname)[-1] # ignore full path
fd, temp_prefix = tempfile.mkstemp(prefix='tmp', suffix=suffix)
return temp_prefix
def _bam_to_sam(local_name, temp_name):
temp_local = tempfile.NamedTemporaryFile( suffix='.sam', prefix='local_bam_converted_to_sam_' )
fd, temp_temp = tempfile.mkstemp( suffix='.sam', prefix='history_bam_converted_to_sam_' )
os.close( fd )
command = 'samtools view -h -o "%s" "%s"' % ( temp_local.name, local_name )
check_command( command, 'Converting local (test-data) bam to sam' )
command = 'samtools view -h -o "%s" "%s"' % ( temp_temp, temp_name )
check_command( command, 'Converting history bam to sam ' )
os.remove( temp_name )
return temp_local, temp_temp
def _verify_checksum(data, checksum_type, expected_checksum_value):
if checksum_type not in ["md5", "sha1", "sha256", "sha512"]:
raise Exception("Unimplemented hash algorithm [%s] encountered." % checksum_type)
h = hashlib.new(checksum_type)
h.update( data )
actual_checksum_value = h.hexdigest()
if expected_checksum_value != actual_checksum_value:
template = "Output checksum [%s] does not match expected [%s] (using hash algorithm %s)."
message = template % (actual_checksum_value, expected_checksum_value, checksum_type)
raise AssertionError(message)
def check_command(command, description):
"""Verify a command runs with an exit code of 0."""
# TODO: also collect ``which samtools`` and ``samtools --version``
p = subprocess.Popen( args=command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )
(stdout, stderr) = p.communicate()
if p.returncode:
template = description
template += " failed: (cmd=[%s], stdout=[%s], stderr=[%s])"
message = template % (command, stdout, stderr)
raise AssertionError(message)
def files_diff(file1, file2, attributes=None):
"""Check the contents of 2 files for differences."""
def get_lines_diff( diff ):
count = 0
for line in diff:
if ( line.startswith( '+' ) and not line.startswith( '+++' ) ) or ( line.startswith( '-' ) and not line.startswith( '---' ) ):
count += 1
return count
if not filecmp.cmp( file1, file2 ):
files_differ = False
local_file = open( file1, 'U' ).readlines()
history_data = open( file2, 'U' ).readlines()
if attributes is None:
attributes = {}
if attributes.get( 'sort', False ):
history_data.sort()
# Why even bother with the check loop below, why not just use the diff output? This seems wasteful.
if len( local_file ) == len( history_data ):
for i in range( len( history_data ) ):
if local_file[i].rstrip( '\r\n' ) != history_data[i].rstrip( '\r\n' ):
files_differ = True
break
else:
files_differ = True
if files_differ:
allowed_diff_count = int(attributes.get( 'lines_diff', 0 ))
diff = list( difflib.unified_diff( local_file, history_data, "local_file", "history_data" ) )
diff_lines = get_lines_diff( diff )
if diff_lines > allowed_diff_count:
if 'GALAXY_TEST_RAW_DIFF' in os.environ:
diff_slice = diff
else:
if len(diff) < 60:
diff_slice = diff[0:40]
else:
diff_slice = diff[:25] + ["********\n", "*SNIP *\n", "********\n"] + diff[-25:]
# FIXME: This pdf stuff is rather special cased and has not been updated to consider lines_diff
# due to unknown desired behavior when used in conjunction with a non-zero lines_diff
# PDF forgiveness can probably be handled better by not special casing by __extension__ here
# and instead using lines_diff or a regular expression matching
# or by creating and using a specialized pdf comparison function
if file1.endswith( '.pdf' ) or file2.endswith( '.pdf' ):
# PDF files contain creation dates, modification dates, ids and descriptions that change with each
# new file, so we need to handle these differences. As long as the rest of the PDF file does
# not differ we're ok.
valid_diff_strs = [ 'description', 'createdate', 'creationdate', 'moddate', 'id', 'producer', 'creator' ]
valid_diff = False
invalid_diff_lines = 0
for line in diff_slice:
# Make sure to lower case strings before checking.
line = line.lower()
# Diff lines will always start with a + or - character, but handle special cases: '--- local_file \n', '+++ history_data \n'
if ( line.startswith( '+' ) or line.startswith( '-' ) ) and line.find( 'local_file' ) < 0 and line.find( 'history_data' ) < 0:
for vdf in valid_diff_strs:
if line.find( vdf ) < 0:
valid_diff = False
else:
valid_diff = True
# Stop checking as soon as we know we have a valid difference
break
if not valid_diff:
invalid_diff_lines += 1
log.info('## files diff on %s and %s lines_diff=%d, found diff = %d, found pdf invalid diff = %d' % (file1, file2, allowed_diff_count, diff_lines, invalid_diff_lines))
if invalid_diff_lines > allowed_diff_count:
# Print out diff_slice so we can see what failed
log.info("###### diff_slice ######")
raise AssertionError( "".join( diff_slice ) )
else:
log.info('## files diff on %s and %s lines_diff=%d, found diff = %d' % (file1, file2, allowed_diff_count, diff_lines))
for line in diff_slice:
for char in line:
if ord( char ) > 128:
raise AssertionError( "Binary data detected, not displaying diff" )
raise AssertionError( "".join( diff_slice ) )
def files_re_match(file1, file2, attributes=None):
"""Check the contents of 2 files for differences using re.match."""
local_file = open( file1, 'U' ).readlines() # regex file
history_data = open( file2, 'U' ).readlines()
assert len( local_file ) == len( history_data ), 'Data File and Regular Expression File contain a different number of lines (%s != %s)\nHistory Data (first 40 lines):\n%s' % ( len( local_file ), len( history_data ), ''.join( history_data[:40] ) )
if attributes is None:
attributes = {}
if attributes.get( 'sort', False ):
history_data.sort()
lines_diff = int(attributes.get( 'lines_diff', 0 ))
line_diff_count = 0
diffs = []
for i in range( len( history_data ) ):
if not re.match( local_file[i].rstrip( '\r\n' ), history_data[i].rstrip( '\r\n' ) ):
line_diff_count += 1
diffs.append( 'Regular Expression: %s\nData file : %s' % ( local_file[i].rstrip( '\r\n' ), history_data[i].rstrip( '\r\n' ) ) )
if line_diff_count > lines_diff:
raise AssertionError( "Regular expression did not match data file (allowed variants=%i):\n%s" % ( lines_diff, "".join( diffs ) ) )
def files_re_match_multiline(file1, file2, attributes=None):
"""Check the contents of 2 files for differences using re.match in multiline mode."""
local_file = open( file1, 'U' ).read() # regex file
if attributes is None:
attributes = {}
if attributes.get( 'sort', False ):
history_data = open( file2, 'U' ).readlines()
history_data.sort()
history_data = ''.join( history_data )
else:
history_data = open( file2, 'U' ).read()
# lines_diff not applicable to multiline matching
assert re.match( local_file, history_data, re.MULTILINE ), "Multiline Regular expression did not match data file"
def files_contains(file1, file2, attributes=None):
"""Check the contents of file2 for substrings found in file1, on a per-line basis."""
local_file = open( file1, 'U' ).readlines() # regex file
# TODO: allow forcing ordering of contains
history_data = open( file2, 'U' ).read()
lines_diff = int( attributes.get( 'lines_diff', 0 ) )
line_diff_count = 0
while local_file:
contains = local_file.pop( 0 ).rstrip( '\n\r' )
if contains not in history_data:
line_diff_count += 1
if line_diff_count > lines_diff:
raise AssertionError( "Failed to find '%s' in history data. (lines_diff=%i):\n" % ( contains, lines_diff ) )
@@ -12,7 +12,7 @@ assertion_module_names = ['text', 'tabular', 'xml']
# <MODULE_NAME> to the list of assertion module names defined above.
assertion_modules = []
for assertion_module_name in assertion_module_names:
full_assertion_module_name = 'base.asserts.' + assertion_module_name
full_assertion_module_name = 'galaxy.tools.verify.asserts.' + assertion_module_name
log.debug(full_assertion_module_name)
try:
# Dynamically import module
+2 -2
View File
@@ -729,7 +729,7 @@ def rst_to_html( s ):
class FakeStream( object ):
def write( self, str ):
if len( str ) > 0 and not str.isspace():
log.warn( str )
log.warning( str )
settings_overrides = {
"embed_stylesheet": False,
@@ -1351,7 +1351,7 @@ def config_directories_from_setting( directories_setting, galaxy_root=galaxy_roo
if not directory.startswith( '/' ):
directory = os.path.join( galaxy_root, directory )
if not os.path.exists( directory ):
log.warn( 'directory not found: %s', directory )
log.warning( 'directory not found: %s', directory )
continue
directories.append( directory )
return directories
+12
View File
@@ -140,3 +140,15 @@ def is_bz2( file_path ):
def is_gzip( file_path ):
is_gzipped, is_valid = check_gzip( file_path )
return is_gzipped
__all__ = [
'check_binary',
'check_bz2',
'check_gzip',
'check_html',
'check_image',
'check_zip',
'is_gzip',
'is_bz2',
]
@@ -1483,7 +1483,7 @@ class ENCODEPeakDataProvider( GenomeDataProvider ):
"""
def get_iterator( self, data_file, chrom, start, end, **kwargs ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
"""
@@ -283,7 +283,7 @@ class DataSourceParser( object ):
test_type = test_elem.get( 'type', 'eq' )
test_result = test_elem.text.strip() if test_elem.text else None
if not test_type or not test_result:
log.warn( 'Skipping test. Needs both type attribute and text node to be parsed: ' +
log.warning( 'Skipping test. Needs both type attribute and text node to be parsed: ' +
'%s, %s' % ( test_type, test_elem.text ) )
continue
test_result = test_result.strip()
+1 -1
View File
@@ -203,7 +203,7 @@ class VisualizationsRegistry( pluginframework.PageServingPluginManager ):
if not test_result:
# but continue (with other tests) if can't find class by that name
# if self.debug:
# log.warn( 'visualizations_registry cannot find class (%s)' +
# log.warning( 'visualizations_registry cannot find class (%s)' +
# ' for applicability test on: %s, id: %s', datatype_class_name,
# target_object, getattr( target_object, 'id', '' ) )
continue
@@ -78,7 +78,7 @@ class ResourceParser( object ):
if trans.debug:
raise
else:
log.warn( 'Exception parsing visualization param from query: %s, %s, (%s) %s',
log.warning( 'Exception parsing visualization param from query: %s, %s, (%s) %s',
param_name, query_val, str( type( exception ) ), str( exception ) )
resource = None
@@ -109,7 +109,7 @@ class ResourceParser( object ):
config_val = self.parse_parameter( trans, param_config, config_val )
except Exception as exception:
log.warn( 'Exception parsing visualization param from query: ' +
log.warning( 'Exception parsing visualization param from query: ' +
'%s, %s, (%s) %s' % ( param_name, config_val, str( type( exception ) ), str( exception ) ))
config_val = None
+1 -1
View File
@@ -80,7 +80,7 @@ class BaseController( object ):
# this should be here - but catching errors from sharable item controllers that *should* have SharableItemMixin
# but *don't* then becomes difficult
# def security_check( self, trans, item, check_ownership=False, check_accessible=False ):
# log.warn( 'BaseController.security_check: %s, %b, %b', str( item ), check_ownership, check_accessible )
# log.warning( 'BaseController.security_check: %s, %b, %b', str( item ), check_ownership, check_accessible )
# # meant to be overridden in SharableSecurityMixin
# return item
@@ -304,8 +304,8 @@ class InteractiveEnvironmentRequest(object):
log.debug( "Container id: %s" % container_id)
inspect_data = self.inspect_container(container_id)
port_mappings = self.get_container_port_mapping(inspect_data)
if self.attr.docker_hostname == 'localhost':
self.attr.docker_hostname = self.get_container_gateway_ip(inspect_data)
self.attr.docker_hostname = self.get_container_host(inspect_data)
log.debug( "Container host: %s", self.attr.docker_hostname )
if len(port_mappings) > 1:
log.warning("Don't know how to handle proxies to containers with multiple exposed ports. Arbitrarily choosing first")
elif len(port_mappings) == 0:
@@ -368,15 +368,25 @@ class InteractiveEnvironmentRequest(object):
# ]
return inspect_data
def get_container_gateway_ip(self, inspect_data):
def get_container_host(self, inspect_data):
"""
Returns gateway ip from inspect_data
Determine the ip address on the container. If inspect_data contains
Node.IP return that (e.g. running in Docker Swarm). If the hostname
is "localhost", look for NetworkSettings.Gateway. Otherwise, just
return the configured docker_hostname.
:type inspect_data: dict
:param inspect_data: output of docker inspect
:returns: gateway_ip
:returns: IP address or hostname of the node the conatainer is
running on.
"""
gateway_ip = inspect_data[0]['NetworkSettings']['Gateway']
return gateway_ip
inspect_data = inspect_data[0]
if 'Node' in inspect_data:
return inspect_data['Node']['IP']
elif self.attr.docker_hostname == "localhost":
return inspect_data['NetworkSettings']['Gateway']
else:
return self.attr.docker_hostname
def get_container_port_mapping(self, inspect_data):
"""
+1 -1
View File
@@ -93,7 +93,7 @@ class PluginManager( object ):
# NOTE: prevent silent, implicit overwrite here (two plugins in two diff directories)
# TODO: overwriting may be desired
elif plugin and plugin.name in self.plugins:
log.warn( '%s, plugin with name already exists: %s. Skipping...', self, plugin.name )
log.warning( '%s, plugin with name already exists: %s. Skipping...', self, plugin.name )
except Exception:
if not self.skip_bad_plugins:
@@ -123,6 +123,10 @@ class DatatypesController( BaseAPIController ):
def edam_formats( self, trans, **kwds ):
return self._datatypes_registry.edam_formats
@expose_api_anonymous_and_sessionless
def edam_data( self, trans, **kwds ):
return self._datatypes_registry.edam_data
@property
def _datatypes_registry( self ):
return self.app.datatypes_registry
+1 -1
View File
@@ -334,7 +334,7 @@ class WorkflowsAPIController(BaseAPIController, UsesStoredWorkflowMixin, UsesAnn
} )
# create tool model and default tool state (if missing)
tool_model = module.tool.to_json( trans, tool_inputs, workflow_mode=True )
tool_model = module.tool.to_json( trans, tool_inputs, workflow_building_mode=True )
module.update_state( tool_model[ 'state_inputs' ] )
return {
'tool_model' : tool_model,
+1 -1
View File
@@ -299,7 +299,7 @@ def populate_api_routes( webapp, app ):
webapp.mapper.resource( 'datatype',
'datatypes',
path_prefix='/api',
collection={ 'sniffers': 'GET', 'mapping': 'GET', 'converters': 'GET', 'edam_formats': 'GET' },
collection={ 'sniffers': 'GET', 'mapping': 'GET', 'converters': 'GET', 'edam_data': 'GET', 'edam_formats': 'GET' },
parent_resources=dict( member_name='datatype', collection_name='datatypes' ) )
webapp.mapper.resource( 'search', 'search', path_prefix='/api' )
webapp.mapper.resource( 'page', 'pages', path_prefix="/api")
@@ -473,7 +473,7 @@ class DatasetInterface( BaseUIController, UsesAnnotations, UsesItemRatings, Uses
assert trans.user.id == hda.history.user_id, "HistoryDatasetAssocation does not belong to current user"
hdas.append( hda )
else:
log.warn( "Invalid history_dataset_association id '%r' passed to list", hda_id )
log.warning( "Invalid history_dataset_association id '%r' passed to list", hda_id )
if hdas:
if operation == "switch" or operation == "switch_history":
@@ -24,4 +24,4 @@ class ExternalServiceController( BaseUIController ):
results = populated_action.handle_results( trans )
return results
else:
raise 'unknown item class type'
raise Exception( 'unknown item class type' )
@@ -283,7 +283,7 @@ class HistoryController( BaseUIController, SharableMixin, UsesAnnotations, UsesI
assert trans.user.id == history.user_id, "History does not belong to current user"
histories.append( history )
else:
log.warn( "Invalid history id '%r' passed to list", history_id )
log.warning( "Invalid history id '%r' passed to list", history_id )
if histories:
if operation == "switch":
status, message = self._list_switch( trans, histories )
@@ -22,10 +22,10 @@ class RBACAgent:
permitted_actions = Bunch()
def associate_components( self, **kwd ):
raise 'No valid method of associating provided components: %s' % kwd
raise Exception( 'No valid method of associating provided components: %s' % kwd )
def associate_user_role( self, user, role ):
raise 'No valid method of associating a user with a role'
raise Exception( 'No valid method of associating a user with a role' )
def convert_permitted_action_strings( self, permitted_action_strings ):
"""
@@ -35,7 +35,7 @@ class RBACAgent:
return filter( lambda x: x is not None, [ self.permitted_actions.get( action_string ) for action_string in permitted_action_strings ] )
def create_private_user_role( self, user ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
def get_action( self, name, default=None ):
"""Get a permitted action by its dict key or action name"""
@@ -49,10 +49,10 @@ class RBACAgent:
return self.permitted_actions.__dict__.values()
def get_item_actions( self, action, item ):
raise 'No valid method of retrieving action (%s) for item %s.' % ( action, item )
raise Exception( 'No valid method of retrieving action (%s) for item %s.' % ( action, item ) )
def get_private_user_role( self, user ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
class CommunityRBACAgent( RBACAgent ):
@@ -93,7 +93,7 @@ class CommunityRBACAgent( RBACAgent ):
return self.associate_group_role( kwd['group'], kwd['role'] )
elif 'repository' in kwd:
return self.associate_repository_category( kwd[ 'repository' ], kwd[ 'category' ] )
raise 'No valid method of associating provided components: %s' % kwd
raise Exception( 'No valid method of associating provided components: %s' % kwd )
def associate_group_role( self, group, role ):
assoc = self.model.GroupRoleAssociation( group, role )
+3 -3
View File
@@ -97,7 +97,7 @@ def extract_steps( trans, history=None, job_ids=None, dataset_ids=None, dataset_
# Tool steps
for job_id in job_ids:
if job_id not in jobs_by_id:
log.warn( "job_id %s not found in jobs_by_id %s" % ( job_id, jobs_by_id ) )
log.warning( "job_id %s not found in jobs_by_id %s" % ( job_id, jobs_by_id ) )
raise AssertionError( "Attempt to create workflow with job not connected to current history" )
job = jobs_by_id[ job_id ]
tool_inputs, associations = step_inputs( trans, job )
@@ -141,7 +141,7 @@ def extract_steps( trans, history=None, job_ids=None, dataset_ids=None, dataset_
if hid is None:
template = "Failed to find matching implicit job - job is %s, jobs are %s, assoc_name is %s."
message = template % ( job.id, jobs, assoc.name )
log.warn( message )
log.warning( message )
raise Exception( "Failed to extract job." )
else:
if hasattr( assoc, "dataset" ):
@@ -241,7 +241,7 @@ class WorkflowSummary( object ):
job_hda = self.__original_hda( dataset_instance )
if not job_hda.creating_job_associations:
log.warn( "An implicitly create output dataset collection doesn't have a creating_job_association, should not happen!" )
log.warning( "An implicitly create output dataset collection doesn't have a creating_job_association, should not happen!" )
job = DatasetCollectionCreationJob( dataset_collection )
self.jobs[ job ] = [ ( None, dataset_collection ) ]
@@ -465,7 +465,7 @@ class InstallRepositoryManager( object ):
message = "Error attempting to retrieve installation information from tool shed "
message += "%s for revision %s of repository %s owned by %s: %s" % \
( str( tool_shed_url ), str( changeset_revision ), str( name ), str( owner ), str( e ) )
log.warn( message )
log.warning( message )
raise exceptions.InternalServerError( message )
if raw_text:
# If successful, the response from get_repository_revision_install_info will be 3
@@ -478,7 +478,7 @@ class InstallRepositoryManager( object ):
else:
message = "Unable to retrieve installation information from tool shed %s for revision %s of repository %s owned by %s: %s" % \
( str( tool_shed_url ), str( changeset_revision ), str( name ), str( owner ), str( e ) )
log.warn( message )
log.warning( message )
raise exceptions.InternalServerError( message )
# Make sure the tool shed returned everything we need for installing the repository.
if not repository_revision_dict or not repo_info_dict:
@@ -119,10 +119,10 @@ class InstallEnvironment( object ):
stdout = output.stdout
stderr = output.stderr
if len( stdout ) > DATABASE_MAX_STRING_SIZE:
log.warn( "Length of stdout > %s, so only a portion will be saved in the database." % str( DATABASE_MAX_STRING_SIZE_PRETTY ) )
log.warning( "Length of stdout > %s, so only a portion will be saved in the database." % str( DATABASE_MAX_STRING_SIZE_PRETTY ) )
stdout = shrink_string_by_size( stdout, DATABASE_MAX_STRING_SIZE, join_by="\n..\n", left_larger=True, beginning_on_size_error=True )
if len( stderr ) > DATABASE_MAX_STRING_SIZE:
log.warn( "Length of stderr > %s, so only a portion will be saved in the database." % str( DATABASE_MAX_STRING_SIZE_PRETTY ) )
log.warning( "Length of stderr > %s, so only a portion will be saved in the database." % str( DATABASE_MAX_STRING_SIZE_PRETTY ) )
stderr = shrink_string_by_size( stderr, DATABASE_MAX_STRING_SIZE, join_by="\n..\n", left_larger=True, beginning_on_size_error=True )
if output.return_code not in [ 0 ]:
status = self.app.install_model.ToolDependency.installation_status.ERROR
@@ -82,7 +82,7 @@ class CompressedFile( object ):
if os.path.exists( absolute_filepath ):
os.chmod( absolute_filepath, unix_permissions )
else:
log.warn("Unable to change permission on extracted file '%s' as it does not exist" % absolute_filepath)
log.warning("Unable to change permission on extracted file '%s' as it does not exist" % absolute_filepath)
return os.path.abspath( os.path.join( extraction_path, common_prefix ) )
def getmembers_tar( self ):
@@ -239,10 +239,10 @@ class RecipeStep( object ):
def execute_step( self, tool_dependency, package_name, actions, action_dict, filtered_actions, env_file_builder,
install_environment, work_dir, current_dir=None, initial_download=False ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method")
def prepare_step( self, tool_dependency, action_elem, action_dict, install_environment, is_binary_download ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
class AssertDirectoryExecutable( RecipeStep ):
@@ -22,7 +22,7 @@ class RecipeTag( object ):
def process_tag_set( self, tool_shed_repository, tool_dependency, package_elem, package_name, package_version,
from_tool_migration_manager=False, tool_dependency_db_records=None ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
class SyncDatabase( object ):
+1 -1
View File
@@ -16,7 +16,7 @@ class Metadata( object ):
return repo.changelog
def is_valid_for_type( self, app, repository, revisions_to_check=None ):
raise "Unimplemented Method"
raise Exception( "Unimplemented Method" )
class TipOnly( Metadata ):
+2 -2
View File
@@ -161,7 +161,7 @@ def get_repository_dependencies( app, tool_shed_url, repository_name, repository
tool_shed_accessible = True
except Exception as e:
tool_shed_accessible = False
log.warn( "The URL\n%s\nraised the exception:\n%s\n", util.build_url( tool_shed_url, pathspec=pathspec, params=params ), e )
log.warning( "The URL\n%s\nraised the exception:\n%s\n", util.build_url( tool_shed_url, pathspec=pathspec, params=params ), e )
if tool_shed_accessible:
if len( raw_text ) > 2:
encoded_text = json.loads( raw_text )
@@ -193,7 +193,7 @@ def get_tool_dependencies( app, tool_shed_url, repository_name, repository_owner
tool_shed_accessible = True
except Exception as e:
tool_shed_accessible = False
log.warn( "The URL\n%s\nraised the exception:\n%s\n", util.build_url( tool_shed_url, pathspec=pathspec, params=params ), e )
log.warning( "The URL\n%s\nraised the exception:\n%s\n", util.build_url( tool_shed_url, pathspec=pathspec, params=params ), e )
if tool_shed_accessible:
if text:
tool_dependencies_dict = encoding_util.tool_shed_decode( text )
+1 -1
View File
@@ -366,7 +366,7 @@ def remove_tool_dependency_installation_directory( dependency_install_dir ):
except Exception as e:
removed = False
error_message = "Error removing tool dependency installation directory %s: %s" % ( str( dependency_install_dir ), str( e ) )
log.warn( error_message )
log.warning( error_message )
else:
removed = True
error_message = ''
+10 -8
View File
@@ -176,8 +176,9 @@ RELEASE_ISSUE_TEMPLATE = string.Template("""
- [ ] **Deploy and Test Release**
- [ ] Deploy to test (${freeze_date} + 1 day).
- [ ] Update test to ensure it is running a dev at or past branch point (${freeze_date} + 1 day).
- [ ] Deploy to usegalaxy.org (${freeze_date} + 1 week).
- [ ] [Update bioblend testing](https://github.com/galaxyproject/bioblend/commit/b74b1c302a1b8fed86786b40d7ecc3520cbadcd3) to include a ``release_${version}`` target - add ``env`` target ``- TOX_ENV=py27 GALAXY_VERSION=release_${version}`` to ``tox.ini``.
- [ ] **Create Release Notes**
@@ -226,19 +227,20 @@ RELEASE_ISSUE_TEMPLATE = string.Template("""
- [ ] **Announce Release**
- [ ] Verify release included in https://docs.galaxyproject.org/en/master/releases/index.html
- [ ] Review announcement in https://github.com/galaxyproject/galaxy/blob/dev/doc/source/releases/${version}_announce.rst
- [ ] Stage annoucement content (Wiki, Biostars, Bit.ly link) on annouce date to capture date tags. Note: all final content does not need to be completed to do this.
- [ ] Finalize https://github.com/galaxyproject/galaxy/blob/dev/doc/source/releases/${version}_announce.rst
- [ ] Post release notes to https://docs.galaxyproject.org/en/master/releases/index.html
- [ ] Create wiki *highlights* and post to http://galaxyproject.org News (w/ RSS) and NewsBriefs
- [ ] Tweet wiki news *highlights* (or RTD?) via bit.ly link to https://twitter.com/galaxyproject/
- [ ] Post *highlights* type News to Galaxy Biostars https://biostar.usegalaxy.org
- [ ] Email *highlights* to galaxy-dev and galaxy-announce @lists.galaxyproject.org
- [ ] Adjust http://getgalaxy.org text and links to match current master branch
- [ ] Create wiki *highlights* and post to http://galaxyproject.org News (w/ RSS) and NewsBriefs. [An Example](https://wiki.galaxyproject.org/News/2016_04_GalaxyRelease).
- [ ] Tweet docs news *highlights* via bit.ly link to https://twitter.com/galaxyproject/ (As user ``galaxyproject``, password in Galaxy password store under ``twitter.com / galaxyproject`` ). [An Example](https://twitter.com/galaxyproject/status/733029921316986881).
- [ ] Post *highlights* type News to Galaxy Biostars https://biostar.usegalaxy.org. [An Example](https://biostar.usegalaxy.org/p/17712/).
- [ ] Email *highlights* to [galaxy-dev](http://dev.list.galaxyproject.org/) and [galaxy-announce](http://announce.list.galaxyproject.org/) @lists.galaxyproject.org. [An Example](http://dev.list.galaxyproject.org/The-Galaxy-release-16-04-is-out-tp4669419.html)
- [ ] Adjust http://getgalaxy.org text and links to match current master branch (TODO: describe how to do this)
- [ ] **Prepare for next release**
- [ ] Ensure milestone ``${next_version}`` exists.
- [ ] Create release issue for next version ``make release-issue RELEASE_CURR=${next_version}``.
- [ ] Schedule committer meeting to discuss re-alignment of priorities.
- [ ] Close this issue.
""")
+1 -27
View File
@@ -1,8 +1,6 @@
#!/bin/bash
set -e
GXPIP_VERSION='8.0.2+gx2'
SET_VENV=1
for arg in "$@"; do
[ "$arg" = "--skip-venv" ] && SET_VENV=0
@@ -133,31 +131,7 @@ fi
: ${GALAXY_WHEELS_INDEX_URL:="https://wheels.galaxyproject.org/simple"}
if [ $REPLACE_PIP -eq 1 ]; then
pip_version=`pip --version | awk '{print $2}'`
method=`python - << EOF
from pkg_resources import parse_version
from sys import stdout
if parse_version('$pip_version') >= parse_version('6.0'):
stdout.write('req')
elif parse_version('$pip_version') >= parse_version('1.5'):
stdout.write('wheel')
else:
stdout.write('sdist')
EOF`
case $method in
req)
pip install --no-index --find-links ${GALAXY_WHEELS_INDEX_URL}/pip --upgrade "pip==${GXPIP_VERSION}"
;;
wheel)
pip install --upgrade "https://wheels.galaxyproject.org/packages/pip-${GXPIP_VERSION}-py2.py3-none-any.whl"
;;
sdist)
pip install --upgrade "https://wheels.galaxyproject.org/packages/pip-${GXPIP_VERSION}.tar.gz"
;;
esac
# binary-compatibility.cfg may need to be created (e.g. on CentOS)
[ -n "$VIRTUAL_ENV" -a ! -f ${VIRTUAL_ENV}/binary-compatibility.cfg ] && python ./scripts/binary_compatibility.py -o ${VIRTUAL_ENV}/binary-compatibility.cfg
pip install 'pip>=8.1'
fi
if [ $FETCH_WHEELS -eq 1 ]; then
+1 -1
View File
@@ -1 +1 @@
{"version":3,"file":"scratchbook.js","sources":["../../src/layout/scratchbook.js"],"names":["define","Frames","Backbone","View","extend","initialize","options","self","this","frames","visible","setElement","$el","buttonActive","collection","add","id","icon","tooltip","onclick","active","set","toggle","show_note","note_cls","hide","onbeforeunload","length","buttonLoad","show","on","note","addDataset","dataset_id","require","DATA","dataset","Dataset","$","when","fetch","then","frame_config","title","get","is_tabular","_","find","data_type","indexOf","tabular_dataset","TabularDataset","toJSON","content","parent_elt","createTabularDatasetChunkedView","model","embedded","height","url","Galaxy","root","addTrackster","viz_id","visualization","trackster","viz","Visualization","ui","TracksterUI","type","view_config","container","name","dbkey","stand_alone","latest_revision","drawables","config","view","each","d","hda_ldda","create_visualization","viewport","bookmarks","target","window","open","location","$galaxy_main","parent","document","href","attr"],"mappings":"AACAA,QAAS,oBAAsB,SAAUC,GACzC,MAAOC,UAASC,KAAKC,QACjBC,WAAa,SAAUC,GACnB,GAAIC,GAAOC,IACXF,GAAUA,MACVE,KAAKC,OAAS,GAAIR,GAAOE,MAAOO,SAAU,IAC1CF,KAAKG,WAAYH,KAAKC,OAAOG,KAC7BJ,KAAKK,aAAeP,EAAQQ,WAAWC,KACnCC,GAAkB,qBAClBC,KAAkB,QAClBC,QAAkB,6BAClBC,QAAkB,WACdZ,EAAKa,QAAUb,EAAKa,OACpBb,EAAKM,aAAaQ,KACdC,OAAYf,EAAKa,OACjBG,UAAYhB,EAAKa,OACjBI,SAAYjB,EAAKa,QAAU,iBAE9Bb,EAAKa,QAAUb,EAAKE,OAAOgB,QAEhCC,eAAkB,WACd,MAAKnB,GAAKE,OAAOkB,SAAW,EACjB,cAAgBpB,EAAKE,OAAOkB,SAAW,gCADlD,UAKRnB,KAAKoB,WAAatB,EAAQQ,WAAWC,KACjCC,GAAkB,mBAClBC,KAAkB,SAClBC,QAAkB,wBAClBK,WAAkB,EAClBb,SAAkB,EAClBS,QAAkB,WACdZ,EAAKE,OAAOC,QAAUH,EAAKE,OAAOgB,OAASlB,EAAKE,OAAOoB,UAG/DrB,KAAKC,OAAOqB,GAAI,aAAc,WAC1BtB,KAAKE,SAA4B,GAAjBF,KAAKmB,UAAiBnB,KAAKiB,OAC3ClB,EAAKqB,WAAWP,KAAOU,KAAQvB,KAAKmB,SAAUjB,QAAWF,KAAKmB,SAAW,MAC1EG,GAAI,aAAc,WACjBvB,EAAKqB,WAAWP,KAAOC,OAAUd,KAAKE,QAASO,KAAQT,KAAKE,SAAW,UAAY,oBAK3FsB,WAAY,SAAUC,GAClB,GAAI1B,GAAOC,IACX0B,UAAU,oBAAsB,SAAUC,GACtC,GAAIC,GAAU,GAAID,GAAKE,SAAWrB,GAAKiB,GACvCK,GAAEC,KAAMH,EAAQI,SAAUC,KAAM,WAE5B,GAAIC,IACIC,MAAOP,EAAQQ,IAAI,SAKvBC,EAAaC,EAAEC,MAAQ,UAAW,YAAe,SAAUC,GACvD,MAA2D,KAApDZ,EAAQQ,IAAK,aAAcK,QAASD,IAInD,IAAKH,EAAa,CACd,GAAIK,GAAkB,GAAIf,GAAKgB,eAAgBf,EAAQgB,SACvDN,GAAE1C,OAAQsC,GACNW,QAAS,SAAUC,GACfnB,EAAKoB,iCACDC,MAAcN,EACdI,WAAcA,EACdG,UAAc,EACdC,OAAc,gBAM1BZ,GAAE1C,OAAQsC,GACNiB,IAAKC,OAAOC,KAAO,YAAczB,EAAQpB,GAAK,0BAGtDT,GAAKQ,IAAK2B,QAMtBoB,aAAc,SAASC,GACnB,GAAIxD,GAAOC,IACX0B,UAAS,oBAAqB,iBAAkB,SAAS8B,EAAeC,GACpE,GAAIC,GAAM,GAAIF,GAAcG,eAAenD,GAAI+C,GAC/CzB,GAAEC,KAAM2B,EAAI1B,SAAUC,KAAM,WACxB,GAAI2B,GAAK,GAAIH,GAAUI,YAAYT,OAAOC,MAGtCnB,GACIC,MAAOuB,EAAItB,IAAI,QACf0B,KAAM,QACNjB,QAAS,SAASC,GAEd,GAAIiB,IACAC,UAAWlB,EACXmB,KAAMP,EAAItB,IAAI,SACd5B,GAAIkD,EAAIlD,GAER0D,MAAOR,EAAItB,IAAI,SACf+B,aAAa,GAEjBC,EAAkBV,EAAItB,IAAI,mBAC1BiC,EAAYD,EAAgBE,OAAOC,KAAKF,SAGxC/B,GAAEkC,KAAKH,EAAW,SAASI,GACvBA,EAAE7C,SACE8C,SAAUD,EAAEC,SACZlE,GAAIiE,EAAEhD,cAGd8C,KAAOX,EAAGe,qBAAqBZ,EACAK,EAAgBE,OAAOM,SACvBR,EAAgBE,OAAOC,KAAKF,UAC5BD,EAAgBE,OAAOO,WACvB,IAG3C9E,GAAKQ,IAAI2B,QAMrB3B,IAAK,SAAUT,GACX,GAAuB,UAAlBA,EAAQgF,OACTC,OAAOC,KAAMlF,EAAQqD,SAClB,IAAuB,QAAlBrD,EAAQgF,QAAsC,WAAlBhF,EAAQgF,QAAyC,SAAlBhF,EAAQgF,OAC3EC,OAAOE,SAAWnF,EAAQqD,QACvB,IAAMnD,KAAKY,OAiBdZ,KAAKC,OAAOM,IAAKT,OAjBM,CACvB,GAAIoF,GAAepD,EAAGiD,OAAOI,OAAOC,UAAW7C,KAAM,eACrD,IAAuB,eAAlBzC,EAAQgF,QAA6C,UAAlBhF,EAAQgF,OAC5C,GAA6B,IAAxBI,EAAa/D,OAAc,CAC5B,GAAIkE,GAAOvF,EAAQqD,GAEfkC,IADwB,IAAvBA,EAAK5C,QAAS,KACP,IAEA,IACZ4C,GAAQ,kBACRN,OAAOE,SAAWI,MAElBH,GAAaI,KAAM,MAAOxF,EAAQqD,SAGtC4B,QAAOE,SAAWnF,EAAQqD"}
{"version":3,"file":"scratchbook.js","sources":["../../src/layout/scratchbook.js"],"names":["define","Frames","Backbone","View","extend","initialize","options","self","this","frames","visible","setElement","$el","buttonActive","collection","add","id","icon","tooltip","onclick","active","set","toggle","show_note","note_cls","hide","onbeforeunload","length","buttonLoad","show","on","note","history_cache","addDataset","dataset_id","current_dataset","Galaxy","currHistoryPanel","history_id","historyId","name","model","get","dataset_ids","each","push","_findDataset","dataset","offset","history_details","dataset_list","pos","indexOf","_loadDatasetOffset","frame","new_dataset_id","_loadDataset","new_dataset","config","trigger","_","menu","disabled","callback","require","DATA","Dataset","$","when","fetch","then","is_tabular","find","data_type","title","url","content","createTabularDatasetChunkedView","TabularDataset","toJSON","embedded","height","root","addTrackster","viz_id","visualization","trackster","viz","Visualization","ui","TracksterUI","frame_config","type","parent_elt","view_config","container","dbkey","stand_alone","latest_revision","drawables","view","d","hda_ldda","create_visualization","viewport","bookmarks","target","window","open","location","$galaxy_main","parent","document","href","attr"],"mappings":"AACAA,QAAS,oBAAsB,SAAUC,GACzC,MAAOC,UAASC,KAAKC,QACjBC,WAAa,SAAUC,GACnB,GAAIC,GAAOC,IACXF,GAAUA,MACVE,KAAKC,OAAS,GAAIR,GAAOE,MAAOO,SAAU,IAC1CF,KAAKG,WAAYH,KAAKC,OAAOG,KAC7BJ,KAAKK,aAAeP,EAAQQ,WAAWC,KACnCC,GAAkB,qBAClBC,KAAkB,QAClBC,QAAkB,6BAClBC,QAAkB,WACdZ,EAAKa,QAAUb,EAAKa,OACpBb,EAAKM,aAAaQ,KACdC,OAAYf,EAAKa,OACjBG,UAAYhB,EAAKa,OACjBI,SAAYjB,EAAKa,QAAU,iBAE9Bb,EAAKa,QAAUb,EAAKE,OAAOgB,QAEhCC,eAAkB,WACd,MAAKnB,GAAKE,OAAOkB,SAAW,EACjB,cAAgBpB,EAAKE,OAAOkB,SAAW,gCADlD,UAKRnB,KAAKoB,WAAatB,EAAQQ,WAAWC,KACjCC,GAAkB,mBAClBC,KAAkB,SAClBC,QAAkB,wBAClBK,WAAkB,EAClBb,SAAkB,EAClBS,QAAkB,WACdZ,EAAKE,OAAOC,QAAUH,EAAKE,OAAOgB,OAASlB,EAAKE,OAAOoB,UAG/DrB,KAAKC,OAAOqB,GAAI,aAAc,WAC1BtB,KAAKE,SAA4B,GAAjBF,KAAKmB,UAAiBnB,KAAKiB,OAC3ClB,EAAKqB,WAAWP,KAAOU,KAAQvB,KAAKmB,SAAUjB,QAAWF,KAAKmB,SAAW,MAC1EG,GAAI,aAAc,WACjBvB,EAAKqB,WAAWP,KAAOC,OAAUd,KAAKE,QAASO,KAAQT,KAAKE,SAAW,UAAY,mBAEvFF,KAAKwB,kBAITC,WAAY,SAAUC,GAClB,GAAI3B,GAAOC,KACP2B,EAAkB,IACtB,IAAKC,QAAUA,OAAOC,iBAAmB,CACrC,GAAIC,GAAaF,OAAOC,iBAAiBvB,WAAWyB,SACpD/B,MAAKwB,cAAeM,IAAiBE,KAAMJ,OAAOC,iBAAiBI,MAAMC,IAAK,QAAUC,gBACxFP,OAAOC,iBAAiBvB,WAAW8B,KAAM,SAAUH,IAC9CA,EAAMC,IAAK,YAAeD,EAAMC,IAAK,YAAenC,EAAKyB,cAAeM,GAAaK,YAAYE,KAAMJ,EAAMC,IAAK,SAG3H,GAAII,GAAe,SAAUC,EAASC,GAClC,GAAKD,EAAU,CACX,GAAIE,GAAkB1C,EAAKyB,cAAee,EAAQL,IAAK,cACvD,IAAKO,GAAmBA,EAAgBN,YAAc,CAClD,GAAIO,GAAeD,EAAgBN,YAC/BQ,EAAMD,EAAaE,QAASL,EAAQL,IAAK,MAC7C,IAAa,KAARS,GAAcA,EAAMH,GAAU,GAAKG,EAAMH,EAASE,EAAavB,OAChE,MAAOuB,GAAcC,EAAMH,MAKvCK,EAAqB,SAAUN,EAASC,EAAQM,GAChD,GAAIC,GAAiBT,EAAcC,EAASC,EACvCO,GACDhD,EAAKiD,aAAcD,EAAgB,SAAUE,EAAaC,GACtDvB,EAAkBsB,EAClBH,EAAMb,MAAMpB,IAAKqC,KAGrBJ,EAAMb,MAAMkB,QAAS,UAG7BnD,MAAKgD,aAActB,EAAY,SAAUa,EAASW,GAC9CvB,EAAkBY,EAClBxC,EAAKQ,IAAK6C,EAAExD,QAAUyD,OAAU5C,KAAW,4BACXC,QAAW,sBACXC,QAAW,SAAUmC,GAAUD,EAAoBlB,EAAiB,GAAImB,IACxEQ,SAAW,WAAa,OAAQhB,EAAcX,EAAiB,OAC/DlB,KAAW,6BACXC,QAAW,kBACXC,QAAW,SAAUmC,GAAUD,EAAoBlB,EAAiB,EAAGmB,IACvEQ,SAAW,WAAa,OAAQhB,EAAcX,EAAiB,OAAauB,OAIpHF,aAAc,SAAUtB,EAAY6B,GAChC,GAAIxD,GAAOC,IACXwD,UAAU,oBAAsB,SAAUC,GACtC,GAAIlB,GAAU,GAAIkB,GAAKC,SAAWlD,GAAKkB,GACvCiC,GAAEC,KAAMrB,EAAQsB,SAAUC,KAAM,WAC5B,GAAIC,GAAaX,EAAEY,MAAQ,UAAW,YAAe,SAAUC,GAC3D,MAA2D,KAApD1B,EAAQL,IAAK,aAAcU,QAASqB,KAE3CC,EAAQ3B,EAAQL,IAAK,QACrBO,EAAkB1C,EAAKyB,cAAee,EAAQL,IAAK,cAClDO,KACDyB,EAAQzB,EAAgBT,KAAO,KAAOkC,GAE1CX,EAAUhB,EAASwB,GACfG,MAAUA,EACVC,IAAU,KACVC,QAAUX,EAAKY,iCACXpC,MAAc,GAAIwB,GAAKa,eAAgB/B,EAAQgC,UAC/CC,UAAc,EACdC,OAAc,SACfrE,MAEH8D,MAAUA,EACVC,IAAUvC,OAAO8C,KAAO,YAAchD,EAAa,yBACnD0C,QAAU,YAO1BO,aAAc,SAASC,GACnB,GAAI7E,GAAOC,IACXwD,UAAS,oBAAqB,iBAAkB,SAASqB,EAAeC,GACpE,GAAIC,GAAM,GAAIF,GAAcG,eAAexE,GAAIoE,GAC/CjB,GAAEC,KAAMmB,EAAIlB,SAAUC,KAAM,WACxB,GAAImB,GAAK,GAAIH,GAAUI,YAAYtD,OAAO8C,MAGtCS,GACIjB,MAAOa,EAAI7C,IAAI,QACfkD,KAAM,QACNhB,QAAS,SAASiB,GAEd,GAAIC,IACAC,UAAWF,EACXrD,KAAM+C,EAAI7C,IAAI,SACd1B,GAAIuE,EAAIvE,GAERgF,MAAOT,EAAI7C,IAAI,SACfuD,aAAa,GAEjBC,EAAkBX,EAAI7C,IAAI,mBAC1ByD,EAAYD,EAAgBxC,OAAO0C,KAAKD,SAGxCvC,GAAEhB,KAAKuD,EAAW,SAASE,GACvBA,EAAEtD,SACEuD,SAAUD,EAAEC,SACZtF,GAAIqF,EAAEnE,cAGdkE,KAAOX,EAAGc,qBAAqBT,EACAI,EAAgBxC,OAAO8C,SACvBN,EAAgBxC,OAAO0C,KAAKD,UAC5BD,EAAgBxC,OAAO+C,WACvB,IAG3ClG,GAAKQ,IAAI4E,QAMrB5E,IAAK,SAAUT,GACX,GAAuB,UAAlBA,EAAQoG,OACTC,OAAOC,KAAMtG,EAAQqE,SAClB,IAAuB,QAAlBrE,EAAQoG,QAAsC,WAAlBpG,EAAQoG,QAAyC,SAAlBpG,EAAQoG,OAC3EC,OAAOE,SAAWvG,EAAQqE,QACvB,IAAMnE,KAAKY,OAWdZ,KAAKC,OAAOM,IAAKT,OAXM,CACvB,GAAIwG,GAAe3C,EAAGwC,OAAOI,OAAOC,UAAWxC,KAAM,eAC9B,gBAAlBlE,EAAQoG,QAA6C,UAAlBpG,EAAQoG,OACf,IAAxBI,EAAanF,OACdgF,OAAOE,SAAWvG,EAAQqE,KAA+B,IAAvBsC,KAAK7D,QAAS,KAAc,IAAM,KAAQ,kBAE5E0D,EAAaI,KAAM,MAAO5G,EAAQqE,KAGtCgC,OAAOE,SAAWvG,EAAQqE"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More