Visitar URL original
Optimize pathlib path construction · Issue #101362 · python/cpython · GitHub
Skip to content

Optimize pathlib path construction #101362

Description

@barneygale

Pathlib is slow. One of the most obvious symptoms is that pathlib.PurePath objects are slow to construct. We should be able to speed construction up without making other parts of pathlib slower.

Two possible approaches:

  1. Optimize the existing machinary of path construction: __new__(), _from_parts(), _parse_parts(), _parse_args().
  2. Perform less work in the constructor: defer parsing, joining and normalization until needed.

Linked PRs

Activity

  1. barneygale commented on Jan 29, 2023

    @barneygale
    ContributorAuthor

    I'd like to land #101363 before I put the first PR up for this issue.

  2. added 5 commits that reference this issue on Feb 4, 2023
  3. zooba commented on Feb 22, 2023

    @zooba
    Member

    Does the PR cope with WindowsPurePath and PosixPurePath and converting between them?

  4. barneygale commented on Feb 22, 2023

    @barneygale
    ContributorAuthor

    Could you clarify? The PRs maintain the behaviour that attempting to instantiate pathlib.PurePath will give you a PureWindowsPath or a PurePosixPath depending on your platform, but pathlib doesn't support converting between Windows and POSIX paths as I understand it.

  5. zooba commented on Feb 24, 2023

    @zooba
    Member

    This behaviour should be preserved:

    Python 3.10.10 (tags/v3.10.10:aad5f6a, Feb  7 2023, 17:20:36) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from pathlib import *
    >>> p = PureWindowsPath("a/b/c")
    >>> p
    PureWindowsPath('a/b/c')
    >>> PurePosixPath(p)
    PurePosixPath('a/b/c')
    >>> PurePath(p)
    PureWindowsPath('a/b/c')
    >>> PosixPath(p)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2800.0_x64__3847v3x7pw1km\lib\pathlib.py", line 962, in __new__
        raise NotImplementedError("cannot instantiate %r on your system"
    NotImplementedError: cannot instantiate 'PosixPath' on your system
    >>> WindowsPath(p)
    WindowsPath('a/b/c')
    >>>
    
  6. barneygale commented on Feb 24, 2023

    @barneygale
    ContributorAuthor

    Right! That will be broken by #101667 as things stand:

    >>> from os import fspath
    >>> from pathlib import *
    >>> p = PureWindowsPath("a/b/c")
    >>> p
    PureWindowsPath('a/b/c')
    >>> fspath(p)
    'a\\b\\c'
    >>> PurePosixPath(fspath(p))
    PurePosixPath('a\\b\\c')
    >>> PurePosixPath(p)
    PurePosixPath('a\\b\\c')

    It doesn't appear to be documented or tested behaviour, and it feels odd to me that PurePosixPath(p) can give a different result to PurePosixPath(fspath(p)). I'll try to find a good way forwards!

  7. barneygale commented on Feb 24, 2023

    @barneygale
    ContributorAuthor

    This feature doesn't really work with drives or roots:

    >>> PurePosixPath(PureWindowsPath('//server/share/dir'))
    PurePosixPath('\\\\server\\share\\/dir')
    >>> PurePosixPath(PureWindowsPath('c:/dir'))
    PurePosixPath('c:\\/dir')
    >>> PurePosixPath(PureWindowsPath('/dir'))
    PurePosixPath('\\/dir')

    As far as I can tell, no one has ever logged a bug about it.

    However, using PurePosixPath(PureWindowsPath(...).as_posix()) works everywhere:

    >>> PurePosixPath(PureWindowsPath('//server/share/dir').as_posix())
    PurePosixPath('//server/share/dir')
    >>> PurePosixPath(PureWindowsPath('c:/dir').as_posix())
    PurePosixPath('c:/dir')
    >>> PurePosixPath(PureWindowsPath('/dir').as_posix())
    PurePosixPath('/dir')

    So I'm tempted to conclude that converting with PurePosixPath(PureWindowsPath(...)) alone is not supported, and that it only happened to work in some limited circumstances. Users can add .as_posix() to signal their intent and make it work reliably. What do you reckon?

  8. zooba commented on Feb 24, 2023

    @zooba
    Member

    I think the direct conversion should either be consistent with fspath(p) or p.parts, but no strong preference which. As you say, neither makes a huge amount of sense, and the workaround (.as_posix()) has been there for a long time.

    Might be worth adding a short note to the docs warning that the constructor can't reliably convert from different pathlib objects, and maybe specify whether it will fspath or .parts them.

    On another perf note, is it possible that parsing the path up front isn't necessary? Obviously it'll save the most time to keep a single string literal around and parse it later, but I don't personally have a good feel for whether that's common or not. (Obviously if it's available pre-parsed then keep it.)

  9. 7 remaining items

  10. added 2 commits that reference this issue on Mar 6, 2023
  11. added a commit that references this issue on Mar 6, 2023
  12. added a commit that references this issue on Mar 10, 2023
  13. barneygale commented on Mar 22, 2023

    @barneygale
    ContributorAuthor

    For anyone following along, I think this ticket can be resolved if/when this PR lands:

  14. added 3 commits that reference this issue on Apr 3, 2023
  15. barneygale commented on Apr 9, 2023

    @barneygale
    ContributorAuthor

    Resolving this issue. It's now much cheaper to construct pathlib.PurePath and Path objects. Some operations like str() and joinpath() are also cheaper.

    Future work:

  16. added a commit that references this issue on Apr 11, 2023
  17. added a commit that references this issue on Apr 18, 2023
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions