Search code examples
pythonpython-3.xinheritancepathlibpyfakefs

Keep pathlib.(Posix)Path patched by pyfakefs when subclassing it


I have subclassed PosixPath this way:

from pathlib import PosixPath


class Node(PosixPath):

    def __new__(cls, *args, mykwarg=None, **kwargs):
        self = super().__new__(cls, *args, **kwargs)
        self._mykwarg = mykwarg
        return self

and added several @property methods.

Now if I want to test it (I use pytest), it does not work:

def test_Node(fs):
    fs.create_file('simple.txt')
    n = Node('simple.txt')
    n.stat()

Running the test outputs (at line n.stat()):

E   FileNotFoundError: [Errno 2] No such file or directory: 'simple.txt'

what is not completely unexpected, as, I guess, only PosixPath is patched by pyfakefs, but not my own class, even if it inherits from PosixPath.

But I'd liked to be able to test my class while keeping the features of pyfakefs. Have the methods, fields etc. inherited from PosixPath still patched by pyfakefs as is PosixPath, and only have the properties I did add not patched. Is there any way to do that?


Solution

  • The problem here is that Node is derived from PosixPath at load time, while pathlib is not patched yet, and it will not be patched because patching is done by module name. If you want to have it derived from the patched PosixPath, the class definition has to be reloaded after patching started. As you are using pytest, the best way is probably to write your own fixture that does that:

    import pytest
    from pyfakefs.fake_filesystem_unittest import Patcher
    import node  # assuming Node lives in node.py
    
    @pytest.fixture
    def my_fs():
        with Patcher(modules_to_reload=[node]) as p:
            yield p.fs
    
    def test_Node(my_fs):
        ...
    

    The modules_to_reload argument is there exactly for this kind of problems.

    Disclaimer: I'm a contributor to pyfakefs.