Source code for fs.mode

"""Abstract I/O mode container.

Mode strings are used in in `~fs.base.FS.open` and
`~fs.base.FS.openbin`.

"""

from __future__ import print_function
from __future__ import unicode_literals

import typing

import six

from ._typing import Text


if False:  # typing.TYPE_CHECKING
    from typing import Container, FrozenSet, Set, Union


__all__ = ["Mode", "check_readable", "check_writable", "validate_openbin_mode"]


# https://docs.python.org/3/library/functions.html#open
[docs]@six.python_2_unicode_compatible class Mode(typing.Container[Text]): """An abstraction for I/O modes. A mode object provides properties that can be used to interrogate the `mode strings <https://docs.python.org/3/library/functions.html#open>`_ used when opening files. Arguments: mode (str): A *mode* string, as used by `io.open`. Raises: ValueError: If the mode string is invalid. Example: >>> mode = Mode('rb') >>> mode.reading True >>> mode.writing False >>> mode.binary True >>> mode.text False """ def __init__(self, mode): # type: (Text) -> None self._mode = mode self.validate() def __repr__(self): # type: () -> Text return "Mode({!r})".format(self._mode) def __str__(self): # type: () -> Text return self._mode
[docs] def __contains__(self, character): # type: (object) -> bool """Check if a mode contains a given character. """ return character in self._mode
[docs] def to_platform(self): # type: () -> Text """Get a mode string for the current platform. Currently, this just removes the 'x' on PY2 because PY2 doesn't support exclusive mode. """ return self._mode.replace("x", "w") if six.PY2 else self._mode
[docs] def to_platform_bin(self): # type: () -> Text """Get a *binary* mode string for the current platform. Currently, this just removes the 'x' on PY2 because PY2 doesn't support exclusive mode. """ _mode = self.to_platform().replace("t", "") return _mode if "b" in _mode else _mode + "b"
[docs] def validate(self, _valid_chars=frozenset("rwxtab+")): # type: (Union[Set[Text], FrozenSet[Text]]) -> None """Validate the mode string. Raises: ValueError: if the mode contains invalid chars. """ mode = self._mode if not mode: raise ValueError("mode must not be empty") if not _valid_chars.issuperset(mode): raise ValueError("mode '{}' contains invalid characters".format(mode)) if mode[0] not in "rwxa": raise ValueError("mode must start with 'r', 'w', 'x', or 'a'") if "t" in mode and "b" in mode: raise ValueError("mode can't be binary ('b') and text ('t')")
[docs] def validate_bin(self): # type: () -> None """Validate a mode for opening a binary file. Raises: ValueError: if the mode contains invalid chars. """ self.validate() if "t" in self: raise ValueError("mode must be binary")
@property def create(self): # type: () -> bool """`bool`: `True` if the mode would create a file. """ return "a" in self or "w" in self or "x" in self @property def reading(self): # type: () -> bool """`bool`: `True` if the mode permits reading. """ return "r" in self or "+" in self @property def writing(self): # type: () -> bool """`bool`: `True` if the mode permits writing. """ return "w" in self or "a" in self or "+" in self or "x" in self @property def appending(self): # type: () -> bool """`bool`: `True` if the mode permits appending. """ return "a" in self @property def updating(self): # type: () -> bool """`bool`: `True` if the mode permits both reading and writing. """ return "+" in self @property def truncate(self): # type: () -> bool """`bool`: `True` if the mode would truncate an existing file. """ return "w" in self or "x" in self @property def exclusive(self): # type: () -> bool """`bool`: `True` if the mode require exclusive creation. """ return "x" in self @property def binary(self): # type: () -> bool """`bool`: `True` if a mode specifies binary. """ return "b" in self @property def text(self): # type: () -> bool """`bool`: `True` if a mode specifies text. """ return "t" in self or "b" not in self
[docs]def check_readable(mode): # type: (Text) -> bool """Check a mode string allows reading. Arguments: mode (str): A mode string, e.g. ``"rt"`` Returns: bool: `True` if the mode allows reading. """ return Mode(mode).reading
[docs]def check_writable(mode): # type: (Text) -> bool """Check a mode string allows writing. Arguments: mode (str): A mode string, e.g. ``"wt"`` Returns: bool: `True` if the mode allows writing. """ return Mode(mode).writing
def validate_open_mode(mode): # type: (Text) -> None """Check ``mode`` parameter of `~fs.base.FS.open` is valid. Arguments: mode (str): Mode parameter. Raises: `ValueError` if mode is not valid. """ Mode(mode)
[docs]def validate_openbin_mode(mode, _valid_chars=frozenset("rwxab+")): # type: (Text, Union[Set[Text], FrozenSet[Text]]) -> None """Check ``mode`` parameter of `~fs.base.FS.openbin` is valid. Arguments: mode (str): Mode parameter. Raises: `ValueError` if mode is not valid. """ if "t" in mode: raise ValueError("text mode not valid in openbin") if not mode: raise ValueError("mode must not be empty") if mode[0] not in "rwxa": raise ValueError("mode must start with 'r', 'w', 'a' or 'x'") if not _valid_chars.issuperset(mode): raise ValueError("mode '{}' contains invalid characters".format(mode))