Changeset 1603:3bdb8233c7f2


Ignore:
Timestamp:
Nov 1, 2015, 10:50:46 PM (4 years ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
Message:
Adapt the session, not the session factory

Since the session factory may be a function, not a class, don't adapt
the factory. Instead, adapt the session object after creating it by
using the factory.
Location:
ftputil
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • ftputil/host.py

    r1601 r1603  
    127127        # `FTPHost` object's child sessions.
    128128        factory = kwargs.pop("session_factory", ftplib.FTP)
    129         # Adapt session factories so that they accept unicode strings
    130         # with non-ASCII characters (as long as the string contains
    131         # only code points <= 255). See the docstring in
     129        with ftputil.error.ftplib_error_to_ftp_os_error:
     130            session = factory(*args, **kwargs)
     131        # Adapt session so that they accept unicode strings with
     132        # non-ASCII characters (as long as the string contains only
     133        # code points <= 255). See the docstring in module
    132134        # `session_adapter` for details.
    133         factory = ftputil.session_adapter.adapted_session_factory(factory)
    134         with ftputil.error.ftplib_error_to_ftp_os_error:
    135             return factory(*args, **kwargs)
     135        return ftputil.session_adapter.adapted_session(session)
    136136
    137137    def _copy(self):
  • ftputil/session_adapter.py

    r1600 r1603  
    4949
    5050
    51 # Since ftputil can be used with different session factories, for
    52 # example `ftplib.FTP`, `ftplib.FTP_TLS` or
    53 # `M2Crypto.ftpslib.FTP_TLS`), we can't let the adapter inherit
    54 # from a particular class. Instead, the concrete adapter class must
    55 # be generated dynamically depending on the used session factory.
     51# Shortcut
     52as_bytes = ftputil.tool.as_bytes
    5653
    57 def adapted_session_factory(session_factory):
     54
     55# We only have to adapt the methods that are directly called by
     56# ftputil and only those that take string arguments.
     57#
     58# Keep the call signature of each adaptor method the same as the
     59# signature of the adapted method so that code that introspects
     60# the signature of the method still works.
     61
     62class SessionAdapter(object):
     63
     64    def __init__(self, session):
     65        self._session = session
     66
     67    def voidcmd(self, cmd):
     68        cmd = as_bytes(cmd)
     69        return self._session.voidcmd(cmd)
     70
     71    def transfercmd(self, cmd, rest=None):
     72        cmd = as_bytes(cmd)
     73        return self._session.transfercmd(cmd, rest)
     74
     75    def dir(self, *args):
     76        # This is somewhat tricky, since some of the args may not
     77        # be strings. The last argument may be a callback.
     78        args = list(args)
     79        for index, arg in enumerate(args):
     80            # Replace only unicode strings with a corresponding
     81            # byte string.
     82            if isinstance(arg, ftputil.compat.unicode_type):
     83                args[index] = as_bytes(arg)
     84        return self._session.dir(*args)
     85
     86    def rename(self, fromname, toname):
     87        fromname = as_bytes(fromname)
     88        toname = as_bytes(toname)
     89        return self._session.rename(fromname, toname)
     90
     91    def delete(self, filename):
     92        filename = as_bytes(filename)
     93        return self._session.delete(filename)
     94
     95    def cwd(self, dirname):
     96        dirname = as_bytes(dirname)
     97        return self._session.cwd(dirname)
     98
     99    def mkd(self, dirname):
     100        dirname = as_bytes(dirname)
     101        return self._session.mkd(dirname)
     102
     103    def rmd(self, dirname):
     104        dirname = as_bytes(dirname)
     105        return self._session.rmd(dirname)
     106
     107    # Dispatch to session itself for methods that don't need string
     108    # conversions.
     109    def __getattr__(self, name):
     110        return getattr(self._session, name)
     111
     112
     113def adapted_session(session):
    58114    """
    59     Return an adapted session factory that will work with Python 2's
    60     `ftplib.FTP` and compatible factories.
     115    Return an adapted session that will work with Python 2's
     116    `ftplib.FTP` and compatible sessions.
    61117
    62     Under Python 3 return the passed session factory itself.
     118    Under Python 3 return the passed session itself.
    63119    """
    64     if ftputil.compat.python_version > 2:
    65         return session_factory
    66     # We only have to adapt the methods that are directly called by
    67     # ftputil and only those that take string arguments.
    68     #
    69     # Keep the call signature of each adaptor method the same as the
    70     # signature of the adapted method so that code that introspects
    71     # the signature of the method still works.
    72     #
    73     # The calls into the session factory's methods don't use `super`
    74     # since the factory may not be a new-style class (as in the case
    75     # of `ftplib.FTP`).
    76 
    77     # Shortcut
    78     as_bytes = ftputil.tool.as_bytes
    79 
    80     class SessionFactory(session_factory):
    81 
    82         def voidcmd(self, cmd):
    83             cmd = as_bytes(cmd)
    84             return session_factory.voidcmd(self, cmd)
    85 
    86         def transfercmd(self, cmd, rest=None):
    87             cmd = as_bytes(cmd)
    88             return session_factory.transfercmd(self, cmd, rest)
    89 
    90         def dir(self, *args):
    91             # This is somewhat tricky, since some of the args may not
    92             # be strings. The last argument may be a callback.
    93             args = list(args)
    94             for index, arg in enumerate(args):
    95                 # Replace only unicode strings with a corresponding
    96                 # byte string.
    97                 if isinstance(arg, ftputil.compat.unicode_type):
    98                     args[index] = as_bytes(arg)
    99             return session_factory.dir(self, *args)
    100 
    101         def rename(self, fromname, toname):
    102             fromname = as_bytes(fromname)
    103             toname = as_bytes(toname)
    104             return session_factory.rename(self, fromname, toname)
    105 
    106         def delete(self, filename):
    107             filename = as_bytes(filename)
    108             return session_factory.delete(self, filename)
    109 
    110         def cwd(self, dirname):
    111             dirname = as_bytes(dirname)
    112             return session_factory.cwd(self, dirname)
    113 
    114         def mkd(self, dirname):
    115             dirname = as_bytes(dirname)
    116             return session_factory.mkd(self, dirname)
    117 
    118         def rmd(self, dirname):
    119             dirname = as_bytes(dirname)
    120             return session_factory.rmd(self, dirname)
    121 
    122     return SessionFactory
     120    if ftputil.compat.python_version == 2:
     121        return SessionAdapter(session)
     122    else:
     123        return session
Note: See TracChangeset for help on using the changeset viewer.