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 — `os.path.relpath()` needlessly calls `abspath()` when given two paths with matching anchors · Issue #99199 · python/cpython

os.path.relpath() needlessly calls abspath() when given two paths with matching anchors #99199

New issue
Copy link
New issue
Copy link
Closed
Closed
os.path.relpath() needlessly calls abspath() when given two paths with matching anchors#99199
Copy link
Labels
type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@barneygale
barneygale
opened on Nov 7, 2022
Issue body actions

relpath() unconditionally calls abspath() to make both its arguments absolute before comparing them. This is necessary if the supplied arguments have different anchors, but it is not necessary when the paths' anchors match. We can save a call to getcwd() / _getfinalpathname() by skipping the abspath() call in this case. This should improve performance a little.

For example, neither of the following should require a call to abspath() internally:

relpath('foo/bar', 'baz/ding')
relpath('/etc/hosts', '/usr/local/bin')

Activity

  1. barneygale
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Nov 7, 2022
  2. eryksun commented on Nov 7, 2022

    @eryksun
    eryksun
    on Nov 7, 2022
    Contributor
    More actions

    On Windows, abspath() also normalizes a path, such as stripping any trailing spaces and dots from the final component. For example:

    >>> ntpath.relpath('spam/eggs. . .', 'spam/eggs/foo')
    '..'

    If we want to retain the ".." result here, then trailing dots and spaces will have to be stripped from the final component of each path. Otherwise the result will be "..\..\eggs. . .". There are also cases with DOS device names that will change if abspath() isn't called. For example, "foo/bar/nul" resolves to "\\.\nul".

  3. barneygale commented on Nov 9, 2022

    @barneygale
    barneygale
    on Nov 9, 2022
    ContributorAuthor
    More actions

    Funnily enough normpath() doesn't apply that normalisation. The support for Windows normalisation rules in Python seems pretty patchy IMO. There's no provision for it in pathlib, for example.

  4. eryksun commented on Nov 9, 2022

    @eryksun
    eryksun
    on Nov 9, 2022
    Contributor
    More actions

    Funnily enough normpath() doesn't apply that normalisation. The support for Windows normalisation rules in Python seems pretty patchy IMO. There's no provision for it in pathlib, for example.

    I'd prefer for ntpath.normpath() to strip dots and spaces from the final component, except for a ".." name. This would also improve ntpath.abspath() on POSIX1.

    Normalizing DOS device names is problematic because it depends on the Windows version. There's still consistent behavior for bare device names, such as "con" -> "\\.\con", but not "./con"2 or "con.txt".

    Footnotes

    1. The fallback on POSIX also needs better support for drives, and to use "C:" as the working drive. It should get drive, path = splitdrive(path), and then resolve the absolute path as join(drive or 'C:', cwd, path). ↩

    2. ntpath.abspath() is implemented as _getfullpathname(normpath(path)). normpath() aggressively normalizes "./con" as "con", so abspath('./con') returns "\\.\con" even if the current Windows version doesn't reserve "./con". In general, removing a leading "." component is wrong on Windows. For example, "./C:spam" (a file named "C" with a data stream named "spam") differs from the drive-relative path "C:spam". ↩

  5. barneygale commented on Nov 12, 2022

    @barneygale
    barneygale
    on Nov 12, 2022
    ContributorAuthor
    More actions

    Ack, this doesn't work due to differences in collapsing leading ../ segments:

    ======================================================================
    ERROR: test_relpath (test.test_ntpath.TestNtpath.test_relpath)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/Users/barney.gale/code/cpython/Lib/test/test_ntpath.py", line 689, in test_relpath
        tester('ntpath.relpath("a", "../b")', '..\\'+currentdir+'\\a')
      File "/Users/barney.gale/code/cpython/Lib/test/test_ntpath.py", line 57, in tester
        raise TestFailed("%s should return: %s but returned: %s" \
    test.support.TestFailed: ntpath.relpath("a", "../b") should return: ..\@test_90826_tmpæ\a but returned: ..\..\a
    
    ======================================================================
    FAIL: test_relpath (test.test_posixpath.PosixPathTest.test_relpath)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/Users/barney.gale/code/cpython/Lib/test/test_posixpath.py", line 610, in test_relpath
        self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a")
    AssertionError: '../../a' != '../bar/a'
    - ../../a
    + ../bar/a
    
  6. barneygale commented on Nov 12, 2022

    @barneygale
    barneygale
    on Nov 12, 2022
    ContributorAuthor
    More actions

    Closing this issue as the handling of ../ segments in os.path and pathlib can't be reconciled in this case.

  7. barneygale
    closed this as completedon Nov 12, 2022
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

    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — 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.