How can I suppress warnings from a Perl function? - perl

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>
}

Related

Perl: print compilation warnings for do()

I am using do() to execute a perl script. I wanted to make sure it was doing the right error checking, but I noticed that warnings don't get printed when I use do(). I left the following warning on purpose in my script. I see it when I run it on the command line
Useless use of numeric eq (==) in void context at utils/queryEvent/query_event.pl line 47.
When I use do(), this message is suppressed. I saw in perlvar that $# doesn't contain warnings, so I tried to add this before my call to do(), but I still don't see anything.
local $SIG{__WARN__} = sub {
print "Warning #_\n";
};
do(...);
Is there a way I can still print the compilation/parsing warnings?
I'm using Perl v.5.22.1 on Windows 10.
Added edit:
Both the script calling do() and the script being run through do() have use strict; and use warnings;. It is only the parsing warning that isn't showing up. If I call warn in the do script, then I see that (I'm assuming stderr).
Edit:
Adding example script.
A minimal reproducible version is the following
use strict;
use warnings;
sub test
{
return 1;
}
main:
{
(test() == 1);
}
Calling script
use strict;
use warnings;
main:
{
do('test.pl');
}
You are mistaken. do doesn't affect warnings in the least.
There is no warning because there is nothing that should cause a warning. (test() == 1) isn't being evaluated in void context. Instead, its result is returned by do.
But while warnings AREN'T being silenced, exceptions ARE being silenced. Fixing this will fix the other.
Add a trailing 1 to the file loaded by do, and change the do as follows:
do('test.pl')
or die( "Can't execute `./test.pl`: ".( $# // $! ) );
The trailing 1 is used to signal the "caller" whether an error occurred or not. This has the side effect of cause (test() == 1) to be evaluated in void context as expected.
The -w or -W command-line switches will enable warnings throughout your program, including code included through a do statement.

How to Test::More and smarter with Transactions?

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.

Wrapping Perl "die" and "warn" in a utility subroutine

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

How do I conditionally make warnings fatal?

I want to have fatal errors that can be demoted to warnings (or conversely, warnings that can be promoted to fatal errors) depending on the user's preference. At present, I'm using die and overriding it like this:
my $force;
BEGIN {
no warnings 'once';
Getopt::Long::Configure('pass_through');
GetOptions('force', \$force);
*CORE::GLOBAL::die = sub { warn #_ } if $force;
Getopt::Long::Configure('no_pass_through');
}
use My::Module;
...
die "maybe";
...
exit(1) if $force;
exit(0); # success!
I don't like this approach, mostly because there are a few places where I still want to die (e.g. missing command-line arguments). I'd rather change (most) instances of die to warn and do a conditional use warnings FATAL => 'all'1. The problem is that use warnings is lexically scoped, so this is ineffective:
if (!$force) {
use warnings FATAL => 'all';
}
Attempting to use a postfix conditional is a syntax error:
use warnings FATAL => 'all' unless $force;
and use can't be used in an expression:
$force or use warnings FATAL => 'all'; # syntax error
I can think of various distasteful work-arounds (Defining my own warn/die, duplicating my main script code in an if/else, etc.) but am seeking an elegant solution that conditionally applies use warnings in the current lexical scope. (Applying it in the parent scope would work as well but would likely require dark magic.)
1: Actually, I want to add use warnings::register to my modules and use warnings FATAL => 'My::Module' to my script, but the distinction is unimportant for the purposes of this question.
You could try:
use if !$force, warnings => qw( FATAL all );
Yes, there's a module called if that is distributed with Perl to make it really easy to do conditional imports.
Note that this is evaluated at compile time, so $force needs to be defined at compile time. (Probably within a BEGIN { ... } block.) Based on the code samples in your question, you seem to have figured that part out already though.
Alternatively, more manual:
BEGIN {
require warnings;
warnings->import(qw/ FATAL all /) unless $force;
}
A completely different approach would be to use a signal handler $SIG{__WARN__} or $SIG{__DIE__} to decide to die or not at run-time.

How do you best attribute errors in a Perl method to the caller

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