source: ftputil/socket_file_adapter.py @ 1564:c5b353a1c23d

Last change on this file since 1564:c5b353a1c23d was 1564:c5b353a1c23d, checked in by Stefan Schwarzer <sschwarzer@…>, 5 years ago
List contributors in `doc/contributors.txt`. So far, individual files had copyright notices for contributors. However, this makes it difficult to properly adapt files in case of refactoring: If a piece of code is moved to another file, I would need to find out if this code was contributed by someone else and change the copyright notice in the target file accordingly. With the new approach, every file refers to the file `doc/contributors.txt`, which contains the names of contributors.
File size: 3.4 KB
Line 
1# Copyright (C) 2014, Stefan Schwarzer <sschwarzer@sschwarzer.net>
2# and ftputil contributors (see `doc/contributors.txt`)
3# See the file LICENSE for licensing terms.
4
5"""
6See docstring of class `BufferedIO`.
7"""
8
9import io
10
11
12__all__ = ["BufferedIOAdapter"]
13
14
15class BufferedIOAdapter(io.BufferedIOBase):
16    """
17    Adapt a file object returned from `socket.makefile` to the
18    interfaces of `io.BufferedReader` or `io.BufferedWriter`, so that
19    the new object can be wrapped by `io.TextIOWrapper`.
20
21    This is only needed with Python 2, since in Python 3
22    `socket.makefile` already returns a `BufferedReader` or
23    `BufferedWriter` object (depending on mode).
24    """
25
26    def __init__(self, fobj, is_readable=False, is_writable=False):
27        # Don't call baseclass constructor for this adapter.
28        # pylint: disable=super-init-not-called
29        #
30        # This is the return value of `socket.makefile` and is already
31        # buffered.
32        self.raw = fobj
33        self._is_readable = is_readable
34        self._is_writable = is_writable
35
36    @property
37    def closed(self):
38        # pylint: disable=missing-docstring
39        return self.raw.closed
40
41    def close(self):
42        self.raw.close()
43
44    def fileno(self):
45        return self.raw.fileno()
46
47    def isatty(self):
48        # It's highly unlikely that this file is interactive.
49        return False
50
51    def seekable(self):
52        return False
53
54    #
55    # Interface for `BufferedReader`
56    #
57    def readable(self):
58        return self._is_readable
59
60    def read(self, *arg):
61        return self.raw.read(*arg)
62
63    read1 = read
64
65    def readline(self, *arg):
66        return self.raw.readline(*arg)
67
68    def readlines(self, *arg):
69        return self.raw.readlines(*arg)
70
71    def readinto(self, bytearray_):
72        data = self.raw.read(len(bytearray_))
73        bytearray_[:len(data)] = data
74        return len(data)
75
76    #
77    # Interface for `BufferedWriter`
78    #
79    def writable(self):
80        return self._is_writable
81
82    def flush(self):
83        self.raw.flush()
84
85    # Derived from `socket.py` in Python 2.6 and 2.7.
86    # There doesn't seem to be a public API for this.
87    def _write_buffer_size(self):
88        """Return current size of the write buffer in bytes."""
89        # pylint: disable=protected-access
90        if hasattr(self.raw, "_wbuf_len"):
91            # Python 2.6.3 - 2.7.5
92            return self.raw._wbuf_len
93        elif hasattr(self.raw, "_get_wbuf_len"):
94            # Python 2.6 - 2.6.2. (Strictly speaking, all other
95            # Python 2.6 versions have a `_get_wbuf_len` method, but
96            # for 2.6.3 and up it returns `_wbuf_len`).
97            return self.raw._get_wbuf_len()
98        else:
99            # Fallback. In the context of `write` this means the file
100            # appears to be unbuffered.
101            return 0
102
103    def write(self, bytes_or_bytearray):
104        # `BufferedWriter.write` has to return the number of written
105        # bytes, but files returned from `socket.makefile` in Python 2
106        # return `None`. Hence provide a workaround.
107        old_buffer_byte_count = self._write_buffer_size()
108        added_byte_count = len(bytes_or_bytearray)
109        self.raw.write(bytes_or_bytearray)
110        new_buffer_byte_count = self._write_buffer_size()
111        return (old_buffer_byte_count + added_byte_count -
112                new_buffer_byte_count)
113
114    def writelines(self, lines):
115        self.raw.writelines(lines)
Note: See TracBrowser for help on using the repository browser.