Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pathlib.Path.relative_to vs os.path.relpath

I would like to find the relative path between two absolute paths. I have existing code that is generally using pathlib.Path for interacting with the filesystem, but I've run into a problem that seems easy to solve with os.path.relpath but (so far) intractable with pathlib.Path.

I have:

  • (A), An absolute path to a directory, /home/project/cluster-scope/base/namespaces/acm
  • (B), A relative path from (A) to another directory, ../../../components/monitoring-rbac
  • (C), An absolute path to a second directory, /home/project/cluster-scope/base/core/namespaces/acm

I want to compute a new relative path to (B) from (C). This works:

>>> import os
>>> path_A = '/home/project/cluster-scope/base/namespaces/acm'
>>> path_B = '../../../components/monitoring-rbac'
>>> path_C = '/home/project/cluster-scope/base/core/namespaces/acm'
>>> path_B_abs = os.path.abspath(os.path.join(path_A, path_B))
>>> os.path.relpath(path_B_abs, path_C)
'../../../../components/monitoring-rbac'

But this does not:

>>> from pathlib import Path
>>> path_A = Path('/home/project/cluster-scope/base/namespaces/acm')
>>> path_B = Path('../../../components/monitoring-rbac')
>>> path_C = Path('/home/project/cluster-scope/base/core/namespaces/acm')
>>> path_B_abs = (path_A / path_B).resolve()
>>> path_B_abs.relative_to(path_C)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.9/pathlib.py", line 928, in relative_to
    raise ValueError("{!r} is not in the subpath of {!r}"
ValueError: '/home/project/cluster-scope/components/monitoring-rbac' is not in the subpath of '/home/project/cluster-scope/base/core/namespaces/acm' OR one path is relative and the other is absolute.

The message in that ValueError exception seems inaccurate, or at least misleading: the two paths obviously share a common parent. Is there any way to compute the new relative path using the pathlib.Path? I realize I can just use os.path.relpath and be done with it, but I'm curious if I'm misunderstanding the use of pathlib's relative_to method.

like image 923
larsks Avatar asked May 08 '21 22:05

larsks


People also ask

Which is better os or Pathlib?

In this article, I have introduced another Python built-in library, the Pathlib. It is considered to be more advanced, convenient and provides more stunning features than the OS library. Of course, we still need to know how to use the OS library as it is one of the most powerful and basic libraries in Python.

Why is Pathlib better than os path?

Pathlib allows you to easily iterate over that directory's content and also get files and folders that match a specific pattern. Remember the glob module that you used to import along with the os module to get paths that match a pattern?

Does Pathlib replace os path?

The pathlib module replaces many of these filesystem-related os utilities with methods on the Path object. Notice that the pathlib code puts the path first because of method chaining!

What is Pathlib path?

The pathlib is a Python module which provides an object API for working with files and directories. The pathlib is a standard module. Path is the core object to work with files.


Video Answer


1 Answers

Apparently this is not possible. According to an issue:

I agree it's worth improving the error message (and probably the docs too).

It's never made clear that relative_to only looks deeper (won't ever generate leading ".." parts) - the closest hint in the docs is that os.path.relpath is different (and that isn't even in the relative_to() section).

In the current version the docstring says

"""Return the relative path to another path identified by the passed
arguments.  If the operation is not possible (because this is not
a subpath of the other path), raise ValueError.
"""
like image 111
Reti43 Avatar answered Oct 17 '22 02:10

Reti43