A design of os.path?

Which do you think is a bug or a design…?

>>> sys.version
'3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]'
>>> os.path.exists(0)
True
>>> os.path.exists(1)
True
>>> os.path.exists(-1)
False
>>> os.path.exists(2**31)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\Python310\lib\genericpath.py", line 19, in exists
    os.stat(path)
OverflowError: fd is greater than maximum
>>> list(filter(os.path.isfile, range(100)))
[]
>>> list(filter(os.path.isdir, range(100)))
[]
>>> list(filter(os.path.exists, range(100)))
[0, 1, 2]

The documentation for os.path.exists says:

“Changed in version 3.3: path can now be an integer: True is returned if it is an open file descriptor, False otherwise.”

So this is deliberate design: os.path.exists(0) returns True because 0 is the open file descriptor for stdin.

There are no bugs in the code you show. It is all deliberate.

You can learn about file descriptors here.

2 Likes

Thank you very much, Steven. Your explanation is very clear (always) to me!
I have checked documents such as isdir, isfile, but overlooked exists
I ran into a bug in my code since I just expected TypeError thrown from the system, and now I have to write it on my own.

By Kazuya O’moto via Discussions on Python.org at 10Jun2022 12:01:

Thank you very much, Steven. Your explanation is very clear (always) to
me!
I have checked documents such as isdir, isfile, but overlooked exists
I ran into a bug in my code since I just expected TypeError thrown
from the system, and now I have to write it on my own.

You might want to look at both:

  • type annotations, letting you run a static type checker against your
    code to find such issues
  • the typeguard package, which lets you decorate functions to check
    type annotations at runtime

Between them, doing type checks becomes a lot more convenient.

The default behaviour in Python is that type annotations are ignored at
runtime, but available for generated docs and for the programmer’s eye
and for static type analysis with tools such as mypy.

The typeguard package supports typechecking at runtime, handy for
debugging. While you don’t want this on every function call (performance
cost), it is very useful to make particular things checked at runtime,
because they are critical and/or not a performance bottleneck.

Example from a module of mine:

from typeguard import typechecked

@typechecked
def deduce_type_bigendianness(typecode: str) -> bool:
    ... function body here ...

Without the decorator, this function accepts anything. With the
decorator the parameters are checked at the call and the return value
afterwards.

As with the icontract module, these checks are disabled if Python is
run with -O (which also disables asserts). But judiciously used,
there’s rarely a need to reach for -O.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like