Package: warn
warnBetter warnings.See the fulldocumentation.The Python standardwarning
moduleis extremely
good, and I believe underutilized; Though it missed a few functionality;
in particular it allows filtering only on the code that triggered/called
a deprecated functions, but have no ability to filter depending on the
module that emitted the warning.This is an attempt to fix that.Too long didn’t read:Explicit is better than implicit:from warn import patch
patch()

# use the warning module as usualThough thewarnings.filterwarningfunction has now gained theemodulekeyword parameter to filer by the module that emitted the
warning; example:import warnings
warnings.filter('default', category=DeprecationWarnings, emodule='matplotlib\.pyplot.*')All warnings frommatplotlib.pyplotand its submodule will now be
show by default, regardless of whether you trigger them directly, via
pandas, seaborn, your own code…Warning emitter, warning caller.Python warnings are a beautiful relative simple piece of code which is
extremely powerful in the right hands once you learned how to use it.It allows you to determine a posteriori whether you want a particular
piece of code to trigger an exception, display a message to the user or
simply do nothing.It is difficult to show the full power of the waring with a simple piece
of code, but in large code base, and once you start having several layer
of dependency a parsimonious usage of warning , and in particularDeprecationWarningcan make a large difference.Caller, vs EmitterLet’s clear up some vocabulary first, to differentiate the warning
“Caller” from the warning “Emitter”# file emitter.pydefpublic_api(param1,deprecated_parameter=None)::ifdeprecated_parameter:return_deprecated_function(param1,deprecated_parameter):else:returnnormal_buisnell_logic(param1)def_deprecated_function(param1,deprecated_parameter):importwarningsA# warning emitted herewarnings.warn('using `deprecated_parameter` is deprecated ',DeprecationWarning,stacklevel=3)# file caller.pyfromemitterimportpublic_apipublic_api(1,True)# warning triggered here.you can now do something likefromwarnimportpathpatch()importwarningswarnings.filter('default',category=DeprecationWarnings,emodule='emitter.*')importemitteremitter.bar()# will log the warning !Change this to “error” in your test-suite, and filter by all your
dependencies !The Python built-in module allow you to filter warning by caller
(assuming the emitter have set thestackleveloptions right, which
is not always obvious to do). This is extremely useful when you are
developing the caller; but not that much when you are developing the
emitter.It is common for a caller to actually have many underlying library the
can trigger warnings, or for a developer to only care about a subset of
the emitter warnings.Many libraries are going around this limitation by sub-classing
Warnings; two example areMatplolibandsympyin order to selectively enable them. Still this only give a coarse way
of filtering warnings, and it required to know where the warnings are
defined in order to import and filter for them.Because of Python default choice to filter out deprecation warnings,
this also forced either inheritUserWarning(choice of matplotlib),
which removes the semantic meaning ofDeprecationWarningoffered by
Python or to inject a custom filter in the warnings filter module on
import (choice of Sympy), which can lead to surprising behavior.Availability on Python 2I don’t know if if works on Python 2; I don’t really have the time to
investigate; I don’t particularly care a lot; but feel free to send a PR
that ads support if necessary I would be happy to merge it.limitationsThis does not work on packages that either :Got and keep a reference onwarnings.warnbeforepatch()have
been called; that is to say things of the form:from warnings iport warnCannot work on C-extensions (aka won’t filter onnumpy) ; Both of
the above are technically possible with Assembly Patching which I’m
not confortable with.The UglyAs Warnings filtershave to be 5 tuples with specific typesthis works
by shoving dummy instances in the filters list and using this as keys
for a proxy to lookup real filter keys. So worse case scenario the
filter you insert with this module will just be no-op. But you will
incur a performance penalty if you use this, especially if your codebase
triggers a lot of warnings.Get the upstreamI’dlovefeedback and have a nicer API to deal with warnings at
CPython level in order to provide custom filters, and custom filters
functions.ApartéGood Deprecation Warnings.A good warning and in particular Deprecation warning is extremely
helpful and can make the difference for the adoption of an API. Take the
following fiction example:>>>importwarnings>>>warnings.simplefilter('default')>>>fromquezetrasteimportfrobulate,constribule>>>frobulate('HI',3)DeprecationWarning:The'frobulate'functionisdeprecated.>>>contribule('Hi',3)DeprecationWarning:The'constribule(message, recipient_id)'functionofthe'quezetraste'packageisdeprecatedsinceversion7.3.Ithazbeenreplacedby'Recipient(id).send(message)'whichwasavailablesince7.2.Seehttp://url.to/documentation/#1337Turn the DeprecationWarnings into error in your test-suite!At least make them visible; at best once you fixed a deprecation warning
turnthis specific oneinto an error to not reproduce it.