@@ -186,23 +186,25 @@ def simplefilter(action, category=Warning, lineno=0, append=False):
186186 _add_filter (action , None , category , None , lineno , append = append )
187187
188188def _add_filter (* item , append ):
189- # Remove possible duplicate filters, so new one will be placed
190- # in correct place. If append=True and duplicate exists, do nothing.
191- if not append :
192- try :
193- filters .remove (item )
194- except ValueError :
195- pass
196- filters .insert (0 , item )
197- else :
198- if item not in filters :
199- filters .append (item )
200- _filters_mutated ()
189+ with _lock :
190+ if not append :
191+ # Remove possible duplicate filters, so new one will be placed
192+ # in correct place. If append=True and duplicate exists, do nothing.
193+ try :
194+ filters .remove (item )
195+ except ValueError :
196+ pass
197+ filters .insert (0 , item )
198+ else :
199+ if item not in filters :
200+ filters .append (item )
201+ _filters_mutated_unlocked ()
201202
202203def resetwarnings ():
203204 """Clear the list of warning filters, so that no filters are active."""
204- filters [:] = []
205- _filters_mutated ()
205+ with _lock :
206+ filters [:] = []
207+ _filters_mutated_unlocked ()
206208
207209class _OptionError (Exception ):
208210 """Exception used by option processing helpers."""
@@ -353,64 +355,66 @@ def warn_explicit(message, category, filename, lineno,
353355 module = filename or "<unknown>"
354356 if module [- 3 :].lower () == ".py" :
355357 module = module [:- 3 ] # XXX What about leading pathname?
356- if registry is None :
357- registry = {}
358- if registry .get ('version' , 0 ) != _filters_version :
359- registry .clear ()
360- registry ['version' ] = _filters_version
361358 if isinstance (message , Warning ):
362359 text = str (message )
363360 category = message .__class__
364361 else :
365362 text = message
366363 message = category (message )
367364 key = (text , category , lineno )
368- # Quick test for common case
369- if registry .get (key ):
370- return
371- # Search the filters
372- for item in filters :
373- action , msg , cat , mod , ln = item
374- if ((msg is None or msg .match (text )) and
375- issubclass (category , cat ) and
376- (mod is None or mod .match (module )) and
377- (ln == 0 or lineno == ln )):
378- break
379- else :
380- action = defaultaction
381- # Early exit actions
382- if action == "ignore" :
383- return
365+ with _lock :
366+ if registry is None :
367+ registry = {}
368+ if registry .get ('version' , 0 ) != _filters_version :
369+ registry .clear ()
370+ registry ['version' ] = _filters_version
371+ # Quick test for common case
372+ if registry .get (key ):
373+ return
374+ # Search the filters
375+ for item in filters :
376+ action , msg , cat , mod , ln = item
377+ if ((msg is None or msg .match (text )) and
378+ issubclass (category , cat ) and
379+ (mod is None or mod .match (module )) and
380+ (ln == 0 or lineno == ln )):
381+ break
382+ else :
383+ action = defaultaction
384+ # Early exit actions
385+ if action == "ignore" :
386+ return
387+
388+ if action == "error" :
389+ raise message
390+ # Other actions
391+ if action == "once" :
392+ registry [key ] = 1
393+ oncekey = (text , category )
394+ if onceregistry .get (oncekey ):
395+ return
396+ onceregistry [oncekey ] = 1
397+ elif action in {"always" , "all" }:
398+ pass
399+ elif action == "module" :
400+ registry [key ] = 1
401+ altkey = (text , category , 0 )
402+ if registry .get (altkey ):
403+ return
404+ registry [altkey ] = 1
405+ elif action == "default" :
406+ registry [key ] = 1
407+ else :
408+ # Unrecognized actions are errors
409+ raise RuntimeError (
410+ "Unrecognized action (%r) in warnings.filters:\n %s" %
411+ (action , item ))
384412
385413 # Prime the linecache for formatting, in case the
386414 # "file" is actually in a zipfile or something.
387415 import linecache
388416 linecache .getlines (filename , module_globals )
389417
390- if action == "error" :
391- raise message
392- # Other actions
393- if action == "once" :
394- registry [key ] = 1
395- oncekey = (text , category )
396- if onceregistry .get (oncekey ):
397- return
398- onceregistry [oncekey ] = 1
399- elif action in {"always" , "all" }:
400- pass
401- elif action == "module" :
402- registry [key ] = 1
403- altkey = (text , category , 0 )
404- if registry .get (altkey ):
405- return
406- registry [altkey ] = 1
407- elif action == "default" :
408- registry [key ] = 1
409- else :
410- # Unrecognized actions are errors
411- raise RuntimeError (
412- "Unrecognized action (%r) in warnings.filters:\n %s" %
413- (action , item ))
414418 # Print message and context
415419 msg = WarningMessage (message , category , filename , lineno , source )
416420 _showwarnmsg (msg )
@@ -488,11 +492,12 @@ def __enter__(self):
488492 if self ._entered :
489493 raise RuntimeError ("Cannot enter %r twice" % self )
490494 self ._entered = True
491- self ._filters = self ._module .filters
492- self ._module .filters = self ._filters [:]
493- self ._module ._filters_mutated ()
494- self ._showwarning = self ._module .showwarning
495- self ._showwarnmsg_impl = self ._module ._showwarnmsg_impl
495+ with _lock :
496+ self ._filters = self ._module .filters
497+ self ._module .filters = self ._filters [:]
498+ self ._module ._filters_mutated_unlocked ()
499+ self ._showwarning = self ._module .showwarning
500+ self ._showwarnmsg_impl = self ._module ._showwarnmsg_impl
496501 if self ._filter is not None :
497502 simplefilter (* self ._filter )
498503 if self ._record :
@@ -508,10 +513,11 @@ def __enter__(self):
508513 def __exit__ (self , * exc_info ):
509514 if not self ._entered :
510515 raise RuntimeError ("Cannot exit %r without entering first" % self )
511- self ._module .filters = self ._filters
512- self ._module ._filters_mutated ()
513- self ._module .showwarning = self ._showwarning
514- self ._module ._showwarnmsg_impl = self ._showwarnmsg_impl
516+ with _lock :
517+ self ._module .filters = self ._filters
518+ self ._module ._filters_mutated_unlocked ()
519+ self ._module .showwarning = self ._showwarning
520+ self ._module ._showwarnmsg_impl = self ._showwarnmsg_impl
515521
516522
517523class deprecated :
@@ -701,17 +707,48 @@ def extract():
701707# If either if the compiled regexs are None, match anything.
702708try :
703709 from _warnings import (filters , _defaultaction , _onceregistry ,
704- warn , warn_explicit , _filters_mutated )
710+ warn , warn_explicit ,
711+ _filters_mutated_unlocked ,
712+ _acquire_lock , _release_lock ,
713+ )
705714 defaultaction = _defaultaction
706715 onceregistry = _onceregistry
707716 _warnings_defaults = True
717+
718+ class _Lock :
719+ def __enter__ (self ):
720+ _acquire_lock ()
721+ return self
722+
723+ def __exit__ (self , * args ):
724+ _release_lock ()
725+
726+ _lock = _Lock ()
727+
728+ def _filters_mutated ():
729+ # Even though this function is part of the public API, it's used
730+ # by a fair amount of user code.
731+ with _lock :
732+ _filters_mutated_unlocked ()
733+
708734except ImportError :
709735 filters = []
710736 defaultaction = "default"
711737 onceregistry = {}
712738
739+ import _thread
740+
741+ # Note that this is a non-reentrant lock, matching what's used by
742+ # _acquire_lock() and _release_lock(). Care must be taken to
743+ # not deadlock.
744+ _lock = _thread .LockType ()
745+
713746 _filters_version = 1
714747
748+ def _filters_mutated_unlocked ():
749+ global _filters_version
750+ _filters_version += 1
751+
715752 def _filters_mutated ():
716753 global _filters_version
717754 _filters_version += 1
0 commit comments