4949import sys
5050import tempfile
5151import tokenize
52+ import unittest
53+ import warnings
54+ from importlib import reload
5255from importlib .abc import Loader , MetaPathFinder
56+ from importlib .machinery import ModuleSpec
57+ from importlib .util import spec_from_file_location , module_from_spec
5358from types import ModuleType , TracebackType , FunctionType
5459from typing import (
5560 Any ,
6671 ItemsView ,
6772 Sequence ,
6873)
69- import unittest
70- import warnings
7174from unittest import TestSuite
7275
76+ from pyfakefs import fake_filesystem , fake_io , fake_os , fake_open , fake_path , fake_file
77+ from pyfakefs import fake_filesystem_shutil
78+ from pyfakefs import fake_legacy_modules
79+ from pyfakefs import fake_pathlib
80+ from pyfakefs import mox3_stubout
7381from pyfakefs .fake_filesystem import (
7482 set_uid ,
7583 set_gid ,
7987)
8088from pyfakefs .fake_os import use_original_os
8189from pyfakefs .helpers import IS_PYPY
82- from pyfakefs .mox3_stubout import StubOutForTesting
83-
84- from importlib .machinery import ModuleSpec
85- from importlib import reload
86-
87- from pyfakefs import fake_filesystem , fake_io , fake_os , fake_open , fake_path , fake_file
88- from pyfakefs import fake_legacy_modules
89- from pyfakefs import fake_filesystem_shutil
90- from pyfakefs import fake_pathlib
91- from pyfakefs import mox3_stubout
9290from pyfakefs .legacy_packages import pathlib2 , scandir
91+ from pyfakefs .mox3_stubout import StubOutForTesting
9392
9493OS_MODULE = "nt" if sys .platform == "win32" else "posix"
9594PATH_MODULE = "ntpath" if sys .platform == "win32" else "posixpath"
@@ -1225,14 +1224,32 @@ def cleanup(self) -> None:
12251224 del sys .modules [name ]
12261225
12271226 def needs_patch (self , name : str ) -> bool :
1228- """Check if the module with the given name shall be replaced."""
1227+ """Checks if the module with the given name shall be replaced."""
12291228 if name not in self .modules :
12301229 self ._loaded_module_names .add (name )
12311230 return False
12321231 if name in sys .modules and type (sys .modules [name ]) is self .modules [name ]:
12331232 return False
12341233 return True
12351234
1235+ def fake_module_path (self , name : str ) -> str :
1236+ """Checks if the module with the given name is a module existing in the fake
1237+ filesystem and returns its path in this case.
1238+ """
1239+ fs = self ._patcher .fs
1240+ # we assume that the module name is the absolute module path
1241+ if fs is not None :
1242+ base_path = name .replace ("." , fs .path_separator )
1243+ for path in sys .path :
1244+ module_path = fs .joinpaths (path , base_path )
1245+ py_module_path = module_path + ".py"
1246+ if fs .exists (py_module_path ):
1247+ return py_module_path
1248+ init_path = fs .joinpaths (module_path , "__init__.py" )
1249+ if fs .exists (init_path ):
1250+ return init_path
1251+ return ""
1252+
12361253 def find_spec (
12371254 self ,
12381255 fullname : str ,
@@ -1242,6 +1259,15 @@ def find_spec(
12421259 """Module finder."""
12431260 if self .needs_patch (fullname ):
12441261 return ModuleSpec (fullname , self )
1262+ if self ._patcher .patch_open_code != PatchMode .OFF :
1263+ # handle modules created in the fake filesystem
1264+ module_path = self .fake_module_path (fullname )
1265+ if module_path :
1266+ spec = spec_from_file_location (fullname , module_path )
1267+ if spec :
1268+ module = module_from_spec (spec )
1269+ sys .modules [fullname ] = module
1270+ return ModuleSpec (fullname , self )
12451271 return None
12461272
12471273 def load_module (self , fullname : str ) -> ModuleType :
0 commit comments