@@ -186,23 +186,25 @@ def simplefilter(action, category=Warning, lineno=0, append=False):
186
186
_add_filter (action , None , category , None , lineno , append = append )
187
187
188
188
def _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 ()
201
202
202
203
def resetwarnings ():
203
204
"""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 ()
206
208
207
209
class _OptionError (Exception ):
208
210
"""Exception used by option processing helpers."""
@@ -353,64 +355,66 @@ def warn_explicit(message, category, filename, lineno,
353
355
module = filename or "<unknown>"
354
356
if module [- 3 :].lower () == ".py" :
355
357
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
361
358
if isinstance (message , Warning ):
362
359
text = str (message )
363
360
category = message .__class__
364
361
else :
365
362
text = message
366
363
message = category (message )
367
364
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 ))
384
412
385
413
# Prime the linecache for formatting, in case the
386
414
# "file" is actually in a zipfile or something.
387
415
import linecache
388
416
linecache .getlines (filename , module_globals )
389
417
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 ))
414
418
# Print message and context
415
419
msg = WarningMessage (message , category , filename , lineno , source )
416
420
_showwarnmsg (msg )
@@ -488,11 +492,12 @@ def __enter__(self):
488
492
if self ._entered :
489
493
raise RuntimeError ("Cannot enter %r twice" % self )
490
494
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
496
501
if self ._filter is not None :
497
502
simplefilter (* self ._filter )
498
503
if self ._record :
@@ -508,10 +513,11 @@ def __enter__(self):
508
513
def __exit__ (self , * exc_info ):
509
514
if not self ._entered :
510
515
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
515
521
516
522
517
523
class deprecated :
@@ -701,17 +707,48 @@ def extract():
701
707
# If either if the compiled regexs are None, match anything.
702
708
try :
703
709
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
+ )
705
714
defaultaction = _defaultaction
706
715
onceregistry = _onceregistry
707
716
_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
+
708
734
except ImportError :
709
735
filters = []
710
736
defaultaction = "default"
711
737
onceregistry = {}
712
738
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
+
713
746
_filters_version = 1
714
747
748
+ def _filters_mutated_unlocked ():
749
+ global _filters_version
750
+ _filters_version += 1
751
+
715
752
def _filters_mutated ():
716
753
global _filters_version
717
754
_filters_version += 1
0 commit comments