177

Making a path object with pathlib module like:

p = pathlib.Path('file.txt')

The p object will point to some file in the filesystem, since I can do for example p.read_text().

How can I get the absolute path of the p object in a string?

Appears that I can use for example os.path.abspath(p) to get the absolute path, but it awkward to use an os.path method, since I assume that pathlib should be a replacement for os.path.

Lan Quil
  • 13
  • 8
EquipDev
  • 5,573
  • 10
  • 37
  • 63
  • does `'file.txt'` exist as a relative path in comparison to your .py file? If yes, then all you need to do is get "current path" and then concatenate it in front of the `'file.txt`' – TehTris Feb 28 '17 at 15:47
  • 2
    @TehTris: I would assume that it is possible to get the absolute path of `p` based on only `p`, since I can open a file based on `p`, so the location must be fixed in the file system already. – EquipDev Feb 28 '17 at 15:48

4 Answers4

292

Use resolve()

Simply use Path.resolve() like this:

p = p.resolve()

This makes your path absolute and replaces all relative parts with absolute parts, and all symbolic links with physical paths. On case-insensitive file systems, it will also canonicalize the case (file.TXT becomes file.txt).

Avoid absolute() before Python 3.11

The alternative method absolute() was not documented or tested before Python 3.11 (See the discussion in the bug report created by @Jim Fasarakis Hilliard).

Fixes were merged in January 2022.

The difference

The difference between resolve and absolute is that absolute() does not replace the symbolically linked (symlink) parts of the path, and it never raises FileNotFoundError. It does not modify the case either.

If you want to avoid resolve() (e.g. you want to retain symlinks, casing, or relative parts) then use this instead on Python <3.11:

p = Path.cwd() / "file.txt"

This works even if the path you are supplying is absolute -- in that case the cwd (current working directory) is ignored.

Beware non-existing file on Windows

If the file does not exist, in Python 3.6 to 3.9 on Windows, resolve() does not prepend the current working directory. See issue 38671, fixed in Python 3.10.

Beware FileNotFoundError

On Python versions predating v3.6, resolve() does raise a FileNotFoundError if the path is not present on disk.

So if there's any risk to that, either check beforehand with p.exists() or try/catch the error.

# check beforehand
if p.exists():
    p = p.resolve()

# or except afterward
try:
    p = p.resolve()
except FileNotFoundError:
    # deal with the missing file here
    pass

If you're dealing with a path that's not on disk, to begin with, and you're not on Python 3.6+, it's best to revert to os.path.abspath(str(p)).

From 3.6 on, resolve() only raises FileNotFoundError if you use the strict argument.

# might raise FileNotFoundError
p = p.resolve(strict=True)

But beware, using strict makes your code incompatible with Python versions predating 3.6 since those don't accept the strict argument.

florisla
  • 12,668
  • 6
  • 40
  • 47
  • I still have problem with back porting -- `openpyxl`'s `wb.save_workbook()`and `open(str, 'w')` in Python 3.5.5 (in Travis CI). So, yes, this, "On Python versions predating v3.6, resolve() does raise a FileNotFoundError if the path is not present on disk." is not True. – Polv Jul 16 '18 at 08:11
  • @Polv Take a look at the official docs for 3.5: https://docs.python.org/3.5/library/pathlib.html#pathlib.Path.resolve It clearly states 'If the path doesn’t exist, `FileNotFoundError` is raised.' – florisla Jul 18 '18 at 06:20
  • Sorry I misread, but how would I `write to a new file` with absolute path... before 3.6 – Polv Jul 18 '18 at 06:56
  • Just... write to the file first, and afterwards, call `resolve()` to get its canonical path? Else, use `os.path.abspath(str(pathlib_path_object))`. – florisla Jul 18 '18 at 07:01
  • 1
    On Windows (perhaps on Linux too?), absolute() returns path using any symlinks, resolve() returns a path with symlinks resolved (gone). – BSalita Dec 22 '19 at 12:08
  • 2
    Based on the latest PR that was merged (https://github.com/python/cpython/pull/26153) your argument that "absolute" is going away and should be avoided is no longer accurate. It offers a distinct behavior to "resolve" and there's no indication in the latest comments on that thread that it will be removed. – Jordan May 11 '22 at 01:04
  • Even though pathlib.absolute is document now, still be aware of the following difference on Windows: ```Path("G:").absolute() # still relative path G:```, ```os.path.abspath("G:") # absolute G:\\``` – Edvard Rejthar Dec 12 '22 at 18:54
85

You're looking for the method .absolute, if my understanding is correct, whose documentation states:

>>> print(p.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.

With a test file on my system this returns:

>>> p = pathlib.Path('testfile')
>>> p.absolute()
PosixPath('/home/jim/testfile')

This method seems to be a new, and still, undocumented addition to Path and Path inheritting objects.

Created an issue to document this.

danronmoon
  • 3,814
  • 5
  • 34
  • 56
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • 12
    Naturally, the accepted answer is the answer **absolutely no one should ever use.** See also [the only sane answer, which documents exactly why this is the case](https://stackoverflow.com/a/44569249/2809027). – Cecil Curry Jan 29 '21 at 07:20
  • I had to use the resolve() function as the the absolute() was giving me a path like /home/usename/projects/src/app/../../interfaces/ and not like /home/usename/projects/interfaces/ – thanos.a Aug 19 '21 at 20:56
48

If you simply want the path and do not want to check if the file exists, you can do

str(p)

as document in the Operations section.

Veech
  • 1,397
  • 2
  • 12
  • 20
  • 10
    topic starter ask for **absolute** path, you can't get it this way from `Path` object initialized with relative path – El Ruso Jul 16 '19 at 01:51
  • This should be marked as the best answer – svinther Sep 30 '22 at 06:52
  • 1
    Curious why the upvotes on this one. I'd welcome additional comments providing a bit more explanation. `str(pathlib.Path('.'))` returns `'.'`. This sort of behavior hardly seems helpful as a general solution for obtaining an absolute path. – dat Feb 26 '23 at 22:12
8
pathlib.Path.cwd() / p

This is recommended by CPython core developers as the "one obvious way".

p.resolve() does not return an absolute path for non-existing files on Windows at least.

p.absolute() is undocumented.

Peter
  • 3,322
  • 3
  • 27
  • 41
  • 3
    Well, it is recommended by **one** CPython core developer (and disputed by another one, as not being so obvious). Furthermore, on the same page it is [demonstrated](https://discuss.python.org/t/pathlib-absolute-vs-resolve/2573/15) that this solution does not always yield an absolute path. It will work for most cases, but is not bullet-proof. – wovano May 19 '21 at 11:08