@@ -130,6 +130,54 @@ def stop_patching(self):
130130 tempfile .tempdir = None
131131
132132
133+ class LineCachePatcher :
134+ """Handles linecache patching for newer Python versions."""
135+
136+ def __init__ (self ):
137+ self .linecache_updatecache = None
138+ self .linecache_checkcache = None
139+
140+ def start_patching (self ):
141+ if self .linecache_updatecache is not None :
142+ return
143+
144+ def checkcache (filename = None ):
145+ """Calls the original linecache.checkcache making sure no fake OS calls
146+ are used."""
147+ with use_original_os ():
148+ return self .linecache_checkcache (filename )
149+
150+ def updatecache (filename , module_globals = None ):
151+ """Calls the original linecache.updatecache making sure no fake OS calls
152+ are used."""
153+
154+ with use_original_os ():
155+ # workaround for updatecache problem with pytest under Windows, see #1096
156+ if not filename .endswith (r"pytest.exe\__main__.py" ):
157+ return self .linecache_updatecache (filename , module_globals )
158+ return []
159+
160+ if (
161+ sys .version_info >= (3 , 13 )
162+ or sys .platform == "win32"
163+ and sys .version_info >= (3 , 12 )
164+ ):
165+ # in linecache, 'os' is now imported locally, which involves the
166+ # dynamic patcher, therefore we patch the affected functions
167+ self .linecache_updatecache = linecache .updatecache
168+ linecache .updatecache = updatecache
169+ self .linecache_checkcache = linecache .checkcache
170+ linecache .checkcache = checkcache
171+
172+ def stop_patching (self ):
173+ if self .linecache_updatecache is None :
174+ return
175+ linecache .updatecache = self .linecache_updatecache
176+ linecache .checkcache = self .linecache_checkcache
177+ self .linecache_updatecache = None
178+ self .linecache_checkcache = None
179+
180+
133181def patchfs (
134182 _func : Optional [Callable ] = None ,
135183 * ,
@@ -616,9 +664,8 @@ def __init__(
616664 # save the original open function for use in pytest plugin
617665 self .original_open = open
618666 self .patch_open_code = patch_open_code
619- self .linecache_updatecache = None
620- self .linecache_checkcache = None
621667 self .tempfile_patcher = TempfilePatcher ()
668+ self .linecache_patcher = LineCachePatcher ()
622669
623670 if additional_skip_names is not None :
624671 skip_names = [
@@ -692,21 +739,6 @@ def __init__(
692739 self .has_copy_file_range = False
693740 self .has_copy_file = False
694741
695- def checkcache (self , filename = None ):
696- """Calls the original linecache.checkcache making sure no fake OS calls
697- are used."""
698- with use_original_os ():
699- return self .linecache_checkcache (filename )
700-
701- def updatecache (self , filename , module_globals = None ):
702- """Calls the original linecache.updatecache making sure no fake OS calls
703- are used."""
704- with use_original_os ():
705- # workaround for updatecache problem with pytest under Windows, see #1096
706- if not filename .endswith (r"pytest.exe\__main__.py" ):
707- return self .linecache_updatecache (filename , module_globals )
708- return []
709-
710742 @classmethod
711743 def clear_fs_cache (cls ) -> None :
712744 """Clear the module cache."""
@@ -1028,14 +1060,7 @@ def start_patching(self) -> None:
10281060 self ._patching = True
10291061 self ._paused = False
10301062
1031- if sys .version_info >= (3 , 12 ):
1032- # in linecache, 'os' is now imported locally, which involves the
1033- # dynamic patcher, therefore we patch the affected functions
1034- self .linecache_updatecache = linecache .updatecache
1035- linecache .updatecache = self .updatecache
1036- self .linecache_checkcache = linecache .checkcache
1037- linecache .checkcache = self .checkcache
1038-
1063+ self .linecache_patcher .start_patching ()
10391064 self .tempfile_patcher .start_patching ()
10401065
10411066 self .patch_modules ()
@@ -1156,9 +1181,7 @@ def stop_patching(self, temporary=False) -> None:
11561181 self ._dyn_patcher .cleanup ()
11571182 sys .meta_path .pop (0 )
11581183 self .tempfile_patcher .stop_patching ()
1159- if self .linecache_updatecache is not None :
1160- linecache .updatecache = self .linecache_updatecache
1161- linecache .checkcache = self .linecache_checkcache
1184+ self .linecache_patcher .stop_patching ()
11621185 self ._set_glob_os_functions ()
11631186
11641187 @property
0 commit comments