You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Unclear how to support subclasses of pathlib.Path #1086
They don't work out-of-the-box and I'm uncertain how to get them to work at all without using lazy imports everywhere or defining the class itself within a function.
Can you elaborate a bit what you are trying to do and what you are expecting?
I guess that this is just not supported out of the box, given that pyfakefs relies on module and function names, but maybe we can add something to support some scenarios.
It appears to be broken only sometimes, in the following example you can see that the touch method works properly but write_text causes infinite recursion:
Hm, that's odd. Under Windows, with Python 3.8 both tests fail, with 3.9 the second (but with no recursion), with 3.10 the first and with 3.11-3.13 none fails.
I cannot reproduce this locally with Windows 10, Python 3.12.7, pytest 8.3.3 and pyfakefs 3.7.1 (though as I wrote, I got failures with Python < 3.11). There is obviously a problem with the older Python versions, but I have no idea why it behaves differently for 3.12. You are using the latest pyfakefs version, right?
Yes I am using the latest version. Interesting! Indeed I cannot reproduce when I bump from Python 3.12.6 to 3.12.7. This doesn't exactly fix my situation however because we must support Python 3.9+ for now.
Ok, so the problem appears with 3.12.6, but not with 3.12.7? That's strange... anyway, I will try to understand the problem at least with the older Python versions, though this may take a while.
I think this is the only pathlib change that landed in that timeframe: python/cpython#125156
That code runs if you pass a PurePath object as an initialiser argument to PurePath. If the parsers don't match, we now call as_posix() to stringify the path (rather than extending with its _raw_paths)
also might have been the problem - it will not work with the fake filesystem. I had to overwrite a similar check in another place, but this is all a bit fragile.
Please forgive me, I was actually totally incorrect regarding my test of a newer Python. I installed the Python to a particular path so was invoking path\to\python.exe -m pytest. It turns out that also works on 3.12.6 and on both versions running the pytest script directly from an activated virtual environment fails. Here is a more complete picture of tests I just ran:
Something odd and temporary happened in Python 3.10 with respect to this library. Since 3.11 everything works but only if you invoke the Python executable (which we couldn't do as it's difficult to change internal tooling for everyone).
Yeah, that is very odd. I will see if I can understand this, but probably not before the next weekend (labouring with some dental issue at the moment that makes thinking straight a bit hard...)
Ok, I had another look at this, and now (with a clearer mind) I see that this is related to the problem of globally defined variables.
The problem is that your own derived version of path is not patched, because _pathBase is set before patching happens, and will not be patched afterwards except if the module is reloaded. Your Path class will derive from that version, not from the patched one. The behavior also depends on the implementation of pathlib in the the different versions, though I can't completely explain every result it at the moment.
If you would rewrite your tests to only import the tested class inside the test, it should work, e.g.:
There is also the possibility to reload the module, but that is also not very convenient, because you cannot use names imported from the (unpatched module), as they would remain in the old state, e.g. something like:
Note that the problem with Python > 3.10 has been fixed in pyfakefs 3.7.3, though the problem remains in Python < 3.10.
As mentioned in the troubleshooting section, the underlying problem with paths created outside of tests does no longer exist (at least in this context) in Python > 3.10, because the Path object no longer holds a reference to the original filesystem accessor.
Converting this into a discussion issue for reference - where is nothing to be done here, as far as I can see.
Activity
mrbean-bremen commentedon Nov 3, 2024
Can you elaborate a bit what you are trying to do and what you are expecting?
I guess that this is just not supported out of the box, given that pyfakefs relies on module and function names, but maybe we can add something to support some scenarios.
ofek commentedon Nov 3, 2024
It appears to be broken only sometimes, in the following example you can see that the
touchmethod works properly butwrite_textcauses infinite recursion:mrbean-bremen commentedon Nov 3, 2024
Which os and Python version are you using? With Python 3.13 under Windows I could not reproduce this.
ofek commentedon Nov 3, 2024
Windows 11
mrbean-bremen commentedon Nov 3, 2024
Hm, that's odd. Under Windows, with Python 3.8 both tests fail, with 3.9 the second (but with no recursion), with 3.10 the first and with 3.11-3.13 none fails.
mrbean-bremen commentedon Nov 3, 2024
I cannot reproduce this locally with Windows 10, Python 3.12.7, pytest 8.3.3 and pyfakefs 3.7.1 (though as I wrote, I got failures with Python < 3.11). There is obviously a problem with the older Python versions, but I have no idea why it behaves differently for 3.12. You are using the latest pyfakefs version, right?
ofek commentedon Nov 3, 2024
Yes I am using the latest version. Interesting! Indeed I cannot reproduce when I bump from Python 3.12.6 to 3.12.7. This doesn't exactly fix my situation however because we must support Python 3.9+ for now.
ofek commentedon Nov 3, 2024
cc @barneygale the
pathlibexpert for any insight/hunch you may have about this 😄mrbean-bremen commentedon Nov 3, 2024
Ok, so the problem appears with 3.12.6, but not with 3.12.7? That's strange... anyway, I will try to understand the problem at least with the older Python versions, though this may take a while.
barneygale commentedon Nov 3, 2024
I think this is the only pathlib change that landed in that timeframe: python/cpython#125156
That code runs if you pass a
PurePathobject as an initialiser argument toPurePath. If theparsers don't match, we now callas_posix()to stringify the path (rather than extending with its_raw_paths)mrbean-bremen commentedon Nov 3, 2024
@barneygale - thanks, indeed the check
also might have been the problem - it will not work with the fake filesystem. I had to overwrite a similar check in another place, but this is all a bit fragile.
barneygale commentedon Nov 3, 2024
Let me know if there's an alternative formulation that would work better for you!
ofek commentedon Nov 3, 2024
Please forgive me, I was actually totally incorrect regarding my test of a newer Python. I installed the Python to a particular path so was invoking
path\to\python.exe -m pytest. It turns out that also works on 3.12.6 and on both versions running thepytestscript directly from an activated virtual environment fails. Here is a more complete picture of tests I just ran:3.8.20touchpython -m pytestpytestwrite_textpython -m pytestpytest3.9.20touchpython -m pytestpytestwrite_textpython -m pytestpytest3.10.15touchpython -m pytestpytestwrite_textpython -m pytestpytest3.11.10touchpython -m pytestpytestwrite_textpython -m pytestpytest3.12.7touchpython -m pytestpytestwrite_textpython -m pytestpytest3.13.0touchpython -m pytestpytestwrite_textpython -m pytestpytestofek commentedon Nov 4, 2024
Something odd and temporary happened in Python 3.10 with respect to this library. Since 3.11 everything works but only if you invoke the Python executable (which we couldn't do as it's difficult to change internal tooling for everyone).
mrbean-bremen commentedon Nov 4, 2024
Yeah, that is very odd. I will see if I can understand this, but probably not before the next weekend (labouring with some dental issue at the moment that makes thinking straight a bit hard...)
ofek commentedon Nov 4, 2024
Thanks, I hope you feel better!
mrbean-bremen commentedon Nov 19, 2024
Ok, I had another look at this, and now (with a clearer mind) I see that this is related to the problem of globally defined variables.
The problem is that your own derived version of path is not patched, because
_pathBaseis set before patching happens, and will not be patched afterwards except if the module is reloaded. YourPathclass will derive from that version, not from the patched one. The behavior also depends on the implementation ofpathlibin the the different versions, though I can't completely explain every result it at the moment.If you would rewrite your tests to only import the tested class inside the test, it should work, e.g.:
This is not nice, of course, and quite fragile.
There is also the possibility to reload the module, but that is also not very convenient, because you cannot use names imported from the (unpatched module), as they would remain in the old state, e.g. something like:
I don't think that I will have a generic solution for this problem, as it is an inherent problem of patching in combination with global variables.
mrbean-bremen commentedon Mar 16, 2025
Note that the problem with Python > 3.10 has been fixed in pyfakefs 3.7.3, though the problem remains in Python < 3.10.
As mentioned in the troubleshooting section, the underlying problem with paths created outside of tests does no longer exist (at least in this context) in Python > 3.10, because the
Pathobject no longer holds a reference to the original filesystem accessor.Converting this into a discussion issue for reference - where is nothing to be done here, as far as I can see.