Changeset 2:834304b43268 for ftputil.py

Show
Ignore:
Timestamp:
2002-01-13 14:11:21 (9 years ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
convert_revision:
svn:778c30c8-61e0-0310-89d4-fe2f97a467b2/trunk@3
Message:
Added read and write operations to _FTPFile class.
Files:
1 modified

Legend:

Unmodified
Added
Removed
  • ftputil.py

    r1 r2  
    3131 
    3232import ftplib 
    33  
     33import os 
    3434 
    3535class FTPIOError(IOError): 
     
    3737        self.ftp_exception = ftp_exception 
    3838        IOError(self, msg) 
     39 
     40# converters for native line ends to normalized ones in Python 
     41_linesep = os.linesep 
     42if _linesep == '\n': 
     43    _native_to_python_linesep = \ 
     44                        lambda text: text 
     45elif _linesep == '\r\n': 
     46    _native_to_python_linesep = \ 
     47                        lambda text: text.replace('\r', '') 
     48elif _linesep == '\r': 
     49    _native_to_python_linesep = \ 
     50                        lambda text: text.replace('\r', '\n') 
     51else: 
     52    def _native_to_python_linesep(text): 
     53        raise NotImplementedError("Can't do line ending " 
     54              "conversion for %s" % _linesep) 
     55 
     56# converter for Python line ends in native ones 
     57_python_to_native_linesep = \ 
     58  lambda text: text.replace('\n', _linesep) 
    3959 
    4060 
     
    5070        self.mode = mode 
    5171        self._binary = 'b' in mode 
    52         if mode == 'r': 
    53             # the FTP server ensures the correct mode via 
    54             #  the previous TYPE command 
    55             mode = 'rb' 
    5672        self._fp = conn.makefile(mode) 
    5773         
    58     def _normalize_linefeeds(text): 
    59         r'''Return data with occurences of \r removed.''' 
    60         return data.replace('\r', '') 
    61  
     74    # 
     75    # Read and write operations with support for 
     76    # line separator conversion for text modes. 
     77    # 
     78    # Note that we must convert line endings because 
     79    # the FTP server expects the native line separator 
     80    # format sent on ASCII transfers. 
     81    # 
    6282    def read(self, *args, **kwargs): 
    63         '''Return read bytes, normalized if in ASCII 
     83        '''Return read bytes, normalized if in text 
    6484        transfer mode.''' 
    65         text = apply(self._fp.read, args, kwargs) 
     85        data = apply(self._fp.read, args, kwargs) 
    6686        if self._binary: 
    67             return text 
    68         else: 
    69             return self._normalize_linefeeds(text) 
     87            return data 
     88        return _native_to_python_linesep(data) 
    7089 
    7190    def readlines(self, *args, **kwargs): 
    72         '''Return read lines, normalized if in ASCII 
     91        '''Return read lines, normalized if in text 
    7392        transfer mode.''' 
    7493        lines = apply(self._fp.readlines, args, kwargs) 
    75         return [self._normalize_linefeeds(line) 
    76                 for line in lines] 
     94        if self._binary: 
     95            return lines 
     96        # more memory-friendly than 
     97        #  return [... for line in lines] 
     98        for i in range( len(lines) ): 
     99            lines[i] = _native_to_python_linesep(lines[i]) 
     100        return lines 
    77101         
     102    def xreadlines(self): 
     103        '''Return an appropriate xreadlines object with 
     104        built-in line separator conversion support.''' 
     105        if self._binary: 
     106            return self._fp.xreadlines() 
     107        raise NotImplementedError( 
     108              "xreadlines not yet supported") 
     109 
     110    def write(self, data): 
     111        '''Write data to file. Do linesep conversion for 
     112        text mode.''' 
     113        if not self._binary: 
     114            data = _python_to_native_linesep(data) 
     115        self._fp.write(data) 
     116 
     117    def writelines(self, lines): 
     118        '''Write lines to file. Do linesep conversion for 
     119        text mode.''' 
     120        if not self._binary: 
     121            for i in range( len(lines) ): 
     122                lines[i] = _python_to_native_linesep(lines[i]) 
     123        self._fp.writelines(lines) 
     124     
     125    # 
     126    # other attributes 
     127    # 
    78128    def __getattr__(self, attr_name): 
    79129        '''Delegate unknown attribute requests to the file.''' 
    80         if attr_name in ( 'flush isatty fileno read readline ' 
    81           'readlines xreadlines seek tell truncate write ' 
    82           'writelines closed name softspace'.split() ): 
     130        if attr_name in ( 'flush isatty fileno seek tell ' 
     131          'truncate closed name softspace'.split() ): 
    83132            return eval('self._fp.%s' % attr_name) 
    84133        else: 
     
    115164        if '+' in mode: 
    116165            raise FTPIOError("append modes not supported") 
    117         if mode not in ( 'r rb br w wb bw'.split() ): 
     166        if mode not in ('r', 'rb', 'w', 'wb'): 
    118167            raise FTPIOError("invalid mode") 
    119168        # select ASCII or binary mode 
    120169        transfer_type = ('A', 'I')['b' in mode] 
    121170        command = 'TYPE %s' % transfer_type 
    122         # logic taken from ftplib; 
     171        # this logic taken from ftplib; 
    123172        #  why this strange distinction? 
    124173        if mode == 'r': 
    125174            self._host.sendcmd(command) 
    126         else: 
     175        else:  # rb, w, wb 
    127176            self._host.voidcmd(command) 
    128177        # make transfer command