GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Support for sharing state between pathlib subclasses · Issue #100479 · python/cpython

Support for sharing state between pathlib subclasses #100479

New issue
Copy link
New issue
Copy link
Closed
Closed
Support for sharing state between pathlib subclasses#100479
Copy link
Labels
topic-pathlibtype-featureA feature request or enhancementA feature request or enhancement

Description

@barneygale
barneygale
opened on Dec 23, 2022
Issue body actions

Feature or enhancement

This enhancement proposes that we allow state to be shared between related instances of subclasses of pathlib.PurePath and pathlib.Path.

Pitch

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

import pathlib

class MyPath(pathlib.Path):
    def my_custom_method(self):
        pass

etc = MyPath('/etc')
etc_hosts = etc / 'hosts'
etc_hosts.my_custom_method()

However, some user implementations of classes - such as TarPath or S3Path - would require underlying tarfile.TarFile or botocore.Resource objects to be shared between path objects (etc and etc_hosts in the example above). Such sharing of resources is presently rather difficult, as there's no single instance method used to derive new path objects.

This feature request proposes that we add a new PurePath.makepath() method, which is called whenever one path object is derived from another, such as in joinpath(), iterdir(), etc. The default implementation of this method looks something like:

def makepath(self, *args):
    return type(self)(*args)

Users may redefine this method in a subclass, in conjunction with a customized initializer:

class SessionPath(pathlib.Path):
    def __init__(self, *args, session_id):
        super().__init__(*args)
        self.session_id = session_id

    def makepath(self, *args):
        return type(self)(*args, session_id=self.session_id)

etc = SessionPath('/etc', session_id=42)
etc_hosts = etc / 'hosts'
print(etc_hosts.session_id)  # 42

I propose the name "makepath" for this method due to its close relationship with the existing "joinpath" method: a.joinpath(b) == a.makepath(a, b).

Performance

edit: this change has been taken care of elsewhere, and so implementing this feature request should no longer have much affect on performance.

This change will affect the performance of some pathlib operations, because it requires us to remove the _from_parsed_parts() constructor, which is an internal optimization used in cases where path parsing and normalization can be skipped (for example, in the parents sequence). I suggest that, within the standard library, pathlib is not a particularly performance-sensitive module -- few folks reach to pathlib for reason of speed. Within pathlib itself, the savings from optimizing these "pure" methods are usually drowned out by the I/O costs of "impure" methods. With the appeal of this feature in mind, I believe the performance cost is justified.

However, if the performance degradation is considered unacceptable, there's a possible alternative: add a normalize keyword argument to the path initializer and to makepath(). This would require some serious internal surgery to make work, and might be difficult to communicate to users, so at this stage it's not my preferred route forward.

Previous discussion

https://discuss.python.org/t/make-pathlib-extensible/3428/47 (and replies)

Linked PRs

  • GH-100479: Add optional blueprint argument to pathlib.PurePath #100481
  • GH-100479: Add pathlib.PurePath.with_segments() #103975
  • GH-100479: Fix pathlib test failure on WASI #104215

Activity

  1. barneygale
    added
    type-featureA feature request or enhancementA feature request or enhancement
    on Dec 23, 2022
  2. barneygale commented on Dec 23, 2022

    @barneygale
    barneygale
    on Dec 23, 2022
    ContributorAuthor
    More actions

    This will be needed to implement zipfile.Path using pathlib. Observe that it already has a _next() method that works exactly like what I'm proposing here:

    cpython/Lib/zipfile/_path.py

    Lines 296 to 297 in a68e585

    def _next(self, at):
    return self.__class__(self.root, at)

  3. AlexWaygood commented on Dec 24, 2022

    @AlexWaygood
    AlexWaygood
    on Dec 24, 2022
    Member
    More actions

    Exactly how big would the performance regression be? Have you tried running some benchmarks?

  4. barneygale commented on Dec 24, 2022

    @barneygale
    barneygale
    on Dec 24, 2022
    ContributorAuthor
    More actions

    Not yet; I'll do this before I mark the PR as 'ready' and share the numbers.

    Reacted by Alex Waygood
  5. AlexWaygood commented on Dec 24, 2022

    @AlexWaygood
    AlexWaygood
    on Dec 24, 2022
    Member
    More actions

    My instinct is to say that it would be a shame to make pathlib performance worse, since it's already got a reputation in some quarters for having surprisingly bad performance in some ways compared to os.path. But it's hard to evaluate without knowing how big the performance regression would be, and in what situations you'd hit the regression :)

    few folks reach to pathlib for reason of speed.

    In my opinion, we should be trying to fix this rather than exacerbating the problem :)

    Reacted by Barney Gale
  6. barneygale commented on Dec 24, 2022

    @barneygale
    barneygale
    on Dec 24, 2022
    ContributorAuthor
    More actions

    Absolutely fair!

    Do you know of particular cases of (or complaints about) pathlib being slow? I'm aware that recursive globbing in pathlib can be slow, but not much else. We're increasingly calling os.path functions, some of which have C implementations, which should improve performance a little.

    I'm of course keen for pathlib to be as fast as possible, but I don't want to prevent the future addition of an AbstractPath class either.

    Reacted by Alex Waygood
  7. AlexWaygood commented on Dec 24, 2022

    @AlexWaygood
    AlexWaygood
    on Dec 24, 2022
    Member
    More actions

    Do you know of particular cases of (or complaints about) pathlib being slow?

    • optimized implementation of pathlib faster-cpython/ideas#194
    • cache significantly slows down black due to pathlib psf/black#1950
    • https://m.youtube.com/watch?v=tFrh9hKMS6Y
    • https://m.youtube.com/watch?v=qiZyDLEJHh0&feature=youtu.be

    I have no idea how many of these complaints, if any, still apply to the current implementation of pathlib, nor how many of these are realistically resolvable :)

    Reacted by Barney Gale
  8. barneygale commented on Dec 24, 2022

    @barneygale
    barneygale
    on Dec 24, 2022
    ContributorAuthor
    More actions

    Mega, thank you. I'll study these carefully and write benchmarks.

    Some initial thoughts:

    • The performance cost of constructing Path objects (vs constructing strings) stands out. This would surely benefit from an optimization pass, though it's unlikely we'll ever approach str construction performance.
    • The change to the parents implementation in GH-100479: Add optional blueprint argument to pathlib.PurePath #100481 may improve performance for some of these - I'll check.
    • A C implementation of pathlib would be wonderful but I suspect quite difficult! C implementations of select os.path functions would also help.
    • Caching stat() results would break user code, but there's a possible alternative: we could introduce something like a status() method that returns a new object with exists, is_dir, etc, attributes. Users could call path.status() once and check its attributes, rather than calling path.is_dir(), path.is_symlink(), etc, each of which would trigger their own stat() call.
    Reacted by Alex Waygood
  9. AlexWaygood
    added
    topic-pathlib
    on Dec 24, 2022
  10. barneygale
    added a commit that references this issue on Jan 5, 2023

    Merge branch 'main' into pythongh-100479-add-makepath

    4759d01
  11. barneygale
    added a commit that references this issue on Apr 3, 2023

    Merge branch 'main' into pythongh-100479-add-makepath

    ef6f4c3
  12. barneygale commented on Apr 5, 2023

    @barneygale
    barneygale
    on Apr 5, 2023
    ContributorAuthor
    More actions

    Hey @AlexWaygood - I've addressed the performance aspects of this elsewhere (#101664, #101665, #101667, #102789), so addressing this feature request is pretty much performance-neutral. Would you be up for reviewing #100481? Thank you!

    Reacted by Alex Waygood
  13. AlexWaygood commented on Apr 5, 2023

    @AlexWaygood
    AlexWaygood
    on Apr 5, 2023
    Member
    More actions

    I'll try to take a look soon!

    Reacted by Barney Gale
  14. barneygale
    added 3 commits that reference this issue on Apr 9, 2023

    Merge branch 'main' into pythongh-100479-add-makepath

    dcfe70a

    Merge branch 'main' into pythongh-100479-add-makepath

    e75dedc

    Merge branch 'main' into pythongh-100479-add-makepath

    5a6bd3f
  15. barneygale
    added 4 commits that reference this issue on May 2, 2023

    Merge branch 'main' into pythongh-100479-add-makepath-redux

    51fe663

    Merge branch 'main' into pythongh-100479-add-makepath

    1e10188

    Merge branch 'main' into pythongh-100479-add-makepath-redux

    39297cf

    GH-100479: Add `pathlib.PurePath.with_segments()` (GH-103975)

    d00d942
  16. barneygale commented on May 5, 2023

    @barneygale
    barneygale
    on May 5, 2023
    ContributorAuthor
    More actions

    Implemented in 3.12: #103975 / d00d942

    Reacted by Alex Waygood
  17. barneygale
    closed this as completedon May 5, 2023
  18. barneygale
    added a commit that references this issue on May 5, 2023

    pythonGH-100479: Fix pathlib test failure on WASI

    3c74650
  19. carljm
    added a commit that references this issue on May 5, 2023

    Merge branch 'main' into inlinecomp2

    baacf5f
  20. AlexWaygood
    added a commit that references this issue on May 7, 2023

    GH-100479: Fix pathlib test failure on WASI (#104215)

    60f5884
  21. jbower-fb
    added 2 commits that reference this issue on May 8, 2023

    pythonGH-100479: Add `pathlib.PurePath.with_segments()` (pythonGH-103975

    0b62e96

    pythonGH-100479: Fix pathlib test failure on WASI (python#104215)

    f06a11c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic-pathlibtype-featureA feature request or enhancementA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.