Skip to content
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

Support for detecting the flavour of pathlib subclasses #100502

Closed
barneygale opened this issue Dec 24, 2022 · 10 comments
Closed

Support for detecting the flavour of pathlib subclasses #100502

barneygale opened this issue Dec 24, 2022 · 10 comments
Labels
topic-pathlib type-feature A feature request or enhancement

Comments

@barneygale
Copy link
Contributor

barneygale commented Dec 24, 2022

Feature or enhancement

Provide a way of checking whether a user subclass of pathlib.PurePath and Path uses POSIX or Windows semantics

The Problem

Now that #68320 is resolved, users can subclass pathlib.PurePath and Path directly:

import pathlib

class MyPath(pathlib.Path):
    pass

path = MyPath('foo')

However, there's no (public) procedure to detect whether an instance of MyPath uses POSIX or Windows semantics.

A non-public way of doing it:

path._flavour is posixpath  # Check whether the path object uses POSIX semantics
path._flavour is ntpath  # Check whether the path uses Windows semantics
path._flavour is os.path  # Check whether the path uses the current OS's semantics

Note that checking isinstance(path, PurePosixPath) (etc) won't work, as user subclasses of PurePath and Path do not have the POSIX- and Windows-specific subclasses in their class hierarchy.

The Proposal

Make the _flavour attribute public; document it. Possible names:

  • flavour (simply remove the underscore)
  • pathmod (used internally in older pathlib versions)
  • module (used in the longstanding thirdparty path package)

Alternatives

We could make the PurePosixPath and PureWindowsPath classes 'protocols', which support isinstance() checks even when the passed object isn't a conventional subclass. But:

  1. The implementation will be more complex
  2. It could open a can of worms about whether PurePosixPath and PureWindowsPath should be proper protocols, and not directly instantiable.

A further alternative would be to add an is_posix() method, which gels pretty nicely with the existing is_*() and as_posix() methods.

Linked PRs

@barneygale barneygale added the type-feature A feature request or enhancement label Dec 24, 2022
barneygale added a commit to barneygale/cpython that referenced this issue Jul 7, 2023
This instance attribute stores the implementation of `os.path` used for
low-level path operations: either `posixpath` or `ntpath`.

The `PurePath` and `Path` initialisers gain a *flavour* keyword-only
argument that sets the flavour. This argument is not available in the
Posix- and Windows-specific subclasses, and as the `PurePath` and `Path`
classes are not directly instantiable, it is available therefore only in
user subclasses of `PurePath and `Path`. Such subclasses may determine
their flavour in `__init__()` and supply the flavour to `super()`.
barneygale added a commit to barneygale/cpython that referenced this issue Jul 7, 2023
This instance attribute stores the implementation of `os.path` used for
low-level path operations: either `posixpath` or `ntpath`.

The `PurePath` and `Path` initialisers gain a *flavour* keyword-only
argument that sets the flavour. This argument is not available in the
Posix- and Windows-specific subclasses, and as the `PurePath` and `Path`
classes are not directly instantiable, it is available therefore only in
user subclasses of `PurePath and `Path`. Such subclasses may determine
their flavour in `__init__()` and supply the flavour to `super()`.
barneygale added a commit to barneygale/cpython that referenced this issue Jul 7, 2023
This instance attribute stores the implementation of `os.path` used for
low-level path operations: either `posixpath` or `ntpath`.

The `PurePath` and `Path` initialisers gain a *flavour* keyword-only
argument. This argument is not available in the Posix- and Windows-specific
subclasses, and as the `PurePath` and `Path` classes are not directly
instantiable, it is available therefore only in user subclasses of
`PurePath` and `Path`. Such subclasses may determine their flavour in
`__init__()` and supply the flavour to `super()`.
@merwok
Copy link
Member

merwok commented Jul 8, 2023

pathmod is not a bad name! It makes it clear that the value is (normally) one of the path modules, and Python being Python it doesn’t prevent someone using another kind of object for custom needs.

flavour is a bit more vague but okay; accessor is also available!

@merwok
Copy link
Member

merwok commented Jul 8, 2023

About is_posix: I don’t think the name is clear enough. Without reading docs, it could be interpreted as a question about the current platform, or the path module, or a check for some posix spec conformity, or even a question about the form of the paths?!
But maybe my worry is unfounded and it would be fine, we have os.name == 'posix' and os.path is posixpath.

@barneygale
Copy link
Contributor Author

Thanks for the feedback! pathmod sounds good to me. It occurs to me that the pathlib documentation already refers to PureWindowsPath, PurePosixPath etc as "flavours", and so re-using that term could be confusing.

Agree also on is_posix()

barneygale added a commit that referenced this issue Jul 19, 2023
This instance attribute stores the implementation of `os.path` used for
low-level path operations: either `posixpath` or `ntpath`.
@barneygale
Copy link
Contributor Author

Implemented in c6c5665 / #106533

@barneygale
Copy link
Contributor Author

barneygale commented Dec 19, 2023

@merwok I'm beginning to have doubts about the solution I implemented. I think the new, internal PurePathBase class ought to support syntax customization beyond a fat "NT or POSIX" switch, and that perhaps the path module should be an internal implementation detail of PurePath, rather than an attribute of PurePathBase. Would you mind if I revert #106533? It's only been available in 3.13 alphas so far, so it's safe to do so.

@barneygale barneygale reopened this Dec 19, 2023
@merwok
Copy link
Member

merwok commented Dec 19, 2023

Would you revert to _flavour or keep the new name we came to and mark it private with _pathmod?

@barneygale
Copy link
Contributor Author

barneygale commented Dec 19, 2023

I think I'd keep the new name and mark it as private with _pathmod

@merwok
Copy link
Member

merwok commented Dec 19, 2023

This is related to the ongoing discussions about preserving final slash and follow_symlinks (and co) as implicit parameters, yes?
You’re thinking that the addition of parameters to track choices for these properties removes or weakens the usefulness of checking that a Path class or subclass uses posix or nt base rules?

Generally I trust you to shepherd the changes needed to support important features.
In this case I would suggest that maybe it’s not required to revert right now, as the discussions haven’t reached their conclusions and it’s not clear how the pathlib design should change to move in a good direction.
The first beta is in May, so pathmod could be hidden, removed or changed between now and then 🙂

If you still think the attribute should hidden now, then go ahead!

barneygale added a commit to barneygale/cpython that referenced this issue Dec 19, 2023
@barneygale
Copy link
Contributor Author

barneygale commented Dec 19, 2023

This is related to the ongoing discussions about preserving final slash and follow_symlinks (and co) as implicit parameters, yes?

It's related to those discussions, but more directly to the work on pathlib ABCs which has been going on at the same time. There's now a private pathlib._abc module, and though I'm pretty satisfied with the I/O aspects of the PathBase class, I'm much less convinced that the pure aspects of the PurePathBase class are correct, and I expect I'll need to iterate on them over the coming months.

You’re thinking that the addition of parameters to track choices for these properties removes or weakens the usefulness of checking that a Path class or subclass uses posix or nt base rules?

Yes that's right.

Thanks for the advice - I'll follow your suggestion to not revert yet. I appreciate your take on this :)

@barneygale
Copy link
Contributor Author

barneygale commented Jan 12, 2024

I've played with two approaches:

  1. Moving pathmod from PurePathBase to PurePath, and making some PurePathBase methods directly raise UnsupportedOperation
  2. Keeping PurePathBase.pathmod and changing its value to a new PathModuleBase ABC.

Both of these have the effect of making PurePathBase methods raise UnsupportedOperation, but the first option is really nasty, as it means PathBase has two sets abstract methods that are largely independent. The second option is uses composition rather than inheritance and works out much nicer. I've put it up as a PR: #113893

Re-resolving this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-pathlib type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

3 participants