Make FakePathlibModule.Path compare equal to pathlib.Path #478
Description
Activity
Thanks for the report! I see your problem, and I think there is an easy fix for this (overwriting
__eq__), as long as the comparison is this way around, e.g. comparing the fake path against a real path. Would that be sufficient for you?Reacted by Rayyan335Hmm, I think that would probably be sufficient, yes. I'm not sure if it's a good idea to have an asymmetrical
__eq__though. Might cause some confusing errors if someone ever puts the fake path on the wrong side of the comparison. Wouldn't it be better to go all the way and monkeypatchpathlib.Path.__eq__?Reacted by Rayyan335Well, the question is where to do this. The actual problem is that the
pytest.parametrizedecorator is read before any patching occurs - this is one of the instances that are mentioned in the documentation, where patching won't work. I agree that overwriting__eq__is not the best way to handle this. The corrrect way would be to ensure that thepathlibused in the parameter is patched - I will think about this...For now, I've worked around the problem by adding this monkey patch to my
conftest.py:# monkeypatch Path.__eq__ so that pyfakefs FakePaths compare equal to real pathlib.Paths from pathlib import Path from pyfakefs.fake_pathlib import FakePath # Path somehow gets monkeypatched during testing, so in order to have access # to the original class we'll simply create an instance of it PATH = object.__new__(Path) def path_eq(self, other): Path = type(PATH) if isinstance(other, (Path, FakePath)): return str(self) == str(other) return super(Path, self).__eq__(other) Path.__eq__ = path_eq
Reacted by John T. Wodder IIYes, this is a valid solution, at least for your case. I have been thinking about adding the same monkeypatching to the pytest plugin, but I'm somewhat reluctant to do this, as generally there could be other non-patched fs calls in a
parametrizedecorator. I will have another look some time later.Getting back to this, I now think that the correct way to resolve this would be to reload the sut module during the test (for example using
modules_to_reloadin the test setup), as this is the only way that ensures that the code that is read at load time is correctly patched -- see the documentation for how to do this withpytest.
Actually, the fixture in the documentation is too complicated, it could look like this:import pytest from pyfakefs.fake_filesystem_unittest import Patcher import sut @pytest.fixture def fs_reload_sut(): with Patcher(modules_to_reload=[sut]) as p: yield p.fs
@jmcgeheeiv - instead of closing the issue, I would like to to convert this (and other issues that may be helpful) into a Q/A discussion issue. If you agree, could you enable discussions in the pyfakefs configuration?
Great idea, @mrbean-bremen. Done.
Reacted by mrbean-bremen- locked and limited conversation to collaborators
on May 23, 2021
Sometimes it happens that a test case compares a fake path to a real path - usually when you've created a
pathlib.Pathinpytest.mark.parametrize, like so:This fails with
AssertionError: assert WindowsPath('.') == WindowsPath('.').This could of course be avoided by passing in a string and converting it to a path inside the test, but in reality there isn't always such a convenient workaround. Here's a more realistic example, where an object with loads of attributes - some of which are Paths - is loaded from disk and compared to the expected result:
As I'm sure you can see, having to convert all of those attributes to Paths inside the test is rather annoying. For this reason it would be very convenient if fake Paths would compare equal to real Paths.