File Coverage

blib/lib/Parse/StackTrace/Type/Python.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Parse::StackTrace::Type::Python;
2 2     2   125144 use Moose;
  0            
  0            
3              
4             extends 'Parse::StackTrace';
5              
6             our $VERSION = '0.08';
7              
8             use constant HAS_TRACE => qr/^\s*File\s".+"(?:,|\s+in)/ms;
9             use constant EXCEPTION_REGEX => qr/
10             ^
11             (?:Exception \s Type:\s+)? # Django Format
12             \S*(?:Error|Exception) # Actual Exception
13             (?::\s+)|(?:\s+at\b) # Colon (normal python) or "at" (Django)
14             /x;
15              
16             sub thread_number {
17             my ($self, $number) = @_;
18             return $self->threads->[0] if $number == 1;
19             return undef;
20             }
21              
22             sub _handle_block {
23             my $class = shift;
24             my %params = @_;
25             my ($frame_lines, $current_thread, $lines, $end, $debug) =
26             @params{qw(frame_lines thread lines end_line_number debug)};
27             # If we run into the description of the exception, then we're done parsing
28             # the trace, provided that we've already parsed some frames.
29             my $first_line = $frame_lines->[0];
30             if (scalar @{ $current_thread->frames } and $first_line =~ EXCEPTION_REGEX) {
31             $current_thread->{description} = trim($first_line);
32             print STDERR "Thread Exception: $first_line\n" if $debug;
33             pop @$frame_lines;
34             # Don't parse anymore.
35             @$lines = ();
36             $current_thread->ending_line($end);
37             return $current_thread;
38             }
39            
40             return $class->SUPER::_handle_block(@_);
41             }
42              
43             sub _next_line_ends_frame {
44             my $class = shift;
45             my ($line) = @_;
46             return ($class->SUPER::_next_line_ends_frame(@_)
47             or $line =~ EXCEPTION_REGEX);
48             }
49              
50             sub trim {
51             my $str = shift;
52             $str =~ s/^s*//;
53             $str =~ s/\s*$//;
54             return $str;
55             }
56              
57             __PACKAGE__->meta->make_immutable;
58              
59             1;
60              
61             __END__
62              
63             =head1 NAME
64              
65             Parse::StackTrace::Type::Python - A stack trace produced by python
66              
67             =head1 DESCRIPTION
68              
69             This is an implementation of L<Parse::StackTrace> for Python tracebacks.
70              
71             The parser will only parse the I<first> Python stack trace it finds in
72             a block of text, and then stop parsing.
73              
74             =head1 SEE ALSO
75              
76             =over
77              
78             =item L<Parse::StackTrace::Type::Python::Thread>
79              
80             =item L<Parse::StackTrace::Type::Python::Frame>
81              
82             =back