[Bioperl-l] Re: RemoteBlast
paul.boutros at utoronto.ca
paul.boutros at utoronto.ca
Fri Oct 31 15:59:00 EST 2003
>I'd be willing to volunteer for maintaining RemoteBlast if there are no
>other takers, I've used it quite a bit so I guess should try and put
>something back .
>
>Just from first thoughts I'd plan to
>
>- incorporate Megablast / Blast2seqs /rpsblast functionality
>-separate out the form submission bits of code from the Blast specific
>code in the module, perhaps by inheriting
> from Bio::WebAgent.
>
>Other than making sure that the output is parseable by Bio::SearchIO,
>are there any strong feelings for how new features should be
>implemented?
>
>If anyone has requests/ideas fornew functionality please say so!
>
Hi,
I started doing some modifications myself, and I'd be happy to help you if I
can. I have a version with Megablast enabled, as well as with additional
set/get functions for parameters.
One thing that would be really nice: to have a standardized interface for both
StandAloneBlast and RemoteBlast. Perhaps that could be done with a new class,
BlastInterfaceI? Not sure. I'm attaching my version below. I've meant to
post this here, but I've been procrastinating on adding to the test suite....
Paul
###Begin Code
# $Id: RemoteBlast.pm,v 1.14.2.1 2003/03/25 12:32:17 heikki Exp $
#
# BioPerl module for Bio::Tools::Run::RemoteBlast
#
# Cared for by Jason Stajich, Mat Wiepert
#
# Copyright Jason Stajich
#
# You may distribute this module under the same terms as perl itself
# POD documentation - main docs before the code
=head1 NAME
Bio::Tools::Run::RemoteBlast - Object for remote execution of the NCBI Blast
via HTTP
=head1 SYNOPSIS
#Remote-blast "factory object" creation and blast-parameter initialization
use Bio::Tools::Run::RemoteBlast;
use strict;
my $prog = 'blastp';
my $db = 'swissprot';
my $e_val = '1e-10';
my $matrix = 'BLOSUM62';
my @params = (
'-prog' => $prog,
'-data' => $db,
'-expect' => $e_val,
'-readmethod' => 'SearchIO',
'-matrix' => $matrix
);
my $factory = Bio::Tools::Run::RemoteBlast->new(@params);
# Methods exist to change many parameters. A full listing of
# available parameters is at:
# http://www.ncbi.nlm.nih.gov/BLAST/Doc/urlapi.html
# For example, one interesting feature of QBlast is that allows filtering
# of results by expectation value. For instance:
$factory->expect_low(1e-30);
$factory->expect_high(1e-10);
# retrieves only results where the expected number of hits by chance
# in the database would be between 1 and 10. Note that this filtering
# is done after the BLAST is run, but before results are returned.
# One can also limit the number of alignments returned:
$factory->alignments(20);
# Some CGI parameters can only be changed directly, for instance
$Bio::Tools::Run::RemoteBlast::HEADER{'PERC_IDENT'} = 97;
# Parameters can also be removed in this way:
delete $Bio::Tools::Run::RemoteBlast::HEADER{'PERC_IDENT'};
my $v = 1;
#$v is just to turn on and off the messages
my $str = Bio::SeqIO->new(-file=>'amino.fa' , '-format' => 'fasta' );
while (my $input = $str->next_seq()){
#Blast a sequence against a database:
#Alternatively, you could pass in a file with many
#sequences rather than loop through sequence one at a time
#Remove the loop starting 'while (my $input = $str->next_seq())'
#and swap the two lines below for an example of that.
my $r = $factory->submit_blast($input);
#my $r = $factory->submit_blast('amino.fa');
print STDERR "waiting..." if( $v > 0 );
while ( my @rids = $factory->each_rid ) {
foreach my $rid ( @rids ) {
my $rc = $factory->retrieve_blast($rid);
if( !ref($rc) ) {
if( $rc < 0 ) {
$factory->remove_rid($rid);
}
print STDERR "." if ( $v > 0 );
sleep 5;
} else {
my $result = $rc->next_result();
#save the output
my $filename = $result->query_name()."\.out";
$factory->save_output($filename);
$factory->remove_rid($rid);
print "\nQuery Name: ", $result->query_name(), "\n";
while ( my $hit = $result->next_hit ) {
next unless ( $v > 0);
print "\thit name is ", $hit->name, "\n";
while( my $hsp = $hit->next_hsp ) {
print "\t\tscore is ", $hsp->score, "\n";
}
}
}
}
}
}
=head1 DESCRIPTION
Class for remote execution of the NCBI Blast via HTTP.
For a description of the many CGI parameters see:
http://www.ncbi.nlm.nih.gov/BLAST/Doc/urlapi.html
Various additional options and input formats are available.
=head1 FEEDBACK
=head2 Mailing Lists
User feedback is an integral part of the evolution of this and other
Bioperl modules. Send your comments and suggestions preferably to one
of the Bioperl mailing lists. Your participation is much appreciated.
bioperl-l at bioperl.org - General discussion
http://bio.perl.org/MailList.html - About the mailing lists
=head2 Reporting Bugs
Report bugs to the Bioperl bug tracking system to help us keep track
the bugs and their resolution. Bug reports can be submitted via email
or the web:
bioperl-bugs at bio.perl.org
http://bio.perl.org/bioperl-bugs/
=head1 AUTHOR - Jason Stajich
Email jason at bioperl.org
=head1 APPENDIX
The rest of the documentation details each of the object
methods. Internal methods are usually preceded with a _
=cut
package Bio::Tools::Run::RemoteBlast;
use vars qw($AUTOLOAD @ISA $URLBASE %HEADER %RETRIEVALHEADER $RIDLINE);
use strict;
use Bio::Root::Root;
use Bio::Root::IO;
use Bio::SeqIO;
use IO::String;
use Bio::Tools::BPlite;
use Bio::SearchIO;
use LWP;
use HTTP::Request::Common;
BEGIN {
$URLBASE = 'http://www.ncbi.nlm.nih.gov/blast/Blast.cgi';
%HEADER = (
'CMD' => 'Put',
'PROGRAM' => 'blastp',
'DATABASE' => 'nr',
'FILTER' => 'L',
'EXPECT' => '1e-3',
'QUERY' => '',
'CDD_SEARCH' => 'off',
'COMPOSITION_BASED_STATISTICS' => 'no',
'SERVICE' => 'plain',
);
%RETRIEVALHEADER = (
'CMD' => 'Get',
'RID' => '',
'ALIGNMENT_VIEW' => 'Pairwise',
'DESCRIPTIONS' => 500,
'ALIGNMENTS' => 500,
'FORMAT_TYPE' => 'Text',
'FORMAT_OBJECT' => 'Alignment',
'SERVICE' => 'plain',
);
$RIDLINE = 'RID\s+=\s+(\S+)';
}
@ISA = qw(Bio::Root::Root Bio::Root::IO);
sub new {
my ($caller, @args) = @_;
# chained new
my $self = $caller->SUPER::new(@args);
# so that tempfiles are cleaned up
$self->_initialize_io();
my ($prog, $program, $data, $database, $expect, $alignments, $service,
$format_object,
$hitlist_size, $word_size, $auto_format, $matrix_name, $megablast,
$filter,
$descriptions, $expect_low, $expect_high, $entrez_query, $gapcosts,
$nucl_penalty,
$nucl_reward, $readmethod) =
$self->_rearrange([
qw(PROG
PROGRAM
DATA
DATABASE
EXPECT
ALIGNMENTS
SERVICE
FORMAT_OBJECT
HITLIST_SIZE
WORD_SIZE
AUTO_FORMAT
MATRIX_NAME
MEGABLAST
FILTER
DESCRIPTIONS
EXPECT_LOW
EXPECT_HIGH
ENTREZ_QUERY
GAPCOSTS
NUCL_PENALTY
NUCL_REWARD
READMETHOD)
], @args);
$readmethod = 'SearchIO' unless defined $readmethod;
$self->readmethod($readmethod);
$self->program($prog);
$self->program($program); # allow -program as alias for -prog
$self->database($data);
$self->database($database); # allow -database as alias for -data
$self->expect($expect);
$self->alignments($alignments);
$self->service($service);
$self->format_object($format_object);
$self->hitlist_size($hitlist_size);
$self->word_size($word_size);
$self->auto_format($auto_format);
$self->matrix_name($matrix_name);
$self->megablast($megablast);
$self->filter($filter);
$self->descriptions($descriptions);
$self->expect_low($expect_low);
$self->expect_high($expect_high);
$self->entrez_query($entrez_query);
$self->gapcosts($gapcosts);
$self->nucl_penalty($nucl_penalty);
$self->nucl_reward($nucl_reward);
return $self;
}
=head2 header
Title : header
Usage : my $header = $self->header
Function: Get/Set HTTP header for blast query
Returns : string
Args : none
=cut
sub header {
my ($self) = @_;
my %h = %HEADER;
$h{'PROGRAM'} = $self->program;
$h{'DATABASE'} = $self->database;
$h{'EXPECT'} = $self->expect;
return %h;
}
=head2 readmethod
Title : readmethod
Usage : my $readmethod = $self->readmethod
Function: Get/Set the method to read the blast report
Returns : string
Args : string [ Blast, BPlite ]
=cut
sub readmethod {
my ($self, $val) = @_;
if( defined $val ) {
$self->{'_readmethod'} = $val;
}
return $self->{'_readmethod'};
}
=head2 program
Title : program
Usage : my $prog = $self->program
Function: Get/Set the program to run
Returns : string
Args : string [ blastp, blastn, blastx, tblastn, tblastx ]
=cut
sub program {
my ($self, $val) = @_;
if( defined $val ) {
$val = lc $val;
if( $val !~ /t?blast[pnx]/ ) {
$self->warn("trying to set program to an invalid program name
($val) -- defaulting to blastp");
$val = 'blastp';
}
# $self->{'_program'} = $val;
$HEADER{'PROGRAM'} = $val;
}
return $HEADER{'PROGRAM'};
}
=head2 database
Title : database
Usage : my $db = $self->database
Function: Get/Set the database to search
Returns : string
Args : string [ swissprot, nr, nt, etc... ]
=cut
sub database {
my ($self, $val) = @_;
if( defined $val ) {
# $self->{'_database'} = $val;
$HEADER{'DATABASE'} = $val;
}
return $HEADER{'DATABASE'};
}
=head2 expect
Title : expect
Usage : my $expect = $self->expect
Function: Get/Set the E value cutoff
Returns : string
Args : string [ '1e-4' ]
=cut
sub expect {
my ($self, $val) = @_;
if( defined $val ) {
# $self->{'_expect'} = $val;
$HEADER{'EXPECT'} = $val;
}
return $HEADER{'EXPECT'};
}
=head2 format_object
Title : format_object
Usage : my $format_object = $self->format_object
$self->format_object($value)
Function: Get/Set the object-type to be retrieved
Returns : string
Args : string [Alignment, Neighbors, PSSM, etc.]
=cut
sub format_object {
my ($self, $val) = @_;
if (defined($val)) {
$RETRIEVALHEADER{'FORMAT_OBJECT'} = $val;
}
return $RETRIEVALHEADER{'FORMAT_OBJECT'};
}
=head2 service
Title : service
Usage : my $service = $self->service
$self->service($value)
Function: Get/Set the NCBI Blast service to be used
Returns : string
Args : string [plain, psi, phi, rpsblast, megablast]
=cut
sub service {
my ($self, $val) = @_;
if (defined($val)) {
$HEADER{'SERVICE'} = $val;
$RETRIEVALHEADER{'SERVICE'} = $val;
}
return $HEADER{'SERVICE'};
}
=head2 alignments
Title : alignments
Usage : my $alignments = $self->alignments
$self->alignments($value)
Function: Get/Set the number of alignments to be returned
Returns : integer
Args : integer (default: 500)
=cut
sub alignments {
my ($self, $val) = @_;
if (defined($val) && $val =~ /^(\d+)$/) {
$RETRIEVALHEADER{'ALIGNMENTS'} = $1;
}
return $RETRIEVALHEADER{'ALIGNMENTS'};
}
=head2 hitlist_size
Title : hitlist_size
Usage : my $hitlist_size = $self->hitlist_size
Function: Get/Set the number of hits to be returned
Returns : integer
Args : integer (default: 500)
=cut
sub hitlist_size {
my ($self, $val) = @_;
if (defined($val) && $val =~ /^(\d+)$/) {
$HEADER{'HITLIST_SIZE'} = $1;
}
return $HEADER{'HITLIST_SIZE'};
}
=head2 word_size
Title : word_size
Usage : my $word_size = $self->word_size
$self->word_size($value)
Function: Get/Set the BLAST word-size for HSP generation
Returns : integer
Args : integer (default: protein-3; nucleotide-11; megablast-28)
=cut
sub word_size {
my ($self, $val) = @_;
if (defined($val) && $val =~ /^(\d+)$/) {
$HEADER{'WORD_SIZE'} = $1;
}
return $HEADER{'WORD_SIZE'};
}
=head2 auto_format
Title : auto_format
Usage : my $auto_format = $self->auto_format
$self->auto_format($value)
Function: Get/Set the flag for automatic result formatting
Returns : string
Args : string (Values: Off (default), Semiauto, Fullauto)
=cut
sub auto_format {
my ($self, $val) = @_;
if (defined($val)) {
$HEADER{'AUTO_FORMAT'} = $val;
}
return $HEADER{'AUTO_FORMAT'};
}
=head2 matrix_name
Title : matrix_name
Usage : my $matrix_name = $self->matrix_name
$self->matrix_name($value)
Function: Get/Set the name of the substitution matrix used (protein only)
Returns : string
Args : string (Default: BLOSUM62)
=cut
sub matrix_name {
my ($self, $val) = @_;
if (defined($val)) {
$HEADER{'MATRIX_NAME'} = $val;
}
return $HEADER{'MATRIX_NAME'};
}
=head2 megablast
Title : megablast
Usage : my $megablast = $self->megablast
$self->megablast($value)
Function: Flag to indicate if the MegaBLAST algorithm should be used
Returns : string
Args : string (Values: 'yes', 'no' (default))
=cut
sub megablast {
my ($self, $val) = @_;
if (defined($val)) {
$HEADER{'MEGABLAST'} = $val;
}
return $HEADER{'MEGABLAST'};
}
=head2 filter
Title : filter
Usage : my $filter = $self->filter
$self->filter($value)
Function: Sequence filter identifier
Returns : string
Args : string
Values : 'L' for low-complexity (default)
'R' for human repeats
'm' for Mask for Lookup
'no' to turn off
=cut
sub filter {
my ($self, $val) = @_;
if (defined($val) && ($val eq 'L' || $val eq 'R' || $val eq 'm' ||
$val eq 'no')) {
if ($val eq 'no') {
$HEADER{'FILTER'} = '';
}
else {
$HEADER{'FILTER'} = $val;
}
}
return $HEADER{'FILTER'};
}
=head2 descriptions
Title : descriptions
Usage : my $descriptions = $self->descriptions
$self->descriptions($value)
Function: Specify number of descriptions to be returned
Returns : integer
Args : integer (Default: 500)
=cut
sub descriptions {
my ($self, $val) = @_;
if (defined($val) && $val =~ /^(\d+)$/) {
$RETRIEVALHEADER{'DESCRIPTIONS'} = $1;
}
return $RETRIEVALHEADER{'DESCRIPTIONS'};
}
=head2 expect_low
Title : expect_low
Usage : my $expect_low = $self->expect_low
$self->expect_low($value)
Function: Minimum expectation value returned
Returns : double-type value
Args : double-type value (Default: 0)
=cut
sub expect_low {
my ($self, $val) = @_;
if (defined($val)) {
$RETRIEVALHEADER{'EXPECT_LOW'} = $val;
}
return $RETRIEVALHEADER{'EXPECT_LOW'};
}
=head2 expect_high
Title : expect_high
Usage : my $expect_high = $self->expect_high
$self->expect_high($value)
Function: Maximum expectation value returned
Returns : double-type value
Args : double-type value (Default: 0)
=cut
sub expect_high {
my ($self, $val) = @_;
if (defined($val)) {
$RETRIEVALHEADER{'EXPECT_HIGH'} = $val;
}
return $RETRIEVALHEADER{'EXPECT_HIGH'};
}
=head2 entrez_query
Title : entrez_query
Usage : my $entrez_query = $self->entrez_query
$self->entrez_query($value)
Function: An Entrez query to use in limiting searches
Returns : string
Args : string (Default: empty)
=cut
sub entrez_query {
my ($self, $val) = @_;
if (defined($val)) {
$HEADER{'ENTREZ_QUERY'} = $val;
}
return $HEADER{'ENTREZ_QUERY'};
}
=head2 gapcosts
Title : gapcosts
Usage : my $gapcosts = $self->gapcosts
$self->gapcosts($value)
Function: Scoring cost for opening and extending gaps in alignments
Returns : Two space-separated floats (open, extend)
Args : Two space-separated floats (open, extend)
Default : nucleotide 5 + 2x
protein 11 + x
megablast non-affine
=cut
sub gapcosts {
my ($self, $val) = @_;
if (defined($val)) {
my $flag = 1;
my @costs = split(/ /, $val);
if (scalar(@costs) != 2) { # require only two values
$flag = 0;
}
foreach my $cost (@costs) {
$cost =~ s/^\s+//;
$cost =~ s/\s+$//;
# require +ve integers or floats
if (($cost !~ /^\d+$/) && ($cost !~ /^\d+\.\d+$/)) {
$flag = 0;
}
}
if ($flag == 1) {
$HEADER{'GAPCOSTS'} = join(' ', @costs);
}
}
return $HEADER{'GAPCOSTS'};
}
=head2 nucl_penalty
Title : nucl_penalty
Usage : my $nucl_penalty = $self->nucl_penalty
$self->nucl_penalty($value)
Function: Negative score assigned to nucleotide mismatches (BLASTN)
Returns : -ve integer
Args : -ve integer
=cut
sub nucl_penalty {
my ($self, $val) = @_;
if (defined($val) && $val =~ /^-\d+$/) {
$HEADER{'NUCL_PENALTY'} = $val;
}
return $HEADER{'NUCL_PENALTY'};
}
=head2 nucl_reward
Title : nucl_reward
Usage : my $nucl_reward = $self->nucl_reward
$self->nucl_reward($value)
Function: Positive score assigned to a nucleotide match (BLASTN)
Returns : +ve integer
Args : +ve integer
=cut
sub nucl_reward {
my ($self, $val) = @_;
if (defined($val) && $val =~ /^(\d+)$/) {
if ($val > 0) { $HEADER{'NUCL_REWARD'} = $val; }
}
return $HEADER{'NUCL_REWARD'};
}
=head2 ua
Title : ua
Usage : my $ua = $self->ua or
$self->ua($ua)
Function: Get/Set a LWP::UserAgent for use
Returns : reference to LWP::UserAgent Object
Args : none
Comments: Will create a UserAgent if none has been requested before.
=cut
sub ua {
my ($self, $value) = @_;
if( ! defined $self->{'_ua'} ) {
$self->{'_ua'} = new LWP::UserAgent;
}
return $self->{'_ua'};
}
=head2 proxy
Title : proxy
Usage : $httpproxy = $db->proxy('http') or
$db->proxy(['http','ftp'], 'http://myproxy' )
Function: Get/Set a proxy for use of proxy
Returns : a string indicating the proxy
Args : $protocol : an array ref of the protocol(s) to set/get
$proxyurl : url of the proxy to use for the specified protocol
=cut
sub proxy {
my ($self,$protocol,$proxy) = @_;
return undef if ( !defined $self->ua || !defined $protocol
|| !defined $proxy );
return $self->ua->proxy($protocol,$proxy);
}
sub add_rid {
my ($self, @vals) = @_;
foreach ( @vals ) {
$self->{'_rids'}->{$_} = 1;
}
return scalar keys %{$self->{'_rids'}};
}
sub remove_rid {
my ($self, @vals) = @_;
foreach ( @vals ) {
delete $self->{'_rids'}->{$_};
}
return scalar keys %{$self->{'_rids'}};
}
sub each_rid {
my ($self) = @_;
return keys %{$self->{'_rids'}};
}
=head2 submit_blast
Title : submit_blast
Usage : $self->submit_blast([$seq1,$seq2]);
Function: Submit blast jobs to ncbi blast queue on sequence(s)
Returns : Blast report object as defined by $self->readmethod
Args : input can be:
* sequence object
* array ref of sequence objects
* filename of file containing fasta formatted sequences
=cut
sub submit_blast {
my ($self, $input) = @_;
my @seqs = $self->_load_input($input);
return 0 unless ( @seqs );
my $tcount = 0;
my %header = $self->header;
foreach my $seq ( @seqs ) {
#If query has a fasta header, the output has the query line.
$header{'QUERY'} = ">".(defined $seq->display_id() ? $seq->display_id
() : "").
" ".(defined $seq->desc() ? $seq->desc() : "")."\n".$seq->seq
();
my $request = POST $URLBASE, [%header];
$self->warn($request->as_string) if ( $self->verbose > 0);
my $response = $self->ua->request( $request);
if( $response->is_success ) {
if( $self->verbose > 0 ) {
my ($tempfh) = $self->tempfile();
# Hmm, what exactly are we trying to do here?
print $tempfh $response->content;
close($tempfh);
undef $tempfh;
}
my @subdata = split(/\n/, $response->content );
my $count = 0;
foreach ( @subdata ) {
if( /$RIDLINE/ ) {
$count++;
print STDERR $_ if( $self->verbose > 0);
$self->add_rid($1);
last;
}
}
if( $count == 0 ) {
$self->warn("req was ". $request->as_string() . "\n");
$self->warn(join('', @subdata));
}
$tcount += $count;
} else {
# should try and be a little more verbose here
$self->warn("req was ". $request->as_string() . "\n" .
$response->error_as_HTML);
$tcount = -1;
}
}
return $tcount;
}
=head2 retrieve_blast
Title : retrieve_blast
Usage : my $blastreport = $blastfactory->retrieve_blast($rid);
Function: Attempts to retrieve a blast report from remote blast queue
Returns : -1 on error,
0 on 'job not finished',
Bio::Tools::BPlite or Bio::Tools::Blast object
(depending on how object was initialized) on success
Args : Remote Blast ID (RID)
=cut
sub retrieve_blast {
my($self, $rid) = @_;
my (undef,$tempfile) = $self->tempfile();
my %hdr = %RETRIEVALHEADER;
$hdr{'RID'} = $rid;
my $req = POST $URLBASE, [%hdr];
if( $self->verbose > 0 ) {
$self->warn("retrieve request is " . $req->as_string());
}
my $response = $self->ua->request($req, $tempfile);
if( $self->verbose > 0 ) {
open(TMP, $tempfile) or $self->throw("cannot open $tempfile");
while(<TMP>) { print $_; }
close TMP;
}
if( $response->is_success ) {
my $size = -s $tempfile;
if( $size > 1000 ) {
my $blastobj;
if( $self->readmethod =~ /BPlite/ ) {
$blastobj = new Bio::Tools::BPlite(-file => $tempfile);
} else {
$blastobj = new Bio::SearchIO(-file => $tempfile,
-format => 'blast');
}
#save tempfile
$self->file($tempfile);
return $blastobj;
} elsif( $size < 500 ) { # search had a problem
open(ERR, "<$tempfile") or $self->throw("cannot open file
$tempfile");
$self->warn(join("", <ERR>));
close ERR;
return -1;
} else { # still working
return 0;
}
} else {
$self->warn($response->error_as_HTML);
return -1;
}
}
=head2 save_output
Title : saveoutput
Usage : my $saveoutput = $self->save_output($filename)
Function: Method to save the blast report
Returns : 1 (throws error otherwise)
Args : string [rid, filename]
=cut
sub save_output {
my ($self, $filename) = @_;
if( ! defined $filename ) {
$self->throw("Can't save blast output. You must specify a filename to
save to.");
}
#should be set when retrieving blast
my $blastfile = $self->file;
#open temp file and output file, have to filter out some HTML
open(TMP, $blastfile) or $self->throw("cannot open $blastfile");
open(SAVEOUT, ">$filename") or $self->throw("cannot open $filename");
my $seentop=0;
while(<TMP>) {
next if (/<pre>/);
if( /^(?:[T]?BLAST[NPX])\s*.+$/i ||
/^RPS-BLAST\s*.+$/i ) {
$seentop=1;
}
next if !$seentop;
if( $seentop ) {
print SAVEOUT;
}
}
close SAVEOUT;
close TMP;
return 1;
}
sub _load_input {
my ($self, $input) = @_;
if( ! defined $input ) {
$self->throw("Calling remote blast with no input");
}
my @seqs;
if( ! ref $input ) {
if( -e $input ) {
my $seqio = new Bio::SeqIO(-format => 'fasta', -file => $input);
while( my $seq = $seqio->next_seq ) {
push @seqs, $seq;
}
} else {
$self->throw("Input $input was not a valid filename");
}
} elsif( ref($input) =~ /ARRAY/i ) {
foreach ( @$input ) {
if( ref($_) && $_->isa('Bio::PrimarySeqI') ) {
push @seqs, $_;
} else {
$self->warn("Trying to add a " . ref($_) .
" but expected a Bio::PrimarySeqI");
}
}
if( ! @seqs) {
$self->throw("Did not pass in valid input -- no sequence objects
found");
}
} elsif( $input->isa('Bio::PrimarySeqI') ) {
push @seqs, $input;
}
return @seqs;
}
1;
__END__
###End Code
More information about the Bioperl-l
mailing list