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

I'm writing some tests with Test::Class and I'm getting warnings from Contextual::Return. Here's a simple example that replicates the problem:
use Contextual::Return; TestIt->runtests(); package TestIt; use base qw( Test::Class ); use Test::More; sub test : Test(1){ ok(1, 'OK!'); }
First, I'm curious as to why I'm seeing these warnings. I'm using the warnings pragma, but that should only warn me about problems in my own files, right? (as opposed to perl -w). Contextual::Return uses the warnings pragma and I'm thinking that's where the problem lies. Is there any way for me to essentially turn warnings off for Contextual::Return, short of making a local copy and commenting it out?

Replies are listed 'Best First'.
Re: I don't care about *your* warnings! (-X)
by tye (Sage) on Feb 28, 2007 at 20:23 UTC

    This is why it is a sin to "use warnings" in modules. :) I never do that. I always do "-w" in my *.t files instead.

    If I want to see warnings from your module, then I'll use "-w". You shouldn't be telling me whether or not I want to see warnings from your module.

    I actually hope that there is some warnings.pm magic that would let me turn on/off warnings from a specific package but nobody so far is familiar with such a feature (and I'm not and I don't see such documented in warnings).

    You could certain go the moderately ugly route of writing a $SIG{__WARN__} handler to throw such away.

    And you can use -X to disable all warnings. But I got the impression that you wanted to see your own warnings.

    I'd certainly patch Contextual::Return to not "use warnings" (and add -w to all of the *.t files) and submit that back to the module's maintainer.

    And it looks like there is room for improvement in making it easy to ignore warnings from a specific module (that did "use warnings" and didn't test well enough, likely).

    - tye        

      Seems to me the sin wasn't the use of "use warnings" but rather lack of attention to warnings. If one is going to put a module out there for the world to use, it better darn well be robust enough to handle any situation that could result in a warning instead of just causing it.

      But this is just my opinion and off topic to boot :)
      My modules spit out warnings when you do something stupid with them, or in a few cases when there is a non-fatal error. They are intended to be useful both for programmers using my modules and for users of your modules.

      I do try to remember to document what warnings I might spit out, so if you really want to hide errors from your users you can, by catching my warnings in a local $SIG{__WARN__}. Anywhere that I don't document my warnings I consider to be a bug, so please report such things using RT.

Re: I don't care about *your* warnings!
by ikegami (Patriarch) on Feb 28, 2007 at 20:17 UTC

    You can't disable a module's warnings if they were enabled using use warnings;.

    If the module's warnings are enabled using -w or $^W, you can disable them using

    { local $^W = 0; call_other_module(); }

    If you want others to be able to disable your warnings, you can do something like the following:

    use if !$ENV{NOWARN}, 'warnings';

    Note: The condition — !$ENV{NOWARN} in this case — is evaluated at the module's compile time, when its loaded.

    ( philcrow mentioned warnings::register as another means of letting others silence your warnings. )

      The docs on warnings aren't particularly clear on this point to me.

      It looks like warnings::register allows me to define a new class of warnings (with the same name as the module). But "uninit value" is already in a class so would disabling the "Contextual::Return" class of warnings disable "uninit value" warnings that come from the Contextual::Return package?

      It looks like it only works to disable warnings when the package goes out of its way to use things like warnings::warnif(...) and so I'm doubtful that it has any impact on the warnings being discussed here.

      Sorry, I don't have the time/motivation at the moment to construct test cases to answer this question myself (for my version of things, anyway); but I am interested in coming back later and reading more about this. (:

      - tye        

        I ran some tests, and warnif (and similar constructs) is the only thing affected.

        Update: Specifically,

        • no warnings 'OtherModule'; has no effect on builtin warnings.
        • use warnings 'OtherModule'; has no effect on builtin warnings.
        • use warnings 'OtherModule'; has no effect on warn warnings.
        • no warnings 'OtherModule'; has no effect on warn warnings.
        • use warnings 'OtherModule'; in the caller enables warnings::warnif warnings in the module.
        • no warnings 'OtherModule'; in the caller disables warnings::warnif warnings in the module.
        • use warnings 'OtherModule'; in the module has no effect.
        • no warnings 'OtherModule'; in the module has no effect.
        • use warnings; in the caller enables warnings::warnif warnings in the module.
        • no warnings; in the caller disables warnings::warnif warnings in the module.
        • use warnings; in the module has no effect on warnings::warnif warnings in the module.
        • no warnings; in the module has no effect on warnings::warnif warnings in the module.
Re: I don't care about *your* warnings!
by adrianh (Chancellor) on Mar 01, 2007 at 14:48 UTC
    First, I'm curious as to why I'm seeing these warnings

    You're seeing them because (under the hood) Test::Class is doing:

    eval { Contextual::Return::Value->isa( 'SomeOtherClass' ) }

    and Contextual::Return::Value::AUTOLOAD isn't written with autoloading class methods in mind and assuming that its first argument is a reference. I've submitted an RT ticket. I might tweak T::C to avoid this, but I think this is really C:R:V's fault :-)

    Is there any way for me to essentially turn warnings off for Contextual::Return, short of making a local copy and commenting it out?
    $SIG{ __WARN__ } = sub { return if caller eq 'Contextual::Return::Value'; warn @_; };

      Actually, I talked with Damian, and he put together a patch for Contextual::Return that seems to take care of it as well. Before that patch, and with an earlier version of T::C (before you wrapped the isa call with the eval) it used to create a fatal error when Contextual::Return was loaded.

      BTW, Test::Class has made my testing soooo much easier and the improvements over the past several months have made it that much more useful. I highly recommend it for testing, especially for large modules and applications.

        BTW, Test::Class has made my testing soooo much easier and the improvements over the past several months have made it that much more useful. I highly recommend it for testing, especially for large modules and applications.

        Flattery gets you everywhere :-)

      I might tweak T::C to avoid this
      0.24 on its way to CPAN now avoids these warnings, and has a bug fix to boot :-)
Re: I don't care about *your* warnings!
by philcrow (Priest) on Feb 28, 2007 at 19:50 UTC
    Update: Sorry for my previous wrong answer. I was thinking about some code of mine that uses warnings::register. Then the caller can turn off its warnings:
    { no warnings qw( PackageName ); PackageName::subname(...); }
    Of course, that requires more cooperation from the used module than the OP has.

    Phil

      No, that's wrong. The warnings pragma is lexically (statically) scoped, not dynamically scoped.

      { package OtherModule; use warnings; sub routine { my $n = 0; my $i = $n + "a"; } } { no warnings; OtherModule->routine(); }
      Argument "a" isn't numeric in addition (+) at 602580.pl line 4.

      And unfortunately, use warnings; (and no warnings;) overrides $^W.

      { package OtherModule; use warnings; sub routine { my $n = 0; my $i = $n + "a"; } } { local $^W = 0; OtherModule->routine(); }
      Argument "a" isn't numeric in addition (+) at 602580.pl line 4.

      Update: The warnings was initially a compile-time warning. Fixed it to be a run-time warning.

      If the other module has 'use warnings;', you should be able to suppress its warnings with a block like this
      No you shouldn't. The 'warnings' pragma's effect is lexically scoped, not dynamically scoped.

      Dave.

      That's actually the first thing I tried. I'm having trouble overriding Test::Class methods when I sub-class (I'm still working on that problem) but even if I localize the module and modify it to put the call in a block with warnings turned off, it still emits warnings. That method still doesn't work even in this simplified example:

      { no warnings; Foo->bar(); } package Foo; use warnings; sub bar{ print $baz }

      Or am I doing something wrong here?

Re: I don't care about *your* warnings!
by EvanK (Chaplain) on Feb 28, 2007 at 19:53 UTC
    What exactly are the warnings you're seeing? It is possible for a syntax or logic error in your own code (or even an environmental anomaly) to cause an error or warning in a module you're using...(I know, I've done it before)

    __________
    Systems development is like banging your head against a wall...
    It's usually very painful, but if you're persistent, you'll get through it.

      I'm getting a couple of uninitialized value errors. The main problem is that it's not being triggered by any code I wrote, it's actually Test::Class that's doing some quirky stuff. I was trying to debug it and I was surprized that I couldn't get the warnings to go away. If no one is familiar enough with the infrastructure of these two modules to help from that perspective, I'll take the question to the QA list or the author.

      I'm still interested in how to get warnings in a third-party module turned off, though :)