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 — pathlib's relative_to should behave like os.path.relpath · Issue #84538 · python/cpython

pathlib's relative_to should behave like os.path.relpath #84538

New issue
Copy link
New issue
Copy link
Closed
Closed
pathlib's relative_to should behave like os.path.relpath#84538
Copy link
Labels
3.11only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-pathlibtype-featureA feature request or enhancementA feature request or enhancement

Description

domragusa
mannequin
opened on Apr 22, 2020
Issue body actions
BPO 40358
Nosy @pitrou, @eryksun, @ammaraskar, @CuriousLearner, @CAM-Gerlach, @barneygale, @domragusa, @bowiechen
PRs
  • bpo-40358: add strict parameter to pathlib.PurePath.relative_to #19807
  • gh-84538: add strict argument to pathlib.PurePath.relative_to #19813
  • Files
  • relative_to.patch
  • 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:

    assignee = None
    closed_at = None
    created_at = <Date 2020-04-22.00:03:03.148>
    labels = ['type-feature', 'library', '3.11']
    title = "pathlib's relative_to should behave like os.path.relpath"
    updated_at = <Date 2022-02-22.23:57:02.772>
    user = 'https://github.com/domragusa'

    bugs.python.org fields:

    activity = <Date 2022-02-22.23:57:02.772>
    actor = 'terry.reedy'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2020-04-22.00:03:03.148>
    creator = 'd.ragusa'
    dependencies = []
    files = ['49095']
    hgrepos = []
    issue_num = 40358
    keywords = ['patch']
    message_count = 11.0
    messages = ['366958', '367037', '367041', '367047', '367490', '367697', '367723', '370254', '393696', '393777', '408249']
    nosy_count = 10.0
    nosy_names = ['pitrou', 'python-dev', 'eryksun', 'ammar2', 'Socob', 'CuriousLearner', 'CAM-Gerlach', 'barneygale', 'd.ragusa', 'bowiechen']
    pr_nums = ['19807', '19813']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue40358'
    versions = ['Python 3.11']

    Activity

    1. domragusa commented on Apr 22, 2020

      @domragusa
      domragusamannequin
      on Apr 22, 2020
      MannequinAuthor
      More actions

      Can we improve pathlib.relative_to(other) so that it handles the case of a path not being a direct child of other, like os.path.relpath?

      For example:
      Path('/some/thing').relative_to('/foo') -> Path('../some/thing')

      At the moment it just raises an exception.

      Reacted by Bogdan Pradatu
    2. domragusa
      added
      3.9 (EOL)end of lifeend of life
      stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
      type-featureA feature request or enhancementA feature request or enhancement
      on Apr 22, 2020
    3. pitrou commented on Apr 22, 2020

      @pitrou
      pitrou
      on Apr 22, 2020
      Member
      More actions

      The current behaviour is by design. I would not mind adding an option to control it, though.

      If you are new to Python development and want to submit a patch or PR, I recommend reading the Developer's Guide:
      https://devguide.python.org/

    4. domragusa commented on Apr 22, 2020

      @domragusa
      domragusamannequin
      on Apr 22, 2020
      MannequinAuthor
      More actions

      Thanks for your answer. Yeah, I'm new, I'm reading the guide, sorry for any
      faux pas :)

      Ok, an option would be great as well, a simple True/False switch? Any
      suggestion for the name?
      I'll get back with a proper patch this time.

      On Wed, Apr 22, 2020 at 8:18 PM Antoine Pitrou <[email protected]>
      wrote:

      Antoine Pitrou <[email protected]> added the comment:

      The current behaviour is by design. I would not mind adding an option to
      control it, though.

      If you are new to Python development and want to submit a patch or PR, I
      recommend reading the Developer's Guide:
      https://devguide.python.org/

      ----------


      Python tracker <[email protected]>
      <https://bugs.python.org/issue40358\>


    5. eryksun commented on Apr 22, 2020

      @eryksun
      eryksun
      on Apr 22, 2020
      Contributor
      More actions

      Note that the implementation of relpath is pure and thus assumes it's working with existing, resolved paths (i.e. "the filesystem is not accessed to confirm the existence or nature of path or start"). For example:

          >>> os.path.relpath('/some/thing', '/symlink')
          '../some/thing'

      If "symlink" targets "/spam/eggs/foo", then the resolved path would be "/spam/eggs/some/thing" instead of "/some/thing". Maybe the relative_to method should default to a strict mode that raises ValueError on ambiguous cases that depend on the "existence or nature" of the paths. I think the current implementation is strict.

    6. domragusa commented on Apr 28, 2020

      @domragusa
      domragusamannequin
      on Apr 28, 2020
      MannequinAuthor
      More actions

      Yeah, you're right, there's no access to the filesystem and the result
      is generated assuming the paths are already resolved.
      strict seems to be an appropriate name for the option, thanks.

      I've looked into the test suite, it helped a lot especially with
      Windows paths, they were more complicated than I though.
      I've duplicated the tests to verify that it still function as before
      and I've added some tests for values that would raise an exception. It
      works.
      I'm not overly fond of the way I check for unrelated paths, but I
      couldn't think of something more elegant.

      Any input is appreciated.

    7. ammaraskar commented on Apr 29, 2020

      @ammaraskar
      ammaraskar
      on Apr 29, 2020
      Member
      More actions

      Thank you for your work on this Domenico. For reviewing the code, would you mind creating a Github pull request for it as described here https://devguide.python.org/pullrequest/

    8. domragusa commented on Apr 30, 2020

      @domragusa
      domragusamannequin
      on Apr 30, 2020
      MannequinAuthor
      More actions

      I may have forgotten to use the proper format for the title of each
      commit, should I delete the pull request and make a new one or can it
      be fixed when (or if) it's pulled?

      On Thu, Apr 30, 2020 at 2:03 AM Roundup Robot <[email protected]> wrote:

      Change by Roundup Robot <[email protected]>:

      ----------
      nosy: +python-dev
      nosy_count: 5.0 -> 6.0
      pull_requests: +19128
      stage: -> patch review
      pull_request: #19807


      Python tracker <[email protected]>
      <https://bugs.python.org/issue40358\>


    9. domragusa commented on May 28, 2020

      @domragusa
      domragusamannequin
      on May 28, 2020
      MannequinAuthor
      More actions

      I've solved the conflicts with #63810 (bpo-23082: Better error message for PurePath.relative_to() from pathlib) that was merged in the mean time and improved the documentation.

      Everything appears to be in order, can you take a look at it?

    10. domragusa
      added
      3.10 (EOL)end of lifeend of life
      and removed
      3.9 (EOL)end of lifeend of life
      on May 28, 2020
    11. terryjreedy commented on May 14, 2021

      @terryjreedy
      terryjreedy
      on May 14, 2021
      Member
      More actions

      On bpo-44078 (closed as duplicate), Mark Hammond made a similar request.

    12. terryjreedy
      added
      3.11only security fixesonly security fixes
      and removed
      3.10 (EOL)end of lifeend of life
      on May 14, 2021
    13. barneygale commented on May 17, 2021

      @barneygale
      barneygalemannequin
      on May 17, 2021
      Mannequin
      More actions

      Also requested in bpo-42234.

    14. CAM-Gerlach commented on Dec 10, 2021

      @CAM-Gerlach
      CAM-Gerlach
      on Dec 10, 2021
      Member
      More actions

      For the record, requested on Discourse as well, with a fairly similar proposal.

    15. ezio-melotti
      transferred this issue fromon Apr 10, 2022
    16. brettcannon
      added
      topic-pathlib
      on Jun 21, 2022
    17. barneygale commented on Jun 26, 2022

      @barneygale
      barneygale
      on Jun 26, 2022
      Contributor
      More actions

      os.path.relpath() always calls abspath(), which is "impure" by pathlib standards.

      If both arguments to relpath() are relative paths then the abspath() calls can probably be removed. It would save a system call, and allow PurePath.relative_to() to call into os.path.relpath() safely:

          def relative_to(self, *other):
              if not other:
                  raise TypeError("need at least one argument")
              other = type(self)(*other)
              if self.is_absolute() != other.is_absolute():
                  raise ValueError("one path is relative and the other is absolute: "
                                   "{!r}, {!r}".format(str(self), str(other)))
              rel = self._flavour.relpath(self, other)
              return type(self)(rel)
      Reacted by C.A.M. Gerlach
    18. barneygale commented on Jul 12, 2022

      @barneygale
      barneygale
      on Jul 12, 2022
      Contributor
      More actions

      An interesting comment in PurePath.relative_to():

              # For the purpose of this method, drive and root are considered
              # separate parts, i.e.:
              #   Path('c:/').relative_to('c:')  gives Path('/')
              #   Path('c:/').relative_to('/')   raise ValueError

      This isn't true for ntpath.relpath():

      >>> import ntpath
      >>> ntpath.relpath('c:\\', 'c:')
      '.'

      Pathlib's behaviour is deliberate but questionable. If we're willing to drop it, then we can call through to os.path.relpath() when users call relative_to(..., strict=False).

      Also, path.is_relative_to(other) would simplify down to other == path or other in path.parents, which is so simple it barely qualifies for a (misleadingly named) method. It might make sense to deprecate it.

    19. pitrou commented on Jul 12, 2022

      @pitrou
      pitrou
      on Jul 12, 2022
      Member
      More actions

      "C:" is the current directory in drive C, so I think pathlib's answer is the correct one here (of course, I wrote it so I may be biaised :-)).

    20. barneygale commented on Jul 12, 2022

      @barneygale
      barneygale
      on Jul 12, 2022
      Contributor
      More actions

      Thanks Antoine! That makes sense, but it still seems a odd to me that naked Windows drive paths are the only place where absolute and relative paths can be mixed! Extending your logic:

      1. Should PureWindowsPath('c:/').relative_to('c:foo') also return '/'?
      2. Should PurePosixPath('/').relative_to('foo') also return '/'?

      Both of these raise ValueError at the moment. Maybe this is a "practicality beats purity" thing?

    21. pitrou commented on Jul 12, 2022

      @pitrou
      pitrou
      on Jul 12, 2022
      Member
      More actions

      I would say it is a practically beats purity thing indeed. I don't remember the details of why I chose to allow it at the time.

      Reacted by Barney Gale and C.A.M. Gerlach
    22. barneygale commented on Jul 15, 2022

      @barneygale
      barneygale
      on Jul 15, 2022
      Contributor
      More actions

      Correction to my earlier post:

      C: is a relative path, and relpath() transforms it to an absolute path (i.e. prepends the working directory) before working out the result. From an actual windows box and C:\Users\me:

      >>> import ntpath
      >>> ntpath.relpath('C:\\', start='C:')
      '..\\..'
      >>> ntpath.relpath('C:\\', start='C:foo')
      '..\\..\\..'

      Here's pathlib for comparison's sake:

      >>> import pathlib
      >>> pathlib.PureWindowsPath('C:/').relative_to('C:')
      PureWindowsPath('/')
      >>> pathlib.PureWindowsPath('C:/').relative_to('C:foo')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        File "/Users/barney.gale/code/cpython/Lib/pathlib.py", line 673, in relative_to
          raise ValueError("{!r} is not in the subpath of {!r}"
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      ValueError: 'C:\\' is not in the subpath of 'C:foo' OR one path is relative and the other is absolute.
    23. miss-islington
      added a commit that references this issue on Oct 28, 2022

      gh-84538: add strict argument to pathlib.PurePath.relative_to (GH-19813)

      e089f23
    24. brettcannon
      closed this as completedon Oct 28, 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

      3.11only security fixesonly security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-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.