2
\$\begingroup\$

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."""

    @classmethod
    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."""

    @classmethod
    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)))
\$\endgroup\$
3
\$\begingroup\$

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

    @property
    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
'r-x'
>>> 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.

\$\endgroup\$
  • \$\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\$ – Richard Neumann Nov 22 '17 at 10:05
  • \$\begingroup\$ @RichardNeumann As demonstrated above, PosixPermission(5). \$\endgroup\$ – Peilonrayz Nov 22 '17 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\$ – Richard Neumann Nov 22 '17 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 '17 at 10:09
  • \$\begingroup\$ @MaartenFabré That's exactly what I meant to say in my last comment. \$\endgroup\$ – Richard Neumann Nov 22 '17 at 11:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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