Porting Python2 file derived class to Python 3

Viewed 79

I'm porting some Python 2 legacy code and I have this class:

class myfile(file):
    "Wrapper for file object whose read member returns a string buffer"
    def __init__ (self, *args):
        return file.__init__ (self, *args)

    def read(self, size=-1):
        return create_string_buffer(file.read(self, size))

It's used like a File object:

self._file = myfile(name, mode, buffering)
self._file.seek(self.si*self.blocksize)

I'm trying to implement it in Python 3 like so:

class myfile(io.FileIO):
    "Wrapper for file object whose read member returns a string buffer"
    def __init__(self, name, mode, *args, **kwargs):
        super(myfile, self).__init__(name, mode, closefd=True, *args, **kwargs)

    def read(self, size=-1):
        return create_string_buffer(self.read(size))

The problem is that the constructor for FileIO doesn't take the buffering argument and Python throws a TypeError: fileio() takes at most 3 arguments (4 given) error.

The Python 3 open function is what I need. Can I inherit from that? I've looked at the PyFile_FromFd class, but it needs an open file descriptor and I'm concerned that the behaviour is not going to be the same.

Thank you!!!

2 Answers

You can't inherit from open. The buffering argument changes the class returned, so open is implemented as a function that can return one of several classes. Best option is to do the same thing, with your own wrapper classes if necessary.

Basic implementation idea is:

  1. myfile is a function with a signature similar to open
  2. You have two classes, one inheriting from FileIO, one from BufferedReader.
  3. When myfile is invoked, it inspects the buffering argument, and either creates and returns the FileIO derived subclass (when unbuffered) or creates a normal unbuffered FileIO class with open, then wraps it in your BufferedReader derived subclass.

One quick solution would be monkey patching:

def myfile(*args, **kwargs):
    f = open(*args, **kwargs)

    def read(size=-1):
        return create_string_buffer(f._read(size))

    f._read = f.read # save old read method
    f.read = read # patch

    return f
Related