diff --git a/modules/Bio/EnsEMBL/Utils/ConversionSupport.pm b/modules/Bio/EnsEMBL/Utils/ConversionSupport.pm index 98d729c9b2543c7731ed44026fc92124119ce6c3..820d1d0e4b2ad073042df516e17215a3fa6f648a 100644 --- a/modules/Bio/EnsEMBL/Utils/ConversionSupport.pm +++ b/modules/Bio/EnsEMBL/Utils/ConversionSupport.pm @@ -53,6 +53,7 @@ use FindBin qw($Bin $Script); use POSIX qw(strftime); use Cwd qw(abs_path); use DBI; +use Data::Dumper; =head2 new @@ -115,6 +116,7 @@ sub parse_common_options { 'help|h|?', ); + # reads config file my $conffile = $h{'conffile'} || $self->serverroot . "/sanger-plugins/vega/conf/ini-files/Conversion.ini"; $conffile = abs_path($conffile); @@ -129,8 +131,8 @@ sub parse_common_options { s/^[#;].*//; s/\s+[;].*$//; - # read options into internal parameter datastructure - next unless (/(\w\S*)\s*=\s*(.*)/); + # read options into internal parameter datastructure, removing whitespace + next unless (/(\w\S*)\s*=\s*(\S*)\s*/); my $name = $1; my $val = $2; if ($val =~ /\$SERVERROOT/) { @@ -143,6 +145,7 @@ sub parse_common_options { } elsif ($conffile) { warning("Unable to open configuration file $conffile for reading: $!"); } + # override configured parameter with commandline options map { $self->param($_, $h{$_}) } keys %h; @@ -232,6 +235,27 @@ sub get_common_params { ); } +=head2 get_lutre_params + + Example : my @allowed_params = $self->get_lutre_params, 'extra_param'; + Description : Returns a list of commonly used parameters in for working with a loutre db + Return type : Array - list of common parameters + Exceptions : none + Caller : general + +=cut + +sub get_loutre_params { + return qw( + loutrehost + loutreport + loutreuser + loutrepass + loutredbname + ); +} + + =head2 confirm_params Example : $support->confirm_params; @@ -634,6 +658,7 @@ sub get_database { otter => 'Bio::Otter::DBSQL::DBAdaptor', vega => 'Bio::Otter::DBSQL::DBAdaptor', compara => 'Bio::EnsEMBL::DBSQL::DBAdaptor', + loutre => 'Bio::Vega::DBSQL::DBAdaptor', ); throw("Unknown database: $database") unless $adaptors{$database}; @@ -675,7 +700,7 @@ sub get_database { sub get_dbconnection { my $self = shift; my $prefix = shift; - + $self->check_required_params( "${prefix}host", "${prefix}port", @@ -691,7 +716,6 @@ sub get_dbconnection { } my $dbh; - eval{ $dbh = DBI->connect($dsn, $self->param("${prefix}user"), $self->param("${prefix}pass"), {'RaiseError' => 1, 'PrintError' => 0}); @@ -704,7 +728,6 @@ sub get_dbconnection { } $self->{'_dbh'} = $dbh; - return $self->{'_dbh'}; } @@ -813,6 +836,8 @@ sub dynamic_use { Arg[1] : (optional) Bio::EnsEMBL::DBSQL::DBAdaptor $dba Arg[2] : (optional) String $version - coord_system version + Arg[3] : (optional) String $type - type of region eg chromsome (defaults to 'toplevel') + Arg[4] : (optional) Boolean - return non reference slies as well (required for haplotypes eq 6-COX) Example : my $chr_length = $support->get_chrlength($dba); Description : Get all chromosomes and their length from the database. Return chr_name/length for the chromosomes the user requested (or all @@ -824,15 +849,17 @@ sub dynamic_use { =cut sub get_chrlength { - my ($self, $dba, $version) = @_; + my ($self, $dba, $version,$type,$include_non_reference) = @_; $dba ||= $self->dba; + $type ||= 'toplevel'; throw("get_chrlength should be passed a Bio::EnsEMBL::DBSQL::DBAdaptor\n") unless ($dba->isa('Bio::EnsEMBL::DBSQL::DBAdaptor')); my $sa = $dba->get_SliceAdaptor; + my @chromosomes = map { $_->seq_region_name } - @{ $sa->fetch_all('chromosome', $version) }; - my %chr = map { $_ => $sa->fetch_by_region('chromosome', $_, undef, undef, undef, $version)->length } @chromosomes; + @{ $sa->fetch_all($type, $version,$include_non_reference) }; + my %chr = map { $_ => $sa->fetch_by_region($type, $_, undef, undef, undef, $version)->length } @chromosomes; my @wanted = $self->param('chromosomes'); if (@wanted) { @@ -1149,7 +1176,7 @@ sub log { sub log_warning { my ($self, $txt, $indent) = @_; - $txt = "WARNING: " . $txt; + $txt = "\nWARNING: " . $txt; $self->log($txt, $indent); $self->{'_warnings'}++; return(1); @@ -1428,4 +1455,257 @@ sub commify { return scalar reverse $num; } +=head2 fetch_non_hidden_slices + + Arg[1] : B::E::SliceAdaptor + Arg[2] : B::E::AttributeAdaptor + Arg[3] : string $coord_system_name (optional) - 'chromosome' by default + Arg[4] : string $coord_system_version (optional) - 'otter' by default + Example : $chroms = $support->fetch_non_hidden_slice($sa); + Description : retrieve all slices from a lutra database that don't have a hidden attribute + Return type : arrayref + Caller : general + Status : stable + +=cut + +sub fetch_non_hidden_slices { + my $self = shift; + my $aa = shift or throw("You must supply an attribute adaptor"); + my $sa = shift or throw("You must supply a slice adaptor"); + my $cs = shift || 'chromosome'; + my $cv = shift || 'Otter'; + my $visible_chroms; + foreach my $chrom ( @{$sa->fetch_all($cs,$cv)} ) { + my $attribs = $aa->fetch_all_by_Slice($chrom); + push @$visible_chroms, $chrom if @{$self->get_attrib_values($attribs,'hidden',0)}; + } + return $visible_chroms; +} + + +=head2 get_attrib_values + + Arg[1] : Arrayref of B::E::Attributes + Arg[2] : 'code' to search for + Arg[3] : 'value' to search for (optional) + Example : my $c = $self->get_attrib_values($attribs,'name')); + Description : (i) In the abscence of an attribute value argument examines an arrayref + of B::E::Attributes for a particular attribute type, returning the values + for each attribute of that type (can therefore be used to test for the + number of attributes of that type). + (ii) In the presence of the optional value argument, it can be used to test + for the presence of an attribute with a particular value + Return type : arrayref of values for that attribute + Caller : general + Status : stable + +=cut + +sub get_attrib_values { + my $self = shift; + my $attribs = shift; + my $code = shift; + my $value = shift; + if (my @atts = grep {$_->code eq $code } @$attribs) { + my $r; + if ($value) { + if (my @values = grep {$_->value eq $value} @atts) { + foreach (@values) { + push @$r, $_->value; + } + return $r; + } + else { + return []; + } + } + else { + foreach (@atts) { + push @$r, $_->value; + } + return $r; + } + } + else { + return []; + } +} + +=head2 fix_attrib_value + + Arg[1] : Arrayref of exisiting B::E::Attributes + Arg[2] : dbID of object + Arg[3] : name of object (just for reporting) + Arg[4] : attrib_type.code + Arg[5] : attrib_type.value + Arg[5] : interactive ? (0 by default) + Arg[6] : table + Example : $support->fix_attrib_value($attribs,$chr_id,$chr_name,'vega_export_mod','N',1); + Description : adds a new attribute to an object, or updates an existing attribute with a new value + Can be run in interactive or non-interactive mode (default) + Return type : none + Caller : general + Status : only ever tested with seq_region_attributes to date + +=cut + +sub fix_attrib_value { + my $self = shift; + my $attribs = shift; + my $id = shift; + my $name = shift; + my $code = shift; + my $value = shift; + my $interact = shift || 0; + my $table = shift || 'seq_region_attrib'; + + #set interactive parameter + my $int_before; + if (! $interact) { + $int_before = $self->param('interactive'); + $self->param('interactive',0); + } + +# warn "interactive_before = $int_before"; + #get any existing value(s) for this attribute + my $existings = $self->get_attrib_values($attribs,$code); + + #add a new attribute if there is none... + if (! @$existings ) { + if ($self->user_proceed("Do you want to set $name attrib (code = $code) to value $value ?")) { + my $r = $self->store_new_attribute($id,$code,$value); + + #reset interactive parameter + $self->param('interactive',$int_before) if (! $interact); + return $r; + } + } + #...warn and exit if you're trying to update more than one value for the same attribute... + elsif (scalar @$existings > 1) { + $self->log_warning("You shouldn't be trying to update multiple attributes with the same code at once ($name:$code,$value), looks like you have duplicate entries in the (seq_region_)attrib table\n"); + exit; + } + + else { + my $existing = $existings->[0]; + #...or update an attribute with new values... + if ($existing ne $value) { + if ($self->user_proceed("Do you want to reset $name attrib (code = $code) from $existing to $value ?")) { + my $r = $self->update_attribute($id,$code,$value); + $self->param('interactive',$int_before) if (! $interact); + push @$r, $existing; + return $r; + } + } + #...or make no change + else { + $self->param('interactive',$int_before) if (! $interact); + return []; + } + } +} + +=head2 _get_attrib_id + + Arg[1] : attrib_type.code + Arg[2] : database handle + Example : $self->_get_attrib_id('name',$dbh) + Description : get attrib_type.attrib_type_id from a attrib_type.code + Return type : attrib_type.attrib_type_id + Caller : internal + Status : stable + +=cut + +sub _get_attrib_id { + my $self = shift; + my $attrib_code = shift; + my $dbh = shift; + my ($attrib_id) = $dbh->selectrow_array( + qq(select attrib_type_id + from attrib_type + where code = ?), + {}, + ($attrib_code) + ); + if (! $attrib_id) { + $self->log_warning("There is no attrib_type_id for code $attrib_code, please patch the attrib_table\n"); + exit; + } + else { + return $attrib_id; + } +} + +=head2 store_new_attribute + + Arg[1] : seq_region.seq_region_id + Arg[2] : attrib_type.code + Arg[3] : attrib_type.value + ARG[4] : table to update (seq_region_attribute by default) + Example : $support->store_new_attribute(23,name,5); + Description : uses MySQL to store an entry (code and value) in an attribute table + (seq_region_attrib by default) + Return type : array_ref + Caller : general + Status : stable + +=cut + +sub store_new_attribute { + my $self = shift; + my $sr_id = shift; + my $attrib_code = shift; + my $attrib_value = shift; + my $table = shift || 'seq_region_attrib'; + + #get database handle + my $dbh = $self->get_dbconnection('loutre'); + #get attrib_type_id for this particular attribute + my $attrib_id = $self->_get_attrib_id($attrib_code,$dbh); + #store + my $r = $dbh->do( + qq(insert into $table + values (?,?,?)), + {}, + ($sr_id,$attrib_id,$attrib_value) + ); + return ['Stored',$r]; +} + +=head2 update_attribute + + Arg[1] : seq_region.seq_region_id + Arg[2] : attrib_type.code + Arg[3] : attrib_type.value + ARG[4] : table to update (seq_region_attribute by default) + Example : $support->update_attribute(23,name,5); + Description : uses MySQL to update an attribute table (seq_region_attrib by default) + Return type : array_ref + Caller : general + Status : stable + +=cut + +sub update_attribute { + my $self = shift; + my $sr_id = shift; + my $attrib_code = shift; + my $attrib_value = shift; + my $table = shift || 'seq_region_attrib'; + my $dbh = $self->get_dbconnection('loutre'); + my $attrib_id = $self->_get_attrib_id($attrib_code,$dbh); + #update + my $r = $dbh->do( + qq(update $table + set value = ? + where seq_region_id = $sr_id + and attrib_type_id = $attrib_id), + {}, + ($attrib_value) + ); + return ['Updated',$r]; +} + 1;