43
43
import unittest
44
44
import zipfile # noqa: F401 make sure it gets correctly stubbed, see #427
45
45
46
+ from pyfakefs .helpers import IS_PY2 , IS_PYPY
47
+
46
48
from pyfakefs .deprecator import Deprecator
47
49
48
50
try :
79
81
80
82
OS_MODULE = 'nt' if sys .platform == 'win32' else 'posix'
81
83
PATH_MODULE = 'ntpath' if sys .platform == 'win32' else 'posixpath'
84
+ BUILTIN_MODULE = '__builtin__' if IS_PY2 else 'buildins'
82
85
83
86
84
87
def load_doctests (loader , tests , ignore , module ,
@@ -319,6 +322,8 @@ def __init__(self, additional_skip_names=None,
319
322
"""For a description of the arguments, see TestCase.__init__"""
320
323
321
324
self ._skipNames = self .SKIPNAMES .copy ()
325
+ # save the original open function for use in pytest plugin
326
+ self .original_open = open
322
327
323
328
if additional_skip_names is not None :
324
329
self ._skipNames .update (additional_skip_names )
@@ -339,6 +344,15 @@ def __init__(self, additional_skip_names=None,
339
344
'shutil' : fake_filesystem_shutil .FakeShutilModule ,
340
345
'io' : fake_filesystem .FakeIoModule ,
341
346
}
347
+ if IS_PY2 or IS_PYPY :
348
+ # in Python 2 io.open, the module is referenced as _io
349
+ self ._fake_module_classes ['_io' ] = fake_filesystem .FakeIoModule
350
+
351
+ # No need to patch builtins in Python 3 - builtin open
352
+ # is an alias for io.open
353
+ if IS_PY2 or IS_PYPY :
354
+ self ._fake_module_classes [
355
+ BUILTIN_MODULE ] = fake_filesystem .FakeBuiltinModule
342
356
343
357
# class modules maps class names against a list of modules they can
344
358
# be contained in - this allows for alternative modules like
@@ -364,32 +378,37 @@ def __init__(self, additional_skip_names=None,
364
378
# each patched function name has to be looked up separately
365
379
self ._fake_module_functions = {}
366
380
for mod_name , fake_module in self ._fake_module_classes .items ():
367
- modnames = (
368
- (mod_name , OS_MODULE ) if mod_name == 'os' else (mod_name ,)
369
- )
370
381
if (hasattr (fake_module , 'dir' ) and
371
382
inspect .isfunction (fake_module .dir )):
372
383
for fct_name in fake_module .dir ():
373
- self ._fake_module_functions [fct_name ] = (
374
- modnames ,
375
- getattr (fake_module , fct_name ),
376
- mod_name
377
- )
384
+ module_attr = (getattr (fake_module , fct_name ), mod_name )
385
+ self ._fake_module_functions .setdefault (
386
+ fct_name , {})[mod_name ] = module_attr
387
+ if mod_name == 'os' :
388
+ self ._fake_module_functions .setdefault (
389
+ fct_name , {})[OS_MODULE ] = module_attr
390
+
378
391
# special handling for functions in os.path
379
392
fake_module = fake_filesystem .FakePathModule
380
393
for fct_name in fake_module .dir ():
381
- self ._fake_module_functions [fct_name ] = (
382
- ('genericpath' , PATH_MODULE ),
383
- getattr (fake_module , fct_name ),
384
- PATH_MODULE
385
- )
394
+ module_attr = (getattr (fake_module , fct_name ), PATH_MODULE )
395
+ self ._fake_module_functions .setdefault (
396
+ fct_name , {})['genericpath' ] = module_attr
397
+ self ._fake_module_functions .setdefault (
398
+ fct_name , {})[PATH_MODULE ] = module_attr
399
+
400
+ # special handling for built-in open
401
+ self ._fake_module_functions .setdefault (
402
+ 'open' , {})[BUILTIN_MODULE ] = (
403
+ fake_filesystem .FakeBuiltinModule .open ,
404
+ BUILTIN_MODULE
405
+ )
386
406
387
407
# Attributes set by _refresh()
388
408
self ._modules = {}
389
409
self ._fct_modules = {}
390
410
self ._stubs = None
391
411
self .fs = None
392
- self .fake_open = None
393
412
self .fake_modules = {}
394
413
self ._dyn_patcher = None
395
414
@@ -441,10 +460,10 @@ def _find_modules(self):
441
460
inspect .isbuiltin (fct )) and
442
461
fct .__name__ in self ._fake_module_functions and
443
462
fct .__module__ in self ._fake_module_functions [
444
- fct .__name__ ][ 0 ] }
463
+ fct .__name__ ]}
445
464
for name , fct in functions .items ():
446
465
self ._fct_modules .setdefault (
447
- (name , fct .__name__ ), set ()).add (module )
466
+ (name , fct .__name__ , fct . __module__ ), set ()).add (module )
448
467
449
468
def _refresh (self ):
450
469
"""Renew the fake file system and set the _isStale flag to `False`."""
@@ -456,7 +475,6 @@ def _refresh(self):
456
475
for name in self ._fake_module_classes :
457
476
self .fake_modules [name ] = self ._fake_module_classes [name ](self .fs )
458
477
self .fake_modules [PATH_MODULE ] = self .fake_modules ['os' ].path
459
- self .fake_open = fake_filesystem .FakeFileOpen (self .fs )
460
478
461
479
self ._isStale = False
462
480
@@ -480,16 +498,21 @@ def setUp(self, doctester=None):
480
498
def start_patching (self ):
481
499
if not self ._patching :
482
500
self ._patching = True
483
- if sys .version_info < (3 ,):
484
- # file() was eliminated in Python3
485
- self ._stubs .smart_set (builtins , 'file' , self .fake_open )
486
- self ._stubs .smart_set (builtins , 'open' , self .fake_open )
501
+ if IS_PYPY :
502
+ # patching open via _fct_modules does not work in PyPy
503
+ self ._stubs .smart_set (builtins , 'open' ,
504
+ self .fake_modules [BUILTIN_MODULE ].open )
505
+ if IS_PY2 :
506
+ # file is not a function and has to be handled separately
507
+ self ._stubs .smart_set (builtins , 'file' ,
508
+ self .fake_modules [BUILTIN_MODULE ].open )
509
+
487
510
for name , modules in self ._modules .items ():
488
511
for module , attr in modules :
489
512
self ._stubs .smart_set (
490
513
module , name , self .fake_modules [attr ])
491
- for (name , fct_name ), modules in self ._fct_modules .items ():
492
- _ , method , mod_name = self ._fake_module_functions [fct_name ]
514
+ for (name , ft_name , ft_mod ), modules in self ._fct_modules .items ():
515
+ method , mod_name = self ._fake_module_functions [ft_name ][ ft_mod ]
493
516
fake_module = self .fake_modules [mod_name ]
494
517
attr = method .__get__ (fake_module , fake_module .__class__ )
495
518
for module in modules :
0 commit comments