Currently I am creating transactional tests like that:
use Test::More;
use Try::Tiny;
my $dbh = ...;
subtest 'do something envolving a transaction' => sub {
$dbh->begin_work();
try {
my $obj = create_in_db({...}, $dbh);
my $result = MyTestObject->new()->do_something($obj);
ok $result "We've got great results";
} catch {
croak $_;
} finally {
$dbh->rollback(); #kills $obj
};
};
done_testing();
1;
This works, but has the disadvantage, that the line of the error is always the catch block and the end of the subtest, never where the error actually happens. And it is a lot of boring boilerplate code that quickly adds up.
How to do this in a smarter way?
The fact that the error (croak) is reported at the end of try-catch-finally blocks† instead of where the offending code is called seems due to Try::Tiny's mixup with namespaces; see a discussion in this post and comments. The exact source of this misbehavior isn't clear to me in the complex try sub. A simple demo
use warnings;
use strict;
use feature 'say';
use Carp qw(croak);
use Try::Tiny;
sub this_croaks { croak "ouch from a sub in ", __PACKAGE__ } # line 8
try {
this_croaks(); # line 11
}
catch { print "In try: $_" }
finally { say "clean up" }; # line 14
This prints
In try: ouch from a sub in main at try_tiny_mixup.pl line 14.
clean up
But the croak-ing sub is called at line 11 so that should be reported, not line 14.‡
Changing croak to die makes it print line 8 (what of course isn't a solution) while using eval instead of Try::Tiny results in the correct line 11 printed (what is a valid solution). See the linked post. I am not aware of a fix with Try::Tiny but there are drop-in replacements, see below.
I don't see that this in any way depends on what tests are performed (here involving a database transaction as we are told). And I cannot check more specifically without a runable example.
The one thing that works fully is to revert to eval, which since 5.14 isn't anymore borne with subtleties that were the stated reason for Try::Tiny. Like
eval {
this_croaks();
};
if ($#) {
print "In eval: $#";
}
say "clean up";
This is still archaic but it works just as intended (and Try::Tiny comes with twists of its own).
Hopefully the coming native try/catch, introduced as experimental in 5.34.0, won't have problems like this.§ For now it doesn't
use warnings;
use v5.34.0;
use Carp qw(croak);
use feature 'try';
no warnings qw(experimental::try);
sub this_croaks { croak "ouch from a sub in ", __PACKAGE__ } # line 9
try {
this_croaks(); # line 12
}
catch ($e) {
print "In try: $e";
}
say "clean up"; # there is no "finally" keyword
This correctly pegs it as called at line 12 (and coming from line 9). Note that there is no finally keyword yet. The module Syntax::Keyword::Tiny (see footnote) does have it so it may be possible to use it as a drop-in replacement for Try::Tiny.
I suspect that clearing this up will clear up the test's behavior as well. (But I didn't get to test that.)
† Syntax aids ("sugar") for anonymous subs (which in many ways aren't so naive)
‡ Submitted a bug report
§ This is getting ported from Syntax::Keyword::Try by the author themselves so you may want to try that -- but then better use Feature::Compat::Try, they say. See docs of both, and see its tracker.
Once we are at experimental stuff see perlexperiment.
Related
I had seen some exceptions that pointed to (end of) the catch block itself (see the example below).
As my opinion, this is an unexpected behavior, since it alters the location of original exception and make difficult to debug (it should say die at line 13.)
It shows the (correct) line 13, if I use die/confess or using eval instead try-catch.
Not knowing how my code will be called within the stack, I started to avoid using croak now. What do you think? Did I get right, or there is a way to improve this?
Best regards, Steve
use Carp;
use Try::Tiny;
try {
foo();
}
catch {
# do something before die
die $_;
}; # this is line 10
sub foo {
croak 'die'; # this is line 13
}
Output:
die at line 10.
This is the intended behavior from Carp
[...] use carp() or croak() which report the error as being from where your module was called. [...] There is no guarantee that that is where the error was, but it is a good educated guess.
So the error is reported at where the module's sub is called, which is what the user wants
use warnings;
use strict;
use feature 'say';
use Try::Tiny;
package Throw {
use warnings;
use Carp qw(croak confess);
#sub bam { die "die in module" }; # l.11
sub bam { croak "croak in module" };
1;
};
try {
Throw::bam(); # l.17
}
catch {
say "caught one: $_";
die "die in catch: $_";
};
say "done";
Prints
caught one: croak in module at exceptions.pl line 17.
die in catch: croak in module at exceptions.pl line 17.
If the sub throws using die then this is reported at line 11, what is the normal behavior of die, and what you seem to expect.
If any of this is unclear or suboptimal then better use confess and nicely get a full stacktrace. Also, if you wish more exception-based-like code behavior, can put together an exception/error class and throw its object,† designed and populated as desired.
If you want to confess an object note that at this time Carp has limits with that
The Carp routines don't handle exception objects currently. If called with a first argument that is a reference, they simply call die() or warn(), as appropriate.
One way then would be to confess a stringification of the object,‡ getting at least both a full stack backtrace and whatever is in the object.
I get the same behavior with eval, by replacing try-catch and $_ above
eval {
Throw::bam();
};
if ($#) {
say "caught one: $#";
die "die in catch: $#";
};
Prints exactly the same as above
While the above is clear and behaves as expected, a weird thing is indeed seen in the question's example: the error is reported from the whole try-catch statement, ie. at its closing brace, where line 10 is. (The try sub is prototyped and the whole try-catch is a syntax aid equivalent to a call to try that takes an anonymous sub, and then perhaps more. See ikegami's comment, and docs. Also see this post for more about its syntax.)
This is strange since the call to the croaking sub is foo() inside the try statement and this line should be reported, what can be confirmed by running the script with -MCarp::Always. But in the code in this answer the line of the call to Throw::bam is indeed reported -- why this difference?
The clear purpose of croak is to be used in the libraries, so that the user can see at which point in their (user's) code they called the library in a way that triggered an error. (While die would point to the place where error is detected, so in the library, most likely useless to the user. But read die and Carp docs for related complexities.)
What isn't obvious is that when croak is emitted in the same namespace (main::foo()) from try-catch in its own namespace (Try::Tiny) things get confused, and the end of its statement is reported. This can be checked by adding a foo() to my code above and calling it (instead of a sub from a module), and we get the question's behavior reproduced.
This doesn't happen if main::foo() with croak inside is called from a (complex) statement right in main::, so it seems to be due to the try-catch mix up of namespaces. (On the other hand, try-catch sugar adds an anonymous sub to the callstack, and this sure can mix things up as well.)
In practical terms, I'd say: always use croak out of modules (otherwise use die), or, better yet if you want to mimic exception-based code, use confess and/or your exception class hierarchy.
† Even just like die ExceptionClass->new(...);
Bear in mind that in the way of exceptions Perl only has the lonesome die, and eval. For more structure you'll need to implement it all, or use frameworks like Exception::Class or Throwable
‡ By writing and using a method that generates a plain string with useful information from the object, for Carp::confess $obj->stringify.
Or by overloading the "" (quote) operator for the class since it gets used when confess-ing an object (string context), for Carp::confess $obj; this is good to have anyway.
A basic example for both:
use overload ( q("") => \&stringify );
sub stringify {
my $self = shift;
join ", ", map { "$_ => " . ( $self->{$_} // 'undef' ) } keys %$self
}
where instead of a reference to a named sub on can directly write an anonymous sub.
As a way of solving the OP's problem, but with a different module, if you use Nice::Try instead, you will get the result you expect:
use Carp;
use Nice::Try;
try {
foo();
}
catch {
# do something before die
die $_;
} # this is line 10
sub foo {
croak 'die'; # this is line 13
}
You get:
die at ./try-catch-and-croak.pl line 13.
main::foo() called at ./try-catch-and-croak.pl line 4
main::__ANON__ called at ./try-catch-and-croak.pl line 7
eval {...} called at ./try-catch-and-croak.pl line 7 ...propagated at ./try-catch-and-croak.pl line 9.
For full disclosure, I am the author behind Nice::Try
I want to write a small subroutine that can decorate all error messages in a consistent way instead of having to copy it all around my program.
However I want the line numbers to be from where it was called, not from where the die/warn occurred.
In C I would just use a preprocessor macro, but Perl does not have those. What is the best way to implement this?
Use Carp for warnings/errors. You can use __WARN__ and __DIE__ hooks to affect what warn prints to the STDERR stream and how die is thrown. Note that they are quite different.
use warnings;
use strict;
use feature 'say';
use Carp;
$SIG{__WARN__} = \&wrap_warn;
sub wrap_warn {
print "WARNING: #_";
}
sub level_2 {
say "Print from level_2";
carp "carp from level_2(#_)";
}
sub level_1 {
level_2(#_);
}
level_1("from main");
prints to STDOUT
Print from level_2
WARNING: carp from level_2(from main) at wrap_warn.pl line 19.
main::level_2('from main') called at wrap_warn.pl line 15
main::level_1('from main') called at wrap_warn.pl line 22
If you want this to still go to STDERR then use print STDERR "WARNING: #_";
Make sure to carefully read about %SIG in perlvar and warn, at least.
While it seems that you want this to be global, I'd like to mention that one generally wants to local-ize changes like this one. There's an example in this post, and more out there.
Adding the following will add stack traces to exceptions and warnings:
use Carp::Always;
For the occasional use, use the following to avoid modifying your program:
perl -MCarp::Always script args
or
PERL5OPT=-MCarp::Always script args
In PHP you might use # in front of function call to suppress warnings returned.
Is there something similar in Perl?
This feature of PHP is crazy and should be avoided whenever possible.
Perl has two kinds of exceptions: Fatal errors and warnings. Warnings may either be emitted by Perl itself, or by user code.
Inside a certain static/lexical scope, Perl's builtin warnings can be switched off like:
use warnings;
foo();
sub foo {
no warnings 'uninitialized'; # recommended: only switch of specific categories
warn "hello\n";
1 + undef; # Otherwise: Use of uninitialized value in addition (+)
}
Output: hello on STDERR.
(A list of all warnings categories can be found here )
But this can't be used to remove warnings from code you are calling (dynamic scope). This also doesn't silence user-defined warnings.
In this case, you can write a handler for the __WARN__ pseudo-signal:
use warnings;
{
local $SIG{__WARN__} = sub { };
foo();
print "bye\n";
}
sub foo {
warn "hello\n";
1 + undef;
}
Output: bye on STDOUT.
We can abstract that into a function muffle:
sub muffle {
my $func = shift;
local $SIG{__WARN__} = sub { };
return $func->(#_);
}
muffle(\&foo, 1, 2, 3); # foo(1, 2, 3)
However, this is an incredibly dumb thing to do:
Warnings point to potential problems and bugs. Fix those instead of ignoring them.
Don't activate built-in warnings in the first place for categories you aren't interested in. E.g. many people are perfectly happy that an undef value stringifies to the empty string, and don't want any warning for that.
The strategies outlined here do not handle fatal exceptions, use Try::Tiny instead.
You could also just run perl -X and disable all warnings.
I think there are perfectly valid reasons for doing this FWIW.
Easier way is to use no warnings; See perldoc link for more information. Wrap the statement giving warning in curly braces to get rid of the warning message.
E.g.
{
no warnings;
<statement giving warning>
}
Given a method that may fail with warnings and/or errors, I want the error method to show up at the caller. Fir instance this script:
foo(0); # line 1
sub foo {
1 / shift; # line 4
}
Produces the error Illegal division by zero at foo.pl line 4, but I want Illegal division by zero at foo.pl line 1. There should be several ways if I put the method in a module or if I wrap the method body in eval, but I have not found an easy way like this:
sub foo {
attributeErrorsToCaller; # do some magic
1 / shift;
}
Is there such a way?
EDIT: mirod's answer comes close not what I was looking for:
Foo::foo(0); # line 1
package Foo;
use diagnostics -traceonly;
BEGIN { disable diagnostics; }
sub foo {
enable diagnostics;
1 / shift; # line 9
}
Without enable diagnostics the error message is Illegal division by zero at foo.pl line 9.. With enable diagnostics it is still too verbose, but this may also be useful:
Uncaught exception from user code:
Illegal division by zero at foo.pl line 10.
at foo.pl line 10
Foo::foo(0) called at foo.pl line 2
I bet I could hack diagnostics to get exactely the feature I want, but using diagnostics as raw module is probably more recommended.
Carp is very, very close to "do_some_magic" you are asking for. For instance:
#!/usr/bin/perl -w
use strict;
# I fork to be as close to natural die() as possible.
fork() or Foo::foo();
fork() or Foo::bar();
fork() or Foo::baz();
sleep 1;
package Foo;
use Carp;
sub foo { die "Some error (foo)"; };
sub bar { croak "Some error (bar)"; };
sub baz { bar(); };
As you can see, croak() acts almost like die(), but reports error to the caller (even indirectly -- see baz).
However, it won't handle 1/0 for you -- either use eval (or even Try::Tiny), or check input values* and say "division by zero" yourself.
Carp is standard, which means understandable by further maintainers of your code, and also can print neat stack traces via confess or cluck or even print Carp::longmess (see the doc).
*which is good anyway
Would use diagnostics; be enough for you? It will dump the call stack, so the caller is quite easy to find out.
For example in you example:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
foo(0);
sub foo
{
return 1/$_[0];
}
gives this:
`Illegal division by zero at test_die line 12 (#1)
(F) You tried to divide a number by 0. Either something was wrong in
your logic, or you need to put a conditional in to guard against
meaningless input.
Uncaught exception from user code:
Illegal division by zero at test_die line 12.
at test_die line 12
main::foo(0) called at test_die line 8
Not like you describe. You can implement Debug::Trace to pull off a full back trace.
You may also find the perl caller which is quite useful for this type of debugging. But for a live application you will likely need to do more detailed tracing.
http://perldoc.perl.org/functions/caller.html
Yes, the problem is with a library I'm using, and no, I cannot modify it. I need a workaround.
Basically, I'm dealing with a badly written Perl library, that exits with 'die' when a certain error condition is encountered reading a file. I call this routine from a program which is looping through thousands of files, a handful of which are bad. Bad files happen; I just want my routine to log an error and move on.
IF I COULD modify the library, I would simply change the
die "error";
to a
print "error";return;
, but I cannot. Is there any way I can couch the routine so that the bad files won't crash the entire process?
FOLLOWUP QUESTION: Using an "eval" to couch the crash-prone call works nicely, but how do I set up handling for catch-able errors within that framework? To describe:
I have a subroutine that calls the library-which-crashes-sometimes many times. Rather than couch each call within this subroutine with an eval{}, I just allow it to die, and use an eval{} on the level that calls my subroutine:
my $status=eval{function($param);};
unless($status){print $#; next;}; # print error and go to next file if function() fails
However, there are error conditions that I can and do catch in function(). What is the most proper/elegant way to design the error-catching in the subroutine and the calling routine so that I get the correct behavior for both caught and uncaught errors?
You could wrap it in an eval. See:
perldoc -f eval
For instance, you could write:
# warn if routine calls die
eval { routine_might_die }; warn $# if $#;
This will turn the fatal error into a warning, which is more or less what you suggested. If die is called, $# contains the string passed to it.
Does it trap $SIG{__DIE__}? If it does, then it's more local than you are. But there are a couple strategies:
You can evoke its package and override die:
package Library::Dumb::Dyer;
use subs 'die';
sub die {
my ( $package, $file, $line ) = caller();
unless ( $decider->decide( $file, $package, $line ) eq 'DUMB' ) {
say "It's a good death.";
die #_;
}
}
If not, can trap it. (look for $SIG on the page, markdown is not handling the full link.)
my $old_die_handler = $SIG{__DIE__};
sub _death_handler {
my ( $package, $file, $line ) = caller();
unless ( $decider->decide( $file, $package, $line ) eq 'DUMB DIE' ) {
say "It's a good death.";
goto &$old_die_handler;
}
}
$SIG{__DIE__} = \&_death_handler;
You might have to scan the library, find a sub that it always calls, and use that to load your $SIG handler by overriding that.
my $dumb_package_do_something_dumb = \&Dumb::do_something_dumb;
*Dumb::do_something_dumb = sub {
$SIG{__DIE__} = ...
goto &$dumb_package_do_something_dumb;
};
Or override a builtin that it always calls...
package Dumb;
use subs 'chdir';
sub chdir {
$SIG{__DIE__} = ...
CORE::chdir #_;
};
If all else fails, you can whip the horse's eyes with this:
package CORE::GLOBAL;
use subs 'die';
sub die {
...
CORE::die #_;
}
This will override die globally, the only way you can get back die is to address it as CORE::die.
Some combination of this will work.
Although changing a die to not die has a specific solution as shown in the other answers, in general you can always override subroutines in other packages. You don't change the original source at all.
First, load the original package so you get all of the original definitions. Once the original is in place, you can redefine the troublesome subroutine:
BEGIN {
use Original::Lib;
no warnings 'redefine';
sub Original::Lib::some_sub { ... }
}
You can even cut and paste the original definition and tweak what you need. It's not a great solution, but if you can't change the original source (or want to try something before you change the original), it can work.
Besides that, you can copy the original source file into a separate directory for your application. Since you control that directory, you can edit the files in it. You modify that copy and load it by adding that directory to Perl's module search path:
use lib qw(/that/new/directory);
use Original::Lib; # should find the one in /that/new/directory
Your copy sticks around even if someone updates the original module (although you might have to merge changes).
I talk about this quite a bit in Mastering Perl, where I show some other techniques to do that sort of thing. The trick is to not break things even more. How you not break things depends on what you are doing.