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

pathlib should allow converting to absolute paths without resolving symlinks #69200

Closed
mumind mannequin opened this issue Sep 5, 2015 · 8 comments
Closed

pathlib should allow converting to absolute paths without resolving symlinks #69200

mumind mannequin opened this issue Sep 5, 2015 · 8 comments
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@mumind
Copy link
Mannequin

mumind mannequin commented Sep 5, 2015

BPO 25012
Nosy @pitrou, @serhiy-storchaka, @eryksun
Superseder
  • bpo-29688: Add support for Path.absolute()
  • 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 = <Date 2021-03-17.07:10:19.721>
    created_at = <Date 2015-09-05.22:05:48.160>
    labels = ['type-feature', 'library']
    title = 'pathlib should allow converting to absolute paths without resolving symlinks'
    updated_at = <Date 2021-03-17.07:10:19.720>
    user = 'https://bugs.python.org/mumind'

    bugs.python.org fields:

    activity = <Date 2021-03-17.07:10:19.720>
    actor = 'eryksun'
    assignee = 'none'
    closed = True
    closed_date = <Date 2021-03-17.07:10:19.721>
    closer = 'eryksun'
    components = ['Library (Lib)']
    creation = <Date 2015-09-05.22:05:48.160>
    creator = 'mu_mind'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 25012
    keywords = []
    message_count = 8.0
    messages = ['249936', '249941', '249968', '250129', '250139', '250167', '250208', '250209']
    nosy_count = 5.0
    nosy_names = ['pitrou', 'mu_mind', 'serhiy.storchaka', 'eryksun', 'Socob']
    pr_nums = []
    priority = 'normal'
    resolution = 'duplicate'
    stage = 'resolved'
    status = 'closed'
    superseder = '29688'
    type = 'enhancement'
    url = 'https://bugs.python.org/issue25012'
    versions = ['Python 3.6']

    @mumind
    Copy link
    Mannequin Author

    mumind mannequin commented Sep 5, 2015

    There doesn't seem to be any helper in pathlib to expand a relative path to an absolute path *without* resolving symlinks.

    For example, if I want to convert
    pathlib.Path('some/path')
    to
    pathlib.Path('/full/path/to/some/path')
    where some/path is a symlink, my best option seems to be
    pathlib.Path(os.path.abspath(str(pathlib.Path('some/path'))))

    @mumind mumind mannequin added type-bug An unexpected behavior, bug, or error stdlib Python modules in the Lib dir labels Sep 5, 2015
    @serhiy-storchaka
    Copy link
    Member

    pathlib.Path.cwd() / pathlib.Path('some/path')

    @eryksun
    Copy link
    Contributor

    eryksun commented Sep 6, 2015

    There's a public method that's almost what you want:

        >>> print(pathlib.Path.absolute.__doc__)
        Return an absolute version of this path.  This function works
                even if the path doesn't point to anything.
            No normalization is done, i.e. all '.' and '..' will be kept along.
            Use resolve() to get the canonical path to a file.
    

    However, it appears to be only accidentally public. It isn't tested; it isn't mentioned in the docs; and it doesn't do the [expected] path normalization. Currently it's used as a default in resolve() if self._flavour.resolve(self) returns None.

    @pitrou
    Copy link
    Member

    pitrou commented Sep 7, 2015

    Yes, this wasn't meant to be a public method really. I'm still on the fence as to whether we should expose something like this. What is your use case?

    @pitrou pitrou added type-feature A feature request or enhancement and removed type-bug An unexpected behavior, bug, or error labels Sep 7, 2015
    @mumind
    Copy link
    Mannequin Author

    mumind mannequin commented Sep 7, 2015

    The idiom of
    pathlib.Path.cwd() / pathlib.Path('some/path')
    isn't too bad of an approach if it could just be mentioned in the docs. I would intuitively expected something like
    pathlib.Path('some/path').resolve(follow_symlinks=False)

    My use case was that I had an equality check like this failing:
    expected_path = pathlib.Path.cwd() / pathlib.Path('some/path')
    pathlib.Path('some/path') == expected_path
    I suppose I should file that as a separate bug because semantically those paths are equal, but I was trying to work around it like
    pathlib.Path('some/path').resolve() == expected_path
    which in my case still failed because some/path was a symlink.

    Even if that's fixed, I would still expect to run into cases where I wanted to print specifically the relative or absolute path in informational messages and would not want to follow symlinks (e.g., in "Requested path X not found", the user would recognize the absolute path as the one they entered but not necessarily the symlink-resolved version).

    @pitrou
    Copy link
    Member

    pitrou commented Sep 8, 2015

    Le 08/09/2015 01:21, David Barnett a écrit :

    My use case was that I had an equality check like this failing:
    expected_path = pathlib.Path.cwd() / pathlib.Path('some/path')
    pathlib.Path('some/path') == expected_path
    I suppose I should file that as a separate bug because semantically those paths are equal, but I was trying to work around it like
    pathlib.Path('some/path').resolve() == expected_path
    which in my case still failed because some/path was a symlink.

    Semantically, the paths are equal only in that particular system
    configuration, with os.getcwd() pointing to a particular directory. Path
    comparison is done on "pure" path objects (as explained in the
    documentation) and therefore doesn't take into account system specifics.
    This makes comparisons much more predictable.

    Currently the way to implement "absolute" comparison is to call
    .resolve() on both paths. Note you might care about actual file identity
    and call os.path.samefile() instead.

    Even if that's fixed, I would still expect to run into cases where I
    wanted to print specifically the relative or absolute path in
    informational messages and would not want to follow symlinks (e.g., in
    "Requested path X not found", the user would recognize the absolute path
    as the one they entered but not necessarily the symlink-resolved version).

    Yes... and yet that may be misleading, since the "absolute" path
    obtained may not correspond to the actual one, especially if ".."
    fragments are collapsed.

    I'll have to think about this one a bit more.

    @mumind
    Copy link
    Mannequin Author

    mumind mannequin commented Sep 8, 2015

    Right, and to clarify a bit further why I didn't just use A.resolve() == B.resolve() from the beginning, this is in a unit test where the equality check wasn't in my code. I wanted to assert I received a certain call on my mock, like
    mock_open_method.assert_called_once_with(pathlib.Path('foo'))
    so it's much more convenient to be able to create a path object that matches with my target path instead of more complicated matching.

    @mumind
    Copy link
    Mannequin Author

    mumind mannequin commented Sep 8, 2015

    And the symlinks for my paths refer to really cryptic hashes in a virtual filesystem for the tests, so rendering them into the assertion failed errors would really make the failure messages hard to interpret.

    @eryksun eryksun closed this as completed Mar 17, 2021
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants