Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the python pathlib Path('').exists() return True?

I was expecting Path('') to be a path that does not exist because it does not correspond to a file or directory name. Why is this considered to exist?

from pathlib import Path

print(Path('').exists())

I assume there is an advantage gained by defining the Path('') to be the same as Path('.'). In what case is there an advantage?

like image 972
mattm Avatar asked Jul 13 '18 17:07

mattm


3 Answers

As other said, it resolves to the current path and therefore exists, but here's why,

pathlib.Path is acutally a subclass of pathlib.PurePath which assumes the current directory when the pathsegments (argument) is empty (equivalent to '').

You can prove that empirically like this,

from pathlib import PurePath
print(PurePath())
>>>> .

I assume there is an advantage gained by defining the Path('') to be the same as Path('.').

Correct. Even though I'm not the creator of that lib, I assume this is for syntax and logical reasons. Indeed, people often want to refer to the current directory to compute something dynamically. Therefore, for the same reason . points to the current directory, the lib creator probably wanted to let you write something like this,

>>>> p = Path() # or possibly Path('.')
>>> [x for x in p.iterdir() if x.is_dir()]

that would list sub directories.

Basically, see this as a default. It was logic that the default path returned by Path() was the current directory. Thus, logically, an empty string value should have the same behavior.

like image 78
scharette Avatar answered Nov 18 '22 16:11

scharette


If you try stat you get:

$ touch ""
touch: cannot touch '': No such file or directory

but if you peek inside, the story is different:

$ strace -e file touch ""
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=122530, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

So you can stat "" because it's the CWD, but you can't open it as a file because no such file exists. Indeed:

$ strace -e file ipython3 
In [1]: import pathlib

In [2]: p = pathlib.Path()

In [3]: p.exists()
newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=20480, ...}, 0) = 0
Out[3]: True

So this is not exactly any kind of assumption from Python's pathlib module, but all the way down the the C lib and kernel.

like image 5
Marcos Dione Avatar answered Nov 18 '22 17:11

Marcos Dione


Slightly off topic: I want to have a Path whose boolean value is False. Seems to be not possible. I'm doing this inside argparse with type=Path. I suspect that OP wanted something similar.

I ended up using one of two options, neither as "elegant" as it would be if I could simply test "if the_possibly_false_Path:..."

  1. Set the default (which I wish tested False) to something like '%%' which causes argparse to create a Path with the name "%%" which I can then test for
  2. Leave the result as a default type, set the default to something that tests False and then call the Path constructor if the value isn't false.
like image 1
griswolf Avatar answered Nov 18 '22 16:11

griswolf