@@ -367,7 +367,11 @@ class Patcher:
367367 }
368368 # caches all modules that do not have file system modules or function
369369 # to speed up _find_modules
370- CACHED_SKIPMODULES = set ()
370+ CACHED_MODULES = set ()
371+ FS_MODULES = {}
372+ FS_FUNCTIONS = {}
373+ FS_DEFARGS = []
374+ SKIPPED_FS_MODULES = {}
371375
372376 assert None in SKIPMODULES , ("sys.modules contains 'None' values;"
373377 " must skip them." )
@@ -379,6 +383,7 @@ class Patcher:
379383 # hold values from last call - if changed, the cache in
380384 # CACHED_SKIPMODULES has to be invalidated
381385 PATCHED_MODULE_NAMES = {}
386+ ADDITIONAL_SKIP_NAMES = set ()
382387 PATCH_DEFAULT_ARGS = False
383388
384389 def __init__ (self , additional_skip_names = None ,
@@ -413,8 +418,8 @@ def __init__(self, additional_skip_names=None,
413418 patch_default_args: If True, default arguments are checked for
414419 file system functions, which are patched. This check is
415420 expansive, so it is off by default.
416- use_cache: If True (default), non-patched modules are cached
417- between tests for performance reasons. As this is a new
421+ use_cache: If True (default), patched and non-patched modules are
422+ cached between tests for performance reasons. As this is a new
418423 feature, this argument allows to turn it off in case it
419424 causes any problems.
420425 """
@@ -446,9 +451,6 @@ def __init__(self, additional_skip_names=None,
446451 self .modules_to_reload .extend (modules_to_reload )
447452 self .patch_default_args = patch_default_args
448453 self .use_cache = use_cache
449- if patch_default_args != self .PATCH_DEFAULT_ARGS :
450- self .__class__ .PATCH_DEFAULT_ARGS = patch_default_args
451- self .clear_cache ()
452454
453455 if use_known_patches :
454456 modules_to_patch = modules_to_patch or {}
@@ -460,33 +462,41 @@ def __init__(self, additional_skip_names=None,
460462 for name , fake_module in modules_to_patch .items ():
461463 self ._fake_module_classes [name ] = fake_module
462464 patched_module_names = set (modules_to_patch )
463- if patched_module_names != self .PATCHED_MODULE_NAMES :
464- self .__class__ .PATCHED_MODULE_NAMES = patched_module_names
465+ clear_cache = not use_cache
466+ if use_cache :
467+ if patched_module_names != self .PATCHED_MODULE_NAMES :
468+ self .__class__ .PATCHED_MODULE_NAMES = patched_module_names
469+ clear_cache = True
470+ if self ._skip_names != self .ADDITIONAL_SKIP_NAMES :
471+ self .__class__ .ADDITIONAL_SKIP_NAMES = self ._skip_names
472+ clear_cache = True
473+ if patch_default_args != self .PATCH_DEFAULT_ARGS :
474+ self .__class__ .PATCH_DEFAULT_ARGS = patch_default_args
475+ clear_cache = True
476+
477+ if clear_cache :
465478 self .clear_cache ()
466-
467479 self ._fake_module_functions = {}
468480 self ._init_fake_module_functions ()
469481
470482 # Attributes set by _refresh()
471- self ._modules = {}
472- self ._skipped_modules = {}
473- self ._fct_modules = {}
474- self ._def_functions = []
475- self ._open_functions = {}
476483 self ._stubs = None
477484 self .fs = None
478485 self .fake_modules = {}
479486 self .unfaked_modules = {}
480- self ._dyn_patcher = None
481487
482488 # _isStale is set by tearDown(), reset by _refresh()
483489 self ._isStale = True
490+ self ._dyn_patcher = None
484491 self ._patching = False
485- self .found_fs_module = False
486492
487493 def clear_cache (self ):
488- """Clear the cache of non-patched modules."""
489- self .__class__ .CACHED_SKIPMODULES = set ()
494+ """Clear the module cache."""
495+ self .__class__ .CACHED_MODULES = set ()
496+ self .__class__ .FS_MODULES = {}
497+ self .__class__ .FS_FUNCTIONS = {}
498+ self .__class__ .FS_DEFARGS = []
499+ self .__class__ .SKIPPED_FS_MODULES = {}
490500
491501 def _init_fake_module_classes (self ):
492502 # IMPORTANT TESTING NOTE: Whenever you add a new module below, test
@@ -567,17 +577,13 @@ def _is_fs_module(self, mod, name, module_names):
567577 # check for __name__ first and ignore the AttributeException
568578 # if it does not exist - avoids calling expansive ismodule
569579 if mod .__name__ in module_names and inspect .ismodule (mod ):
570- self .found_fs_module = True
571580 return True
572581 except Exception :
573582 pass
574583 try :
575584 if (name in self ._class_modules and
576585 mod .__module__ in self ._class_modules [name ]):
577- if inspect .isclass (mod ):
578- self .found_fs_module = True
579- return True
580- return False
586+ return inspect .isclass (mod )
581587 except Exception :
582588 # handle AttributeError and any other exception possibly triggered
583589 # by side effects of inspect methods
@@ -588,13 +594,10 @@ def _is_fs_function(self, fct):
588594 # check for __name__ first and ignore the AttributeException
589595 # if it does not exist - avoids calling expansive inspect
590596 # methods in most cases
591- if (fct .__name__ in self ._fake_module_functions and
597+ return (fct .__name__ in self ._fake_module_functions and
592598 fct .__module__ in self ._fake_module_functions [
593599 fct .__name__ ] and
594- (inspect .isfunction (fct ) or inspect .isbuiltin (fct ))):
595- self .found_fs_module = True
596- return True
597- return False
600+ (inspect .isfunction (fct ) or inspect .isbuiltin (fct )))
598601 except Exception :
599602 # handle AttributeError and any other exception possibly triggered
600603 # by side effects of inspect methods
@@ -632,7 +635,7 @@ def _def_values(self, item):
632635 def _find_def_values (self , module_items ):
633636 for _ , fct in module_items :
634637 for f , i , d in self ._def_values (fct ):
635- self ._def_functions .append ((f , i , d ))
638+ self .__class__ . FS_DEFARGS .append ((f , i , d ))
636639
637640 def _find_modules (self ):
638641 """Find and cache all modules that import file system modules.
@@ -642,7 +645,7 @@ def _find_modules(self):
642645 module_names = list (self ._fake_module_classes .keys ()) + [PATH_MODULE ]
643646 for name , module in list (sys .modules .items ()):
644647 try :
645- if (self .use_cache and module in self .CACHED_SKIPMODULES or
648+ if (self .use_cache and module in self .CACHED_MODULES or
646649 module in self .SKIPMODULES or
647650 not inspect .ismodule (module )):
648651 continue
@@ -652,9 +655,8 @@ def _find_modules(self):
652655 # see https://github.com/pytest-dev/py/issues/73
653656 # and any other exception triggered by inspect.ismodule
654657 if self .use_cache :
655- self .__class__ .CACHED_SKIPMODULES .add (module )
658+ self .__class__ .CACHED_MODULES .add (module )
656659 continue
657- self .found_fs_module = False
658660 skipped = (any ([sn .startswith (module .__name__ )
659661 for sn in self ._skip_names ]))
660662 module_items = module .__dict__ .copy ().items ()
@@ -664,27 +666,27 @@ def _find_modules(self):
664666
665667 if skipped :
666668 for name , mod in modules .items ():
667- self ._skipped_modules . setdefault ( name , set ()). add (
668- (module , mod .__name__ ))
669+ self .__class__ . SKIPPED_FS_MODULES . setdefault (
670+ name , set ()). add ( (module , mod .__name__ ))
669671 continue
670672
671673 for name , mod in modules .items ():
672- self ._modules .setdefault (name , set ()).add (
674+ self .__class__ . FS_MODULES .setdefault (name , set ()).add (
673675 (module , mod .__name__ ))
674676 functions = {name : fct for name , fct in
675677 module_items
676678 if self ._is_fs_function (fct )}
677679
678680 for name , fct in functions .items ():
679- self ._fct_modules .setdefault (
681+ self .__class__ . FS_FUNCTIONS .setdefault (
680682 (name , fct .__name__ , fct .__module__ ), set ()).add (module )
681683
682684 # find default arguments that are file system functions
683685 if self .patch_default_args :
684686 self ._find_def_values (module_items )
685687
686- if not self . found_fs_module and self .use_cache :
687- self .__class__ .CACHED_SKIPMODULES .add (module )
688+ if self .use_cache :
689+ self .__class__ .CACHED_MODULES .add (module )
688690
689691 def _refresh (self ):
690692 """Renew the fake file system and set the _isStale flag to `False`."""
@@ -723,6 +725,7 @@ def setUp(self, doctester=None):
723725 category = DeprecationWarning
724726 )
725727 self ._find_modules ()
728+
726729 self ._refresh ()
727730
728731 if doctester is not None :
@@ -752,26 +755,26 @@ def start_patching(self):
752755 reload (module )
753756
754757 def patch_functions (self ):
755- for (name , ft_name , ft_mod ), modules in self ._fct_modules .items ():
758+ for (name , ft_name , ft_mod ), modules in self .FS_FUNCTIONS .items ():
756759 method , mod_name = self ._fake_module_functions [ft_name ][ft_mod ]
757760 fake_module = self .fake_modules [mod_name ]
758761 attr = method .__get__ (fake_module , fake_module .__class__ )
759762 for module in modules :
760763 self ._stubs .smart_set (module , name , attr )
761764
762765 def patch_modules (self ):
763- for name , modules in self ._modules .items ():
766+ for name , modules in self .FS_MODULES .items ():
764767 for module , attr in modules :
765768 self ._stubs .smart_set (
766769 module , name , self .fake_modules [attr ])
767- for name , modules in self ._skipped_modules .items ():
770+ for name , modules in self .SKIPPED_FS_MODULES .items ():
768771 for module , attr in modules :
769772 if attr in self .unfaked_modules :
770773 self ._stubs .smart_set (
771774 module , name , self .unfaked_modules [attr ])
772775
773776 def patch_defaults (self ):
774- for (fct , idx , ft ) in self ._def_functions :
777+ for (fct , idx , ft ) in self .FS_DEFARGS :
775778 method , mod_name = self ._fake_module_functions [
776779 ft .__name__ ][ft .__module__ ]
777780 fake_module = self .fake_modules [mod_name ]
@@ -811,15 +814,15 @@ def stop_patching(self):
811814 sys .meta_path .pop (0 )
812815
813816 def unset_defaults (self ):
814- for (fct , idx , ft ) in self ._def_functions :
817+ for (fct , idx , ft ) in self .FS_DEFARGS :
815818 new_defaults = []
816819 for i , d in enumerate (fct .__defaults__ ):
817820 if i == idx :
818821 new_defaults .append (ft )
819822 else :
820823 new_defaults .append (d )
821824 fct .__defaults__ = tuple (new_defaults )
822- self ._def_functions = []
825+ # self._def_functions = []
823826
824827 def pause (self ):
825828 """Pause the patching of the file system modules until `resume` is
0 commit comments