I want to patch a method by running the original method with additional code before and after. In particular, I'm running tests within a pyfakefs
in-memory file system, but I want to sometime use the real file system because some packages will not work on the fake file system (pybedtools
in my case).
There is probably simple way to do this, but I can't figure it out after many, many tries. Is this possible?
Just for an example, below I'm trying to patch to_csv
in pandas.
import os
import tempfile
from unittest.mock import patch
import pandas as pd
from pyfakefs.fake_filesystem_unittest import Patcher
df_intervals = pd.DataFrame([
['1', 10, 20],
['20', 45, 55]],
columns=['chrom', 'start', 'end'])
with Patcher(use_known_patches=True) as patcher:
# As expecte writing to fake filesystem works
fname = tempfile.NamedTemporaryFile()
df_intervals.to_csv(fname.name)
assert not os.path.exists(fname.name)
assert patcher.fs.isfile(fname.name)
# But, how do I patch `to_csv` to write to the real filesystem? My failed attempts:
# Attempt 1
# TypeError: super(type, obj): obj must be an instance or subtype of type
class patched_DataFrame(pd.DataFrame):
def to_csv(self, fname):
print('Pausing fake file system')
patcher.pause()
super().to_csv(fname)
print('Resuming fake file system')
patcher.resume()
with patch.object(pd.core.generic.NDFrame, 'to_csv', new=patched_DataFrame.to_csv):
df_intervals.to_csv(fname.name)
# Attempt 2: TypeError: 'patched_DataFrame' object is not callable
with patch('pandas.core.frame.DataFrame', new_callable=patched_DataFrame):
df_intervals.to_csv(fname.name)
# Attempt 3: infinite recursion
def patched_to_csv(self, fname):
print('Pausing fake file system')
patcher.pause()
self.to_csv(fname)
print('Resuming fake file system')
patcher.resume()
with patch.object(pd.core.generic.NDFrame, 'to_csv', new=patched_to_csv):
df_intervals.to_csv(fname.name)