New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Direct sub-classing of pathlib.Path #68320
Comments
Hello. I have noticed a problem with the following code. from pathlib import Path
class PPath(Path):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
test = PPath("dir", "test.txt") This gives the following error message.
Traceback (most recent call last):
File "/Users/projetmbc/test.py", line 14, in <module>
test = PPath("dir", "test.txt")
File "/anaconda/lib/python3.4/pathlib.py", line 907, in __new__
self = cls._from_parts(args, init=False)
File "/anaconda/lib/python3.4/pathlib.py", line 589, in _from_parts
drv, root, parts = self._parse_args(args)
File "/anaconda/lib/python3.4/pathlib.py", line 582, in _parse_args
return cls._flavour.parse_parts(parts)
AttributeError: type object 'PPath' has no attribute '_flavour' This breaks the sub-classing from Python point of view. There is an ugly hack to sub-class Path but it's a bit unpythonic. |
One issue with your code - what would you expect str(test) to produce? "dir/test.txt" or "dir\test.txt"? That's the point of the "flavour" - is it a Windows path or a Unix path? Agreed that an easier method of creating Path subclasses that handle this type of thing would be useful, but any solution needs to make sure that developers don't overlook the Windows vs Unix implications. Can you give an actual use case (as opposed to the toy example)? |
The Path classes were not designed to be subclassable by the user. |
Hello. I will give a real example in 5 hours after my job. I will try tomorrow a *Christophe BAL* 2015-05-06 13:05 GMT+02:00 Antoine Pitrou <report@bugs.python.org>:
|
Here are for example two extra methods that I have implemented. def __sub__(cls, path):
"""
This magic method allows to use ``onepath - anotherpath`` instead of the
long
version ``onepath.relative_to(anotherpath)`` given by ``pathlib.Path``.
"""
return cls.relative_to(path)
def _ppath_common_with(cls, paths):
"""
This method returns the path of the smaller common "folder" of the current
path
and at least one paths. python:: path = os_use.PPath("/Users/projects/source/doc")
path_1 = os_use.PPath("/Users/projects/README")
path_2 = os_use.PPath("/Users/projects/source/misTool/os_use.py")
print(path.common_with((path_1, path_2)))
"""
if not isinstance(paths, (list, tuple)):
paths = [paths]
commonparts = list(cls.parts)
for onepath in paths:
i = 0
for common, actual in zip(commonparts, onepath.parts):
if common == actual:
i += 1
else:
break
commonparts = commonparts[:i]
if not commonparts:
break
commonpath = pathlib.Path("")
for part in commonparts:
commonpath /= part
return commonpath *Christophe BAL* 2015-05-06 14:13 GMT+02:00 Christophe BAL <report@bugs.python.org>:
|
For that type of function, I'd suggest you use a standalone function rather than subclassing and methods or operator overloading. You don't gain enough to be worth the complexity of having to subclass path objects. And duck typing means that your function works for any subclass of (Pure)Path without change. |
I don't agree with you. I prefer to add new functionalities to the paths I Python is highly OOP, so you can't say *"don't use subclassing in your Another example is the use of *onepath - anotherpath* instead of *Christophe BAL* 2015-05-06 20:21 GMT+02:00 Paul Moore <report@bugs.python.org>:
|
I have no problem with that - it's a style choice certainly. As I said, I'd like to see simpler subclassing of pathlib objects. I just think it'll be quite hard to do (given the complexities of classes for Windows/Unix as well as pure and concrete paths). So if it's just about examples like this, I personally would take the easier route and just go with standalone functions. If someone else felt strongly enough to design and implement a subclassing solution, that's fine though. |
Are you the author of path lib ? *Christophe BAL* 2015-05-06 21:01 GMT+02:00 Paul Moore <report@bugs.python.org>:
|
Nope, that's Antoine. |
OK. What is the good way to propose a patch ? *Christophe BAL* 2015-05-06 21:09 GMT+02:00 Paul Moore <report@bugs.python.org>:
|
If you have a patch, attach it here, and it will get reviewed. |
If I were designing pathlib from scratch, I would not have a separate Path class. I would instead do something like this: In pathlib.py: if os.name == 'nt':
Path = WindowsPath
else:
Path = PosixPath Alternatively, Path() could be a factory function that picks one of those classes at runtime. Of course, that still leaves the issue of where to put the method implementations which currently live in Path. We could change the name of Path to _Path and use the code above to continue providing a Path alias, but that might be too confusing. Another possibility is to pull those methods out into top-level functions and then alias them into methods in WindowsPath and PosixPath (perhaps using a decorator-like-thing to pass the flavor, instead of attaching it to the class). The main thing, though, is that Path should not depend on its subclasses. That really strikes me as poor design, since it produces issues like this one. |
Using a set of paths with special properties and formats in a project, thought "the cleanest oop way to do this is try out python's oop paths in pathlib". Subclassed Path to implement my extra (non platfor specific) properties and fell at the first hurdle because of this issue... for me pathlib does not provide oop paths if i can't subclass Path, for whatever reason. reverted to treating paths as strings and writing functions to handle my special path properties and formats. i was also surprised when i found another bug report on this issue that said it was closed for 3.7, great i thought this has been solved, but no, the other report was closed because it was about the same issue as this ancient report. |
@elguavas the problem is, no-one has proposed a patch. There's not likely to be much movement on this until someone provides one. |
For the moment, you can take a look at this little script that acheives Le 08/11/2017 à 09:55, Paul Moore a écrit :
|
Mistyping : /search for class PPath/ with two P. Le 08/11/2017 à 13:59, Christophe BAL a écrit :
|
@paul.moore is the original contributor mia? i seem to remember pathlib as once being marked 'provisional', i think it should have stayed that way until this problem was resolved. easy to say i know ;) when i don't have a patch. @projetmbc yes i found various work-arounds on the web and decided to not use any of them. really i feel this should be fixed as it's a jarring inconsistency with naturally expected behaviour for a class in python. so i added my report to this as a topic bump because i don't think this should be forgotten about and in case anyone might come up with an idea how to fix it. |
Look at the architecture of Rio in Ruby (also ported to Squeak/Smalltalk) Leave Path to handle path stuff, and have another class to handle Platform stuff. |
Hi all, I made a pull request proposing a fix for this issue. There is still quite a lot to be done:
I will try to fix those by the end of the week. The patch mainly consists of two things:
Ideally I would like _PurePath to become a public class, but I could not come up with a proper name. Any feedback is more than welcome =] |
Hello. What about AbstractPath instead of _PurePath ? Le 28/03/2018 à 02:30, qb-cea a écrit :
|
I will use this, thanks. |
I'm taking another look at making List or preparatory bugfixes and tidy-ups: https://docs.google.com/spreadsheets/d/1TicFDMudKKA6CZcrscg1Xq9kt5Q8To8y0hADGw9u11I/edit#gid=0 |
Hi, Thanks for reviving this! Feel free to reuse any code I wrote in my PR (or the whole PR itself), I do not think I will ever get around to finishing this work myself. |
Progress report: I've been working on tidying up the pathlib internals over the 3.9 and 3.10 releases. We're now in a position where:
The internal abstractions are now much tighter, which allows us to begin refactoring them with confidence! The next step is to remove accessors, in bpo-43012. After that I'll finally be in a position to start working on this bug! |
I agree this would be nice. For now, I'm doing this as a hack: class Path(type(pathlib.Path())):
... |
If/when python/issues-test-cpython#31691 lands, I think this bug can be resolved: the original repro case will no longer raise AttributeError, and subclasses will be able to customize behaviour without needing to define further "flavour" or "accessor" subclasses. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: