Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Make Spreadsheet::ParseXLSX be quiet about errors

by leszekdubiel (Scribe)
on Aug 18, 2022 at 15:25 UTC ( [id://11146229]=perlquestion: print w/replies, xml ) Need Help??

leszekdubiel has asked for the wisdom of the Perl Monks concerning the following question:

This program:

#!/usr/bin/perl use Spreadsheet::ParseXLSX; `echo "" >/tmp/invalid.xlsx`; eval { Spreadsheet::ParseXLSX->new->parse("/tmp/invalid.xlsx") };

prints:

format error: file is too short at /usr/share/perl5/Archive/Zip/Archive.pm line 1031. Archive::Zip::Archive::_findEndOfCentralDirectory(Archive::Zip::Ar +chive=HASH(0x56216520bf48), IO::File=GLOB(0x562165214f30)) called at +/usr/share/perl5/Archive/Zip/Archive.pm line 761 Archive::Zip::Archive::readFromFileHandle(Archive::Zip::Archive=HA +SH(0x56216520bf48), IO::File=GLOB(0x562165214f30), "/tmp/invalid.xlsx +") called at /usr/share/perl5/Archive/Zip/Archive.pm line 729 Archive::Zip::Archive::read(Archive::Zip::Archive=HASH(0x56216520b +f48), "/tmp/invalid.xlsx") called at /usr/share/perl5/Spreadsheet/Par +seXLSX.pm line 63 Spreadsheet::ParseXLSX::parse(Spreadsheet::ParseXLSX=HASH(0x562165 +1e94d8), "/tmp/invalid.xlsx") called at ./quiete_xlsx line 8 eval {...} called at ./quiete_xlsx line 7

How can I grab all erorrs to some variable without polluting stderr?

Replies are listed 'Best First'.
Re: Make Spreadsheet::ParseXLSX be quiet about errors ($SIG{__WARN__} )
by LanX (Saint) on Aug 18, 2022 at 15:42 UTC
    > How can I grab all erorrs to some variable without polluting stderr?

    eval {BLOCK} is only catching fatal errors, either thrown with die or from inside perl.

    But these seem to come from warn

    One way is to locally use a %SIG -handler.

    DEMO:

    > perl -de0 ... DB<173> eval { local $SIG{__WARN__} = sub { die $_[0] }; warn "bla" +} or print "<<<$@>>>" <<<bla at (eval 197)[c:/nonBKU/strawberry-perl-5.32.1.1-64bit-portable +/perl/lib/perl5db.pl:738] line 2. >>> DB<174>

    There is also a pragma for this redirection - use warnings FATAL =>"all"; °

    But with a handler you can also choose to save the warnings to another variable separate from fatals.

    FWIW: Another approach would be to locally redirect STDERR to a var...

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

    °) updated see https://perldoc.perl.org/warnings#Fatal-Warnings for more

      https://stackoverflow.com/a/71683833
      #!/usr/bin/perl use warnings; use strict; print STDERR "STDERR is on.\n"; my ($stderr_fh, $err_msg_ref) = suppress_std_err(); print "STDERR is now off and error messages are being suppressed and s +aved.\n"; print STDERR "I'm an error message.\n"; restore_std_err($stderr_fh); print STDERR "STDERR is back on\n"; print "Errors reported while STDERR was off: $$err_msg_ref\n"; #Saves STDERR in filehandle then turns it off. #Any error messages that occur while STDERR is off are stored for safe +keeping. sub suppress_std_err { my $suppressed_std_error_messages; open (my $saved_std_err_fh, ">&", STDERR); close STDERR; open (STDERR, ">", \$suppressed_std_error_messages); return ($saved_std_err_fh, \$suppressed_std_error_messages); } #Restores STDERR from saved filehandle. sub restore_std_err { my $old_std_err_fh = shift; close STDERR; open (STDERR, ">&", $old_std_err_fh); }
        Yeah, but why?

        Redirecting STDERR is a tricky thing, there are long perldocs on this issue, and I'm not too confident about portability here.

        And you loose the ability to just selectively silence known warnings, while still being alarmed by unknown issues. So you will need to parse that variable afterwards.

        If you really want to capture all errors indiscriminately, better use warnings FATAL => 'all' inside eval (hence only for that lexical scope)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        UPDATE

        well, ok. One advantage of redirecting STDERR is that print STDERR will also be caught.

        But the errors you've shown most certainly come from some Carp routines.

        (FWIW you might alsow want to look into Carp for silencing advice)

Re: Make Spreadsheet::ParseXLSX be quiet about errors
by kcott (Archbishop) on Aug 19, 2022 at 08:15 UTC

    G'day leszekdubiel,

    "open() - Duping filehandles" explains how you can do this. Here's some example code (stderr_test.pl):

    #!/usr/bin/env perl use strict; use warnings; use autodie; use Spreadsheet::ParseXLSX; my $original_stderr; eval { open $original_stderr, '>&', \*STDERR; open STDERR, '>&', \*STDOUT; Spreadsheet::ParseXLSX->new->parse('invalid.xlsx'); 1; } or do { my $err = $@; print $err; }; open STDERR, '>&', $original_stderr; warn "Now back to normal STDERR\n";

    I set up a clean directory to show how this works.

    ken@titan ~/tmp/pm_11146229 $ ls -l total 1 -rw-r--r-- 1 ken None 0 Aug 19 17:09 invalid.xlsx -rwxr-xr-x 1 ken None 380 Aug 19 18:10 stderr_test.pl ken@titan ~/tmp/pm_11146229 $ ./stderr_test.pl > stdout.out 2> stderr.out ken@titan ~/tmp/pm_11146229 $ ls -l total 6 -rw-r--r-- 1 ken None 0 Aug 19 17:09 invalid.xlsx -rw-r--r-- 1 ken None 26 Aug 19 18:11 stderr.out -rwxr-xr-x 1 ken None 380 Aug 19 18:10 stderr_test.pl -rw-r--r-- 1 ken None 1105 Aug 19 18:11 stdout.out ken@titan ~/tmp/pm_11146229 $ cat stdout.out format error: file is too short at /home/ken/perl5/perlbrew/perls/perl-5.36.0/lib/site_perl/5.36.0/Ar +chive/Zip/Archive.pm line 1031. Archive::Zip::Archive::_findEndOfCentralDirectory(Archive::Zip +::Archive=HASH(0x8000b79b0), IO::File=GLOB(0x800099368)) called at /h +ome/ken/perl5/perlbrew/perls/perl-5.36.0/lib/site_perl/5.36.0/Archive +/Zip/Archive.pm line 761 Archive::Zip::Archive::readFromFileHandle(Archive::Zip::Archiv +e=HASH(0x8000b79b0), IO::File=GLOB(0x800099368), "invalid.xlsx") call +ed at /home/ken/perl5/perlbrew/perls/perl-5.36.0/lib/site_perl/5.36.0 +/Archive/Zip/Archive.pm line 729 Archive::Zip::Archive::read(Archive::Zip::Archive=HASH(0x8000b +79b0), "invalid.xlsx") called at /home/ken/perl5/perlbrew/perls/perl- +5.36.0/lib/site_perl/5.36.0/Spreadsheet/ParseXLSX.pm line 63 Spreadsheet::ParseXLSX::parse(Spreadsheet::ParseXLSX=HASH(0x80 +17a9b88), "invalid.xlsx") called at ./stderr_test.pl line 14 eval {...} called at ./stderr_test.pl line 17 Can't open file 'invalid.xlsx' as a zip file at /home/ken/perl5/perlbr +ew/perls/perl-5.36.0/lib/site_perl/5.36.0/Spreadsheet/ParseXLSX.pm li +ne 63. ken@titan ~/tmp/pm_11146229 $ cat stderr.out Now back to normal STDERR ken@titan ~/tmp/pm_11146229 $

    — Ken

Re: Make Spreadsheet::ParseXLSX be quiet about errors
by NERDVANA (Deacon) on Aug 20, 2022 at 13:29 UTC
    Before attempting to redirect STDERR on your own, I would suggest a module like Capture::Tiny

    my ($stdout, $stderr, @result) = capture { eval { Spreadsheet::ParseXLSX->new->parse("/tmp/invalid.xlsx") } };

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11146229]
Approved by marto
Front-paged by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2024-04-24 04:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found