1# Licensed under the Apache License, Version 2.0 (the "License"); 2# you may not use this file except in compliance with the License. 3# You may obtain a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, 9# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10# See the License for the specific language governing permissions and 11# limitations under the License. 12 13""" 14Provides patches for some commonly used modules that enable them to work 15with pyfakefs. 16""" 17import sys 18 19try: 20 import pandas.io.parsers as parsers 21except ImportError: 22 parsers = None 23 24try: 25 import xlrd 26except ImportError: 27 xlrd = None 28 29try: 30 from django.core.files import locks 31except ImportError: 32 locks = None 33 34 35def get_modules_to_patch(): 36 modules_to_patch = {} 37 if xlrd is not None: 38 modules_to_patch['xlrd'] = XLRDModule 39 if locks is not None: 40 modules_to_patch['django.core.files.locks'] = FakeLocks 41 return modules_to_patch 42 43 44def get_classes_to_patch(): 45 classes_to_patch = {} 46 if parsers is not None: 47 classes_to_patch[ 48 'TextFileReader' 49 ] = 'pandas.io.parsers' 50 return classes_to_patch 51 52 53def get_fake_module_classes(): 54 fake_module_classes = {} 55 if parsers is not None: 56 fake_module_classes[ 57 'TextFileReader' 58 ] = FakeTextFileReader 59 return fake_module_classes 60 61 62if xlrd is not None: 63 class XLRDModule: 64 """Patches the xlrd module, which is used as the default Excel file 65 reader by pandas. Disables using memory mapped files, which are 66 implemented platform-specific on OS level.""" 67 68 def __init__(self, _): 69 self._xlrd_module = xlrd 70 71 def open_workbook(self, filename=None, 72 logfile=sys.stdout, 73 verbosity=0, 74 use_mmap=False, 75 file_contents=None, 76 encoding_override=None, 77 formatting_info=False, 78 on_demand=False, 79 ragged_rows=False): 80 return self._xlrd_module.open_workbook( 81 filename, logfile, verbosity, False, file_contents, 82 encoding_override, formatting_info, on_demand, ragged_rows) 83 84 def __getattr__(self, name): 85 """Forwards any unfaked calls to the standard xlrd module.""" 86 return getattr(self._xlrd_module, name) 87 88if parsers is not None: 89 # we currently need to add fake modules for both the parser module and 90 # the contained text reader - maybe this can be simplified 91 92 class FakeTextFileReader: 93 fake_parsers = None 94 95 def __init__(self, filesystem): 96 if self.fake_parsers is None: 97 self.__class__.fake_parsers = ParsersModule(filesystem) 98 99 def __call__(self, *args, **kwargs): 100 return self.fake_parsers.TextFileReader(*args, **kwargs) 101 102 def __getattr__(self, name): 103 return getattr(self.fake_parsers.TextFileReader, name) 104 105 class ParsersModule: 106 def __init__(self, _): 107 self._parsers_module = parsers 108 109 class TextFileReader(parsers.TextFileReader): 110 def __init__(self, *args, **kwargs): 111 kwargs['engine'] = 'python' 112 super().__init__(*args, **kwargs) 113 114 def __getattr__(self, name): 115 """Forwards any unfaked calls to the standard xlrd module.""" 116 return getattr(self._parsers_module, name) 117 118if locks is not None: 119 class FakeLocks: 120 """django.core.files.locks uses low level OS functions, fake it.""" 121 _locks_module = locks 122 123 def __init__(self, _): 124 pass 125 126 @staticmethod 127 def lock(f, flags): 128 return True 129 130 @staticmethod 131 def unlock(f): 132 return True 133 134 def __getattr__(self, name): 135 return getattr(self._locks_module, name) 136