[Python-ideas] PEP: Extended stat_result (First Draft)

Charles-François Natali cf.natali at gmail.com
Mon May 6 11:31:39 CEST 2013


Hello,

Looks good, a couple remarks.

> Added methods on ``stat_result``
> --------------------------------

There are too many is_XXX methods.

> is_dir()
>     Equivalent to ``bool(stat.S_ISDIR(self.st_mode))``.
> is_file()
>     Equivalent to ``bool(stat.S_ISREG(self.st_mode))``.
> is_symbolic_link()
>     Equivalent to ``bool(stat.S_ISLNK(self.st_mode))``.

OK.

> is_character_device()
>     Equivalent to ``bool(stat.S_ISCHR(self.st_mode))``.
>
> is_block_device()
>     Equivalent to ``bool(stat.S_ISBLK(self.st_mode))``.
>
> is_fifo()
>     Equivalent to ``bool(stat.S_ISFIFO(self.st_mode))``.
>
> is_socket()
>     Equivalent to ``bool(stat.S_ISSOCK(self.st_mode)``.

Those are IMO useless.
If we go down this road, we can also add Solaris door files, and
another bazillion files types (see the previous thread).
Something like is_other() or is_special() is enough. Code needing more
specific information about the file type know how to use S_XXX, and
has to be non portable anyway.

> same_stat(other)
>     Equivalent to ``os.path.samestat(self, other)``.

I think it could be better to add a "key" attribute, which would
return (st_dev, st_ino). Then, checking that two stat results refer to
the same file is simply a matter of comparing their key.

Could the following be properties?

> permission_bits()
>     This shall return ``stat.S_IMODE(self.st_mode)``.

good

> file_mode()
>     This shall return ``stat.filemode(stat.S_IMODE(self.st_mode))``, i.e. a
>     string of the form ‘-rwxrwxrwx’.

Interesting.
I don't like the name, though.
Also, if we provide a way to return a string representation from the
permission bits, we also probably want an helper to do it the other
way around, i.e. a permission bit array from a string.
So I think those two methods we be better as static helper methods.

> format()
>     This shall return ``stat.S_IFMT(self.st_mode)``.

Is this really necessary?
AFAICT, S_IFMT is only useful as an helper for S_ISREG/etc. I don't
see any added value in exposing it.


> Added functions in ``os.path``
> ------------------------------
>
> is_dir(f)
>     This shall be an alias for the existing isdir(f).

Why?

> is_character_device(f)
>     This shall return ``os.stat(f).is_character_device()``, or ``False`` if
>     ``f`` does not exist.
>
> is_block_device(f)
>     This shall return ``os.stat(f).is_block_device()``, or ``False`` if
>     ``f`` does not exist.
>
> is_file()
>     This shall be an alias for the existing isfile(f).
>
> is_fifo()
>     This shall return ``os.stat(f).is_fifo()``, or ``False`` if
>     ``f`` does not exist.
>
> is_symbolic_link()
>     This shall return ``os.stat(f).is_symbolic_link()``, or ``False`` if
>     ``f`` does not exist.
>
> is_socket()
>     This shall return ``os.stat(f).is_socket()``, or ``False`` if
>     ``f`` does not exist.

Same remark as above, I'm not convinced that all those special cases
are necessary.

> Rationale
> =========
>
> The PEP is strongly motivated by a desire for symmetry between functions in
> ``os.path`` and methods on ``stat_result``.
>
> Therefore, for each predicate function in ``os.path`` that is essentially
> just an interrogation of ``os.*stat()``, given an existing path, the
> similarly-named predicate method on ``stat_result`` should have the exact
> same semantics.
>
> This definition does not cover the case where the path being interrogated
> does not exist.  In those cases, predicate functions in ``os.path``, such
> as ``os.path.isfile()``, will return ``False``, whereas ``os.*stat()`` will
> raise FileNotFoundError even before any ``stat_result`` is returned that
> could have been interrogated.  This renders considerations of how the
> proposed new predicates on ``stat_result`` could have been symmetrical with
> functions in ``os.path``, if their ``stat_result`` had existed, moot, and
> this PEP does not propose doing anything about the situation (but see `Open
> Issues`_ below).
>
> Secondly, this definition refers to ‘similarly-named’ predicates instead of
> ‘identically-named’ predicates, because the names in ``os.path`` pre-date
> PEP 8 [#PEP-8]_, and are not compliant with it.  This PEP takes the
> position that it is better that the new predicate methods on
> ``stat_result`` be named in compliance with PEP 8 [#PEP-8]_ (i.e.
> ``is_file()``), than that they be precisely identical to the names in
> ``os.path`` (i.e ``isfile()``).  Note also that PEP 428 [#PEP-428]_ also
> specifies PEP-8 compliant names such as ``is_file()`` for the exact same
> concepts, and if PEP 428 [#PEP-428]_ should be accepted, the issue would be
> even more pertinent.
>
> Lastly, this PEP takes the notion of symmetry as far as adding methods and
> aliases to the existing ``os.path`` in order to be symmetrical with the
> added behaviour on ``stat_result``.  But the author is least strongly
> convicted of this latter point, and may be convinced to abandon it.

I'm not convinced either.

> Backwards Compatibility
> =======================
>
> This PEP neither removes current behavior of ``stat_result``, nor changes
> the semantics of any current behavior.  Likewise, it adds functions and
> aliases for functions to ``os.path``, but does not remove or change any
> existing ones.
>
> Therefore, this PEP should not cause any backwards incompatibilities,
> except in the rare and esoteric cases where code is dependent on the
> *nonexistence* of the proposed new names.  It is not deemed important
> remain compatible with code that mistakenly holds the Python Standard
> Library to be closed for new additions.

You just want to make sure that your stat result is compatible with
the current implementation (tuple-struct, supporting indexing).

> Open Issues
> ===========
>
> Whether it is more desirable for the proposed added methods’ names to
> follow PEP 8 [#PEP-8]_ (i.e.  ``is_file()`` etc.), or to mirror the
> pre-existing names in ``os.path`` (i.e.  ``isfile()`` etc.) is still open
> for debate.
>
> The existing attributes on ``stat_result`` follow the pattern ``st_*`` in
> conformance to the relevant POSIX names for the fields of the C-level
> ``stat`` structure.  The new names for the behaviours proposed here do not
> contain such an ``st_`` prefix (nor could they, for that would suggest a
> conformance with ``stat`` structure names which do not exist in POSIX).
> But the resulting asymmetry of names is annoying.  Should aliases for the
> existing ``st_*`` names be added that omit the ``st_`` prefix?

If we offer a higher level abstraction, then I think the 'st_' prefix
should be dropped.

> As it stands, this PEP does not address the asymmetry between the existing
> ``os.path.isfile()`` etc.  functions and the new proposed mechanism in the
> case where the underlying file does not exist.  There is a way to handle
> this, though: an optional flag could be added to ``os.*stat()`` that would
> return a null object implementation of ``stat_result`` whenever the file
> does not exist.  Then that null object could return ``False`` to
> ``is_file()`` etc., That means that the following code would behave
> identically, even when the file ``f`` does not exist::
>
>     if os.path.isfile(f) or os.path.isdir(f):
>         # do something
>
>     st = os.stat(f, null_if_missing=True)
>     if st.is_file() or st.is_dir():
>         # do something
>
> Would this be a useful mechanism?

I don't like the idea of adding an optional attribute: stating a non
existing file will return an exception, that's it.
Also, I don't like the idea of a null object.



More information about the Python-ideas mailing list