diff variant_effect_predictor/Bio/EnsEMBL/Utils/Exception.pm @ 0:21066c0abaf5 draft

Uploaded
author willmclaren
date Fri, 03 Aug 2012 10:04:48 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/variant_effect_predictor/Bio/EnsEMBL/Utils/Exception.pm	Fri Aug 03 10:04:48 2012 -0400
@@ -0,0 +1,536 @@
+=head1 LICENSE
+
+  Copyright (c) 1999-2012 The European Bioinformatics Institute and
+  Genome Research Limited.  All rights reserved.
+
+  This software is distributed under a modified Apache license.
+  For license details, please see
+
+    http://www.ensembl.org/info/about/code_licence.html
+
+=head1 CONTACT
+
+  Please email comments or questions to the public Ensembl
+  developers list at <dev@ensembl.org>.
+
+  Questions may also be sent to the Ensembl help desk at
+  <helpdesk@ensembl.org>.
+
+=cut
+
+=head1 NAME
+
+Bio::EnsEMBL::Utils::Exception - Utility functions for error handling
+
+=head1 SYNOPSIS
+
+  use Bio::EnsEMBL::Utils::Exception
+    qw(throw warning deprecate verbose try catch);
+
+  or to get all methods just
+
+  use Bio::EnsEMBL::Utils::Exception;
+
+  eval { throw("this is an exception with a stack trace") };
+  if ($@) {
+    print "Caught exception:\n$@";
+  }
+
+  # Or you can us the try/catch confortable syntax instead to deal with
+  # throw or die.  Don't forget the ";" after the catch block.  With
+  # this syntax, the original $@ is in $_ in the catch subroutine.
+
+  try {
+    throw("this is an exception with a stack trace");
+  }
+  catch { print "Caught exception:\n$_" };
+
+  # silence warnings
+  verbose('OFF');
+
+  warning('this is a silent warning');
+
+  #show deprecated and warning messages but not info
+  verbose('DEPRECATE');
+
+  warning('this is a warning');
+
+  # show all messages
+  verbose('ALL');
+
+  info('this is an informational message');
+
+  sub my_sub { deprecate('use other_sub() instead') }
+
+  verbose('EXCEPTION');
+  info( 'This is a high priority info message.', 1000 );
+
+=head1 DESCRIPTION
+
+This is derived from the Bio::Root module in BioPerl.  Some formatting
+has been changed and the deprecate function has been added.  Most
+notably the object methods are now static class methods that can be
+called without inheriting from Bio::Root or Bio::EnsEMBL::Root.  This is
+especially useful for throwing exceptions with stack traces outside of a
+blessed context.
+
+The originaly implementations of these methods were by Steve Chervitz
+and refactored by Ewan Birney.
+
+It is recommended that these functions be used instead of inheriting
+unnecessarily from the Bio::EnsEMBL::Root or Bio::Root object.  The
+functions exported by this package provide a set of useful error
+handling methods.
+
+=head1 METHODS
+
+=cut
+
+package Bio::EnsEMBL::Utils::Exception;
+
+use strict;
+use warnings;
+
+use Bio::EnsEMBL::ApiVersion;
+
+use Exporter;
+
+use vars qw(@ISA @EXPORT);
+
+@ISA = qw(Exporter);
+@EXPORT = qw(throw warning stack_trace_dump 
+             stack_trace verbose deprecate info try catch);
+
+my $VERBOSITY         = 3000;
+my $DEFAULT_INFO      = 4000;
+my $DEFAULT_DEPRECATE = 3000;
+my $DEFAULT_WARNING   = 2000;
+my $DEFAULT_EXCEPTION = 1000;
+
+
+=head2 throw
+
+  Arg [1]    : string $msg
+  Arg [2]    : (optional) int $level
+               override the default level of exception throwing
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(throw);
+               throw('We have a problem');
+  Description: Throws an exception which if not caught by an eval will
+               provide a stack trace to STDERR and die.  If the verbosity level
+               is lower than the level of the throw, then no error message is
+               displayed but the program will still die (unless the exception
+               is caught).
+  Returntype : none
+  Exceptions : thrown every time
+  Caller     : generally on error
+
+=cut
+
+sub throw {
+  my $string = shift;
+
+  # For backwards compatibility with Bio::EnsEMBL::Root::throw:  Allow
+  # to be called as an object method as well as class method.  Root
+  # function now deprecated so call will have the string instead.
+
+  $string = shift if ( ref($string) );    # Skip object if one provided.
+  $string = shift if ( $string eq "Bio::EnsEMBL::Utils::Exception" );
+
+  my $level = shift;
+  $level = $DEFAULT_EXCEPTION if ( !defined($level) );
+
+  if ( $VERBOSITY < $level ) {
+    die("\n");    # still die, but silently
+  }
+
+  my $std = stack_trace_dump(3);
+
+  my $out = sprintf(
+             "\n" .
+             "-------------------- EXCEPTION --------------------\n" .
+             "MSG: %s\n" .
+             "%s" .
+             "Date (localtime)    = %s\n" .
+             "Ensembl API version = %s\n" .
+             "---------------------------------------------------\n",
+             $string, $std, scalar( localtime() ), software_version() );
+
+  die($out);
+} ## end sub throw
+
+
+
+=head2 warning
+
+  Arg [1]    : string warning(message);
+  Arg [2]    : (optional) int level
+               Override the default level of this warning changning the level
+               of verbosity at which it is displayed.
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(warning)
+               warning('This is a warning');
+  Description: If the verbosity level is higher or equal to the level of this 
+               warning then a warning message is printed to STDERR.  If the 
+               verbosity lower then nothing is done.  Under the default
+               levels of warning and verbosity warnings will be displayed.
+  Returntype : none
+  Exceptions : warning every time
+  Caller     : general
+
+=cut
+
+sub warning {
+  my $string = shift;
+
+  # See throw() for this:
+  $string = shift if ( ref($string) );    # Skip object if one provided.
+  $string = shift if ( $string eq "Bio::EnsEMBL::Utils::Exception" );
+
+  my $level = shift;
+  $level = $DEFAULT_WARNING if ( !defined($level) );
+
+  return if ( $VERBOSITY < $level );
+
+  my @caller = caller;
+  my $line = $caller[2] || '';
+
+  # Use only two sub-dirs for brevity when reporting the file name.
+  my $file;
+  my @path = split( /\//, $caller[1] );
+  $file = pop(@path);
+  my $i = 0;
+  while ( @path && $i < 2 ) {
+    $i++;
+    $file = pop(@path) . "/$file";
+  }
+
+  @caller = caller(1);
+  my $caller_line;
+  my $caller_file;
+  $i = 0;
+  if (@caller) {
+    @path        = split( /\//, $caller[1] );
+    $caller_line = $caller[2];
+    $caller_file = pop(@path);
+    while ( @path && $i < 2 ) {
+      $i++;
+      $caller_file = pop(@path) . "/$caller_file";
+    }
+  }
+
+  my $out =
+    sprintf( "\n" .
+             "-------------------- WARNING ----------------------\n" .
+             "MSG: %s\n" .
+             "FILE: %s LINE: %d\n",
+             $string, $file, $line );
+
+  if ( defined($caller_file) ) {
+    $out .= sprintf( "CALLED BY: %s  LINE: %d\n", $caller_file,
+                     $caller_line );
+  }
+  $out .= sprintf(
+           "Date (localtime)    = %s\n" .
+           "Ensembl API version = %s\n" .
+           "---------------------------------------------------\n",
+           scalar( localtime() ), software_version() );
+
+  warn($out);
+
+} ## end sub warning
+
+
+
+=head2 info
+
+  Arg [1]    : string $string
+               The message to be displayed
+  Arg [2]    : (optional) int $level
+               Override the default level of this message so it is displayed at
+               a different level of verbosity than it normally would be.
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(verbose info)
+  Description: This prints an info message to STDERR if verbosity is higher 
+               than the level of the message.  By default info messages are not
+               displayed.
+  Returntype : none
+  Exceptions : none
+  Caller     : general
+
+=cut
+
+sub info {
+  my $string = shift;
+  $string = shift if($string eq "Bio::EnsEMBL::Utils::Exception");
+  my $level  = shift;
+
+  $level = $DEFAULT_INFO if(!defined($level));
+
+  return if($VERBOSITY < $level);
+
+  print STDERR "INFO: $string\n";
+}
+
+
+
+=head2 verbose
+
+  Arg [1]    : (optional) int 
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(verbose warning);
+               #turn warnings and everything more important on (e.g. exception)
+               verbose('WARNING'); 
+               warning("Warning displayed");
+               info("This won't be displayed");
+               deprecate("This won't be diplayed"); 
+
+               #turn exception messages on
+               verbose('EXCEPTION'); 
+               warning("This won't do anything");
+               throw("Die with a message");
+
+               #turn everying off
+               verbose('OFF'); #same as verbose(0);               
+               warning("This won't do anything");
+               throw("Die silently without a message");
+
+               #turn on all messages
+               verbose('ALL');
+               info("All messages are now displayed");
+
+               if(verbose() > 3000) {
+                 print "Verbosity is pretty high";
+               }
+
+  Description: Gets/Sets verbosity level which defines which messages are
+               to be displayed.  An integer value may be passed or one of the
+               following strings:
+               'OFF'       (= 0)
+               'EXCEPTION' (= 1000)
+               'WARNING'   (= 2000)
+               'DEPRECATE' (= 3000)
+               'INFO'      (= 4000)
+               'ALL'       (= 1000000)
+
+  Returntype : int 
+  Exceptions : none
+  Caller     : general
+
+=cut
+
+
+sub verbose {
+  if(@_) {
+    my $verbosity = shift;
+    $verbosity = shift if($verbosity eq "Bio::EnsEMBL::Utils::Exception");
+    if($verbosity =~ /\d+/) { #check if verbosity is an integer
+      $VERBOSITY = $verbosity;
+    } else {
+      $verbosity = uc($verbosity);
+      if($verbosity eq 'OFF' || $verbosity eq 'NOTHING' || 
+         $verbosity eq 'NONE') {
+        $VERBOSITY = 0;
+      } elsif($verbosity eq 'EXCEPTION' || $verbosity eq 'THROW') {
+        $VERBOSITY = $DEFAULT_EXCEPTION;
+      } elsif($verbosity eq 'WARNING' || $verbosity eq 'WARN') {
+        $VERBOSITY = $DEFAULT_WARNING;
+      } elsif($verbosity eq 'DEPRECATE' || $verbosity eq 'DEPRECATED') {
+        $VERBOSITY = $DEFAULT_DEPRECATE;
+      } elsif($verbosity eq 'INFO') {
+        $VERBOSITY = $DEFAULT_INFO;
+      } elsif($verbosity eq 'ON' || $verbosity eq 'ALL') {
+        $VERBOSITY = 1e6;
+      } else {
+        $VERBOSITY = $DEFAULT_WARNING;
+        warning("Unknown level of verbosity: $verbosity");
+      }
+    }
+  }
+
+  return $VERBOSITY;
+}
+
+
+
+=head2 stack_trace_dump
+
+  Arg [1]    : (optional) int $levels
+               The number of levels to ignore from the top of the stack when
+               creating the dump. This is useful when this is called internally
+               from a warning or throw function when the immediate caller and 
+               stack_trace_dump function calls are themselves uninteresting.
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(stack_trace_dump);
+               print STDERR stack_trace_dump();
+  Description: Returns a stack trace formatted as a string
+  Returntype : string
+  Exceptions : none
+  Caller     : general, throw, warning
+
+=cut
+
+sub stack_trace_dump{
+  my @stack = stack_trace();
+
+  my $levels = 2; #default is 2 levels so stack_trace_dump call is not present
+  $levels = shift if(@_);
+  $levels = shift if($levels eq "Bio::EnsEMBL::Utils::Exception");
+  $levels = 1 if($levels < 1);
+  
+  while($levels) {
+    $levels--;
+    shift @stack;
+  }
+
+  my $out;
+  my ($module,$function,$file,$position);
+
+
+  foreach my $stack ( @stack) {
+    ($module,$file,$position,$function) = @{$stack};
+    $out .= "STACK $function $file:$position\n";
+  }
+
+  return $out;
+}
+
+
+
+=head2 stack_trace
+
+  Arg [1]    : none
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(stack_trace)
+  Description: Gives an array to a reference of arrays with stack trace info
+               each coming from the caller(stack_number) call
+  Returntype : array of listrefs of strings
+  Exceptions : none
+  Caller     : general, stack_trace_dump()
+
+=cut
+
+sub stack_trace {
+  my $i = 0;
+  my @out;
+  my $prev;
+  while ( my @call = caller($i++)) {
+
+    # major annoyance that caller puts caller context as
+    # function name. Hence some monkeying around...
+    $prev->[3] = $call[3];
+    push(@out,$prev);
+    $prev = \@call;
+  }
+  $prev->[3] = 'toplevel';
+  push(@out,$prev);
+  return @out;
+}
+
+
+=head2 deprecate
+
+  Arg [1]    : string $mesg
+               A message describing why a method is deprecated
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(deprecate)
+               sub old_sub {
+                 deprecate('Please use new_sub() instead');
+               }
+  Description: Prints a warning to STDERR that the method which called 
+               deprecate() is deprecated.  Also prints the line number and 
+               file from which the deprecated method was called.  Deprecated
+               warnings only appear once for each location the method was 
+               called from.  No message is displayed if the level of verbosity
+               is lower than the level of the warning.
+  Returntype : none
+  Exceptions : warning every time
+  Caller     : deprecated methods
+
+=cut
+
+my %DEPRECATED;
+
+sub deprecate {
+  my $mesg = shift;
+  $mesg = shift if($mesg eq "Bio::EnsEMBL::Utils::Exception"); #skip object if one provided
+
+  my $level = shift;
+
+  $level = $DEFAULT_DEPRECATE if(!defined($level));
+
+  return if($VERBOSITY < $level);
+                                 
+  my @caller = caller(1);
+  my $subname = $caller[3] ;
+  my $line = $caller[2];
+
+  #use only 2 subdirs for brevity when reporting the filename
+  my $file;
+  my @path = $caller[1];
+  $file = pop(@path);
+  my $i = 0;
+  while(@path && $i < 2) {
+    $i++;
+    $file .= pop(@path);
+  }
+
+  #keep track of who called this method so that the warning is only displayed
+  #once per deprecated call
+  return if $DEPRECATED{"$line:$file:$subname"};
+
+  if ( $VERBOSITY > -1 ) {
+    print STDERR
+      "\n------------------ DEPRECATED ---------------------\n"
+      . "Deprecated method call in file $file line $line.\n"
+      . "Method $subname is deprecated.\n"
+      . "$mesg\n"
+      . "Ensembl API version = "
+      . software_version() . "\n"
+      . "---------------------------------------------------\n";
+  }
+
+  $DEPRECATED{"$line:$file:$subname"} = 1;
+}
+
+=head2 try/catch
+
+  Arg [1]    : anonymous subroutine
+               the block to be tried
+  Arg [2]    : return value of the catch function
+  Example    : use Bio::EnsEMBL::Utils::Exception qw(throw try catch)
+               The syntax is:
+               try { block1 } catch { block2 };
+               { block1 } is the 1st argument
+               catch { block2 } is the 2nd argument
+               e.g.
+               try {
+                 throw("this is an exception with a stack trace");
+               } catch {
+                 print "Caught exception:\n$_";
+               };
+               In block2, $_ is assigned the value of the first
+               throw or die statement executed in block 1.
+
+  Description: Replaces the classical syntax
+               eval { block1 };
+               if ($@) { block2 }
+               by a more confortable one.
+               In the try/catch syntax, the original $@ is in $_ in the catch subroutine.
+               This try/catch implementation is a copy and paste from
+               "Programming Perl" 3rd Edition, July 2000, by L.Wall, T. Christiansen
+               & J. Orwant. p227, and is only possible because of subroutine prototypes.
+  Returntype : depend on what is implemented the try or catch block
+  Exceptions : none
+  Caller     : general
+
+=cut
+
+sub try (&$) {
+  my ($try, $catch) = @_;
+  eval { &$try };
+  if ($@) {
+    chop $@;
+    local $_ = $@;
+    &$catch;
+  }
+}
+
+sub catch (&) {
+  shift;
+}
+
+1;