I implemented a virtual file system library with POSIX file mode representation.
Any suggestions regarding optimization are welcome.

"""POSIX file system library."""

from collections import namedtuple

__all__ = ['PosixPermission', 'PosixMode']

MIN_PERM = 0b000
MAX_PERM = 0b111
DEF_PERM = 0b110    # rw-
MIN_MODE = 0o000
MAX_MODE = 0o777
DEF_MODE = 0o640

class PosixPermission(namedtuple('PosixPermission', 'read write execute')):
    """POSIX file permissions."""

    def from_int(cls, perm=DEF_PERM):
        """Creates the file permissions from the respective integer value."""
        if MIN_PERM <= perm <= MAX_PERM:
            return cls(bool(perm & 4), bool(perm & 2), bool(perm & 1))

        raise ValueError('Permission value must be between {} and {}.'.format(
            MIN_PERM, MAX_PERM))

    def __int__(self):
        """Returns the integer value of the file permission."""
        return (self.read and 4) + (self.write and 2) + (self.execute and 1)

    def __str__(self):
        """Returns binary representation of the file permission."""
        return ''.join(map(
            lambda perm: perm or '-',
            (self.read and 'r', self.write and 'w', self.execute and 'x')))

class PosixMode(namedtuple('PosixMode', 'user group other')):
    """POSIX file mode."""

    def from_int(cls, mode=DEF_MODE):
        """Creates the file mode from the respective integer value."""
        if MIN_MODE <= mode <= MAX_MODE:
            return cls(
                PosixPermission.from_int(mode >> 6 & 7),
                PosixPermission.from_int(mode >> 3 & 7),
                PosixPermission.from_int(mode & 7))

        raise ValueError('File mode must be between {} and {}.'.format(
            oct(MIN_MODE), oct(MAX_MODE)))

    def __int__(self):
        """Returns the integer value of the file mode."""
        return (int(self.user) << 6) + (int(self.group) << 3) + int(self.other)

    def __str__(self):
        """Returns the octal representation of the file mode."""
        return ''.join((str(self.user), str(self.group), str(self.other)))

1 Answer 1


I'm confused why you're using a named tuple for PosixPermission. To me an Enum would be a better choice:

class PosixPermission(Flag):
    READ = 4
    WRITE = 2
    EXECUTE = 1
    NONE = 0

    def perms(self):
        return ''.join(
            name if self & val else '-'
            for name, val in zip('rwx', PosixPermission)
>>> PosixPermission(0)
<PosixPermission.NONE: 0>
>>> PosixPermission(7)
<PosixPermission.READ|WRITE|EXECUTE: 7>
>>> PosixPermission(5)
<PosixPermission.READ|EXECUTE: 5>
>>> PosixPermission(5).perms
>>> PosixPermission(5) & PosixPermission.READ
<PosixPermission.READ: 4>
>>> PosixPermission(5) & PosixPermission.WRITE
<PosixPermission.NONE: 0>
>>> PosixPermission(8)
Traceback (most recent call last):
ValueError: 8 is not a valid PosixPermission

Honestly PosixMode looks pretty good, I think it's reasonable to assume it to be a namedtuple, rather than an object with __slots__. I however wouldn't use __int__ and __str__, and would instead use properties for these.

  • \$\begingroup\$ I do not understand your enum approach. How would I get a permission instance of, let's say r-x (read, not write, execute) with it? \$\endgroup\$ Nov 22, 2017 at 10:05
  • \$\begingroup\$ @RichardNeumann As demonstrated above, PosixPermission(5). \$\endgroup\$
    – Peilonrayz
    Nov 22, 2017 at 10:07
  • \$\begingroup\$ Ah. Got it. But then I could not do if posix_mode.user.write without adding the write property, which I already have on the namedtuple. \$\endgroup\$ Nov 22, 2017 at 10:09
  • 2
    \$\begingroup\$ @RichardNeumann You can however use if posix_mode.user & PosixPermission.WRITE. If you don't like the length of it, you can just make PosixPermission.WRITE a variable, and use if posix_mode.user&WRITE. \$\endgroup\$
    – Peilonrayz
    Nov 22, 2017 at 10:09
  • \$\begingroup\$ @MaartenFabré That's exactly what I meant to say in my last comment. \$\endgroup\$ Nov 22, 2017 at 11:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.