Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add options for several IO operation #362

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [2.4.12] - (Unreleased)

### Added

- Added `options` kwargs to several I/O operations, including: `readbytes`,
`writebytes`, `readtext`, `writetext` and `writefile`.

### Changed

- Start testing on PyPy. Due to [#342](https://github.com/PyFilesystem/pyfilesystem2/issues/342)
we have to treat PyPy builds specially and allow them to fail, but at least we'll
be able to see if we break something aside from known issues with FTP tests.
- Set `py36 = false` for black to prevent adding trailing comma in function
definition and cause `SyntaxError` in older python version.

## [2.4.11] - 2019-09-07

Expand Down
50 changes: 39 additions & 11 deletions fs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,12 +586,14 @@ def exclude_file(patterns, info):
iter_info = itertools.islice(iter_info, start, end)
return iter_info

def readbytes(self, path):
# type: (Text) -> bytes
def readbytes(self, path, **options):
# type: (Text, Any) -> bytes
"""Get the contents of a file as bytes.

Arguments:
path (str): A path to a readable file on the filesystem.
**options: keyword arguments for any additional information
required by the filesystem (if any).

Returns:
bytes: the file contents.
Expand All @@ -600,7 +602,7 @@ def readbytes(self, path):
fs.errors.ResourceNotFound: if ``path`` does not exist.

"""
with closing(self.open(path, mode="rb")) as read_file:
with closing(self.open(path, mode="rb", **options)) as read_file:
contents = read_file.read()
return contents

Expand Down Expand Up @@ -644,6 +646,7 @@ def readtext(
encoding=None, # type: Optional[Text]
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> Text
"""Get the contents of a file as a string.
Expand All @@ -654,6 +657,8 @@ def readtext(
in text mode (defaults to `None`, reading in binary mode).
errors (str, optional): Unicode errors parameter.
newline (str): Newlines parameter.
**options: keyword arguments for any additional information
required by the filesystem (if any).

Returns:
str: file contents.
Expand All @@ -664,7 +669,12 @@ def readtext(
"""
with closing(
self.open(
path, mode="rt", encoding=encoding, errors=errors, newline=newline
path,
mode="rt",
encoding=encoding,
errors=errors,
newline=newline,
**options
)
) as read_file:
contents = read_file.read()
Expand Down Expand Up @@ -1163,7 +1173,7 @@ def open(
"""
validate_open_mode(mode)
bin_mode = mode.replace("t", "")
bin_file = self.openbin(path, mode=bin_mode, buffering=buffering)
bin_file = self.openbin(path, mode=bin_mode, buffering=buffering, **options)
io_stream = iotools.make_stream(
path,
bin_file,
Expand All @@ -1172,7 +1182,7 @@ def open(
encoding=encoding or "utf-8",
errors=errors,
newline=newline,
**options
line_buffering=options.get("line_buffering", False),
)
return io_stream

Expand Down Expand Up @@ -1271,22 +1281,24 @@ def scandir(
iter_info = itertools.islice(iter_info, start, end)
return iter_info

def writebytes(self, path, contents):
# type: (Text, bytes) -> None
def writebytes(self, path, contents, **options):
# type: (Text, bytes, Any) -> None
# FIXME(@althonos): accept bytearray and memoryview as well ?
"""Copy binary data to a file.

Arguments:
path (str): Destination path on the filesystem.
contents (bytes): Data to be written.
**options: keyword arguments for any additional information
required by the filesystem (if any).

Raises:
TypeError: if contents is not bytes.

"""
if not isinstance(contents, bytes):
raise TypeError("contents must be bytes")
with closing(self.open(path, mode="wb")) as write_file:
with closing(self.open(path, mode="wb", **options)) as write_file:
write_file.write(contents)

setbytes = _new_name(writebytes, "setbytes")
Expand Down Expand Up @@ -1331,6 +1343,7 @@ def writefile(
encoding=None, # type: Optional[Text]
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> None
"""Set a file to the contents of a file object.
Expand All @@ -1343,6 +1356,8 @@ def writefile(
errors (str, optional): How encoding errors should be treated
(same as `io.open`).
newline (str): Newline parameter (same as `io.open`).
**options: Implementation specific options required to open
the source file.

This method is similar to `~FS.upload`, in that it copies data from a
file-like object to a resource on the filesystem, but unlike ``upload``,
Expand All @@ -1362,7 +1377,12 @@ def writefile(

with self._lock:
with self.open(
path, mode=mode, encoding=encoding, errors=errors, newline=newline
path,
mode=mode,
encoding=encoding,
errors=errors,
newline=newline,
**options
) as dst_file:
tools.copy_file_data(file, dst_file)

Expand Down Expand Up @@ -1401,6 +1421,7 @@ def writetext(
encoding="utf-8", # type: Text
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> None
"""Create or replace a file with text.
Expand All @@ -1413,6 +1434,8 @@ def writetext(
errors (str, optional): How encoding errors should be treated
(same as `io.open`).
newline (str): Newline parameter (same as `io.open`).
**options: keyword arguments for any additional information
required by the filesystem (if any).

Raises:
TypeError: if ``contents`` is not a unicode string.
Expand All @@ -1422,7 +1445,12 @@ def writetext(
raise TypeError("contents must be unicode")
with closing(
self.open(
path, mode="wt", encoding=encoding, errors=errors, newline=newline
path,
mode="wt",
encoding=encoding,
errors=errors,
newline=newline,
**options
)
) as write_file:
write_file.write(contents)
Expand Down
10 changes: 5 additions & 5 deletions fs/ftpfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,19 +761,19 @@ def upload(self, path, file, chunk_size=None, **options):
str("STOR ") + _encode(_path, self.ftp.encoding), file
)

def writebytes(self, path, contents):
# type: (Text, ByteString) -> None
def writebytes(self, path, contents, **options):
# type: (Text, ByteString, Any) -> None
if not isinstance(contents, bytes):
raise TypeError("contents must be bytes")
self.upload(path, io.BytesIO(contents))
self.upload(path, io.BytesIO(contents), **options)

def setinfo(self, path, info):
# type: (Text, RawInfo) -> None
if not self.exists(path):
raise errors.ResourceNotFound(path)

def readbytes(self, path):
# type: (Text) -> bytes
def readbytes(self, path, **options):
# type: (Text, Any) -> bytes
_path = self.validatepath(path)
data = io.BytesIO()
with ftp_errors(self, path):
Expand Down
25 changes: 17 additions & 8 deletions fs/mountfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,11 @@ def removedir(self, path):
fs, _path = self._delegate(path)
return fs.removedir(_path)

def readbytes(self, path):
# type: (Text) -> bytes
def readbytes(self, path, **options):
# type: (Text, Any) -> bytes
self.check()
fs, _path = self._delegate(path)
return fs.readbytes(_path)
return fs.readbytes(_path, **options)

def download(self, path, file, chunk_size=None, **options):
# type: (Text, BinaryIO, Optional[int], **Any) -> None
Expand All @@ -203,11 +203,14 @@ def readtext(
encoding=None, # type: Optional[Text]
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> Text
self.check()
fs, _path = self._delegate(path)
return fs.readtext(_path, encoding=encoding, errors=errors, newline=newline)
return fs.readtext(
_path, encoding=encoding, errors=errors, newline=newline, **options
)

def getsize(self, path):
# type: (Text) -> int
Expand Down Expand Up @@ -306,11 +309,11 @@ def upload(self, path, file, chunk_size=None, **options):
fs, _path = self._delegate(path)
return fs.upload(_path, file, chunk_size=chunk_size, **options)

def writebytes(self, path, contents):
# type: (Text, bytes) -> None
def writebytes(self, path, contents, **options):
# type: (Text, bytes, Any) -> None
self.check()
fs, _path = self._delegate(path)
return fs.writebytes(_path, contents)
return fs.writebytes(_path, contents, **options)

def writetext(
self,
Expand All @@ -319,9 +322,15 @@ def writetext(
encoding="utf-8", # type: Text
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> None
fs, _path = self._delegate(path)
return fs.writetext(
_path, contents, encoding=encoding, errors=errors, newline=newline
_path,
contents,
encoding=encoding,
errors=errors,
newline=newline,
**options
)
23 changes: 13 additions & 10 deletions fs/multifs.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,24 +280,26 @@ def scandir(
if not exists:
raise errors.ResourceNotFound(path)

def readbytes(self, path):
# type: (Text) -> bytes
def readbytes(self, path, **options):
# type: (Text, Any) -> bytes
self.check()
fs = self._delegate(path)
if fs is None:
raise errors.ResourceNotFound(path)
return fs.readbytes(path)
return fs.readbytes(path, **options)

def download(self, path, file, chunk_size=None, **options):
# type: (Text, BinaryIO, Optional[int], **Any) -> None
fs = self._delegate_required(path)
return fs.download(path, file, chunk_size=chunk_size, **options)

def readtext(self, path, encoding=None, errors=None, newline=""):
# type: (Text, Optional[Text], Optional[Text], Text) -> Text
def readtext(self, path, encoding=None, errors=None, newline="", **options):
# type: (Text, Optional[Text], Optional[Text], Text, Any) -> Text
self.check()
fs = self._delegate_required(path)
return fs.readtext(path, encoding=encoding, errors=errors, newline=newline)
return fs.readtext(
path, encoding=encoding, errors=errors, newline=newline, **options
)

def getsize(self, path):
# type: (Text) -> int
Expand Down Expand Up @@ -406,9 +408,9 @@ def upload(self, path, file, chunk_size=None, **options):
path, file, chunk_size=chunk_size, **options
)

def writebytes(self, path, contents):
# type: (Text, bytes) -> None
self._writable_required(path).writebytes(path, contents)
def writebytes(self, path, contents, **options):
# type: (Text, bytes, Any) -> None
self._writable_required(path).writebytes(path, contents, **options)

def writetext(
self,
Expand All @@ -417,9 +419,10 @@ def writetext(
encoding="utf-8", # type: Text
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> None
write_fs = self._writable_required(path)
return write_fs.writetext(
path, contents, encoding=encoding, errors=errors, newline=newline
path, contents, encoding=encoding, errors=errors, newline=newline, **options
)
6 changes: 4 additions & 2 deletions fs/wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ def writetext(
encoding="utf-8", # type: Text
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> None
self.check()
Expand Down Expand Up @@ -271,8 +272,8 @@ def open(
**options
)

def writebytes(self, path, contents):
# type: (Text, bytes) -> None
def writebytes(self, path, contents, **options):
# type: (Text, bytes, Any) -> None
self.check()
raise ResourceReadOnly(path)

Expand All @@ -288,6 +289,7 @@ def writefile(
encoding=None, # type: Optional[Text]
errors=None, # type: Optional[Text]
newline="", # type: Text
**options # type: Any
):
# type: (...) -> None
self.check()
Expand Down
Loading