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 )
@@ -340,6 +345,12 @@ def __init__(self, additional_skip_names=None,
340
345
'io' : fake_filesystem .FakeIoModule ,
341
346
}
342
347
348
+ # No need to patch builtins in Python 3 - builtin open
349
+ # is an alias for io.open
350
+ if IS_PY2 or IS_PYPY :
351
+ self ._fake_module_classes [
352
+ BUILTIN_MODULE ] = fake_filesystem .FakeBuiltinModule
353
+
343
354
# class modules maps class names against a list of modules they can
344
355
# be contained in - this allows for alternative modules like
345
356
# `pathlib` and `pathlib2`
@@ -364,32 +375,37 @@ def __init__(self, additional_skip_names=None,
364
375
# each patched function name has to be looked up separately
365
376
self ._fake_module_functions = {}
366
377
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
378
if (hasattr (fake_module , 'dir' ) and
371
379
inspect .isfunction (fake_module .dir )):
372
380
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
- )
381
+ module_attr = (getattr (fake_module , fct_name ), mod_name )
382
+ self ._fake_module_functions .setdefault (
383
+ fct_name , {})[mod_name ] = module_attr
384
+ if mod_name == 'os' :
385
+ self ._fake_module_functions .setdefault (
386
+ fct_name , {})[OS_MODULE ] = module_attr
387
+
378
388
# special handling for functions in os.path
379
389
fake_module = fake_filesystem .FakePathModule
380
390
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
- )
391
+ module_attr = (getattr (fake_module , fct_name ), PATH_MODULE )
392
+ self ._fake_module_functions .setdefault (
393
+ fct_name , {})['genericpath' ] = module_attr
394
+ self ._fake_module_functions .setdefault (
395
+ fct_name , {})[PATH_MODULE ] = module_attr
396
+
397
+ # special handling for built-in open
398
+ self ._fake_module_functions .setdefault (
399
+ 'open' , {})[BUILTIN_MODULE ] = (
400
+ fake_filesystem .FakeBuiltinModule .open ,
401
+ BUILTIN_MODULE
402
+ )
386
403
387
404
# Attributes set by _refresh()
388
405
self ._modules = {}
389
406
self ._fct_modules = {}
390
407
self ._stubs = None
391
408
self .fs = None
392
- self .fake_open = None
393
409
self .fake_modules = {}
394
410
self ._dyn_patcher = None
395
411
@@ -441,10 +457,10 @@ def _find_modules(self):
441
457
inspect .isbuiltin (fct )) and
442
458
fct .__name__ in self ._fake_module_functions and
443
459
fct .__module__ in self ._fake_module_functions [
444
- fct .__name__ ][ 0 ] }
460
+ fct .__name__ ]}
445
461
for name , fct in functions .items ():
446
462
self ._fct_modules .setdefault (
447
- (name , fct .__name__ ), set ()).add (module )
463
+ (name , fct .__name__ , fct . __module__ ), set ()).add (module )
448
464
449
465
def _refresh (self ):
450
466
"""Renew the fake file system and set the _isStale flag to `False`."""
@@ -456,7 +472,6 @@ def _refresh(self):
456
472
for name in self ._fake_module_classes :
457
473
self .fake_modules [name ] = self ._fake_module_classes [name ](self .fs )
458
474
self .fake_modules [PATH_MODULE ] = self .fake_modules ['os' ].path
459
- self .fake_open = fake_filesystem .FakeFileOpen (self .fs )
460
475
461
476
self ._isStale = False
462
477
@@ -480,16 +495,21 @@ def setUp(self, doctester=None):
480
495
def start_patching (self ):
481
496
if not self ._patching :
482
497
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 )
498
+ if IS_PYPY :
499
+ # patching open via _fct_modules does not work in PyPy
500
+ self ._stubs .smart_set (builtins , 'open' ,
501
+ self .fake_modules [BUILTIN_MODULE ].open )
502
+ if IS_PY2 :
503
+ # file is not a function and has to be handled separately
504
+ self ._stubs .smart_set (builtins , 'file' ,
505
+ self .fake_modules [BUILTIN_MODULE ].open )
506
+
487
507
for name , modules in self ._modules .items ():
488
508
for module , attr in modules :
489
509
self ._stubs .smart_set (
490
510
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 ]
511
+ for (name , ft_name , ft_mod ), modules in self ._fct_modules .items ():
512
+ method , mod_name = self ._fake_module_functions [ft_name ][ ft_mod ]
493
513
fake_module = self .fake_modules [mod_name ]
494
514
attr = method .__get__ (fake_module , fake_module .__class__ )
495
515
for module in modules :
0 commit comments