Changeset 2028:72a34b226c8d


Ignore:
Timestamp:
Jan 27, 2021, 3:47:37 PM (10 months ago)
Author:
Stefan Schwarzer <sschwarzer@…>
Branch:
default
amend_source:
26da180e4dd0d745c7329ee3a034499c52edafc0
Message:
Add `encoding` argument for `session_factory`

ticket: 143
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • ftputil/session.py

    r1935 r2028  
    1 # Copyright (C) 2014-2018, Stefan Schwarzer <sschwarzer@sschwarzer.net>
     1# Copyright (C) 2014-2021, Stefan Schwarzer <sschwarzer@sschwarzer.net>
    22# and ftputil contributors (see `doc/contributors.txt`)
    33# See the file LICENSE for licensing terms.
     
    77"""
    88
     9import sys
    910import ftplib
     11
     12import ftputil.tool
    1013
    1114
     
    2225    *,
    2326    encrypt_data_channel=True,
     27    encoding=ftputil.tool.DEFAULT_ENCODING,
    2428    debug_level=None,
    2529):
     
    2832
    2933    base_class: Base class to use for the session class (e. g. `ftplib.FTP_TLS`
    30     or `M2Crypto.ftpslib.FTP_TLS`, default is `ftplib.FTP`).
     34    or `M2Crypto.ftpslib.FTP_TLS`, the default is `ftplib.FTP`).
    3135
    3236    port: Port number (integer) for the command channel (default 21). If you
     
    4145    the base class if it has the method. If `False` or `None` (`None` is the
    4246    default), don't call the method.
     47
     48    encoding: Encoding (str) to use for directory and file paths. Unicode paths
     49    will be encoded with this encoding. Bytes paths are assumed to be in this
     50    encoding. The default is "latin-1". If you use Python 3.9 and want the
     51    default encoding for `ftplib.FTP` sessions, you need to pass "UTF-8"
     52    explicitly.
    4353
    4454    debug_level: Debug level (integer) to be set on a session instance. The
     
    6575        """
    6676
     77        # In Python 3.8 and below, the `encoding` class attribute was never
     78        # documented, but setting it is the only way to set a custom encoding
     79        # for remote file system paths. Since we set the encoding on the class
     80        # level, all instances created from this class will share this
     81        # encoding. That's ok because the user asked for a specific encoding of
     82        # the _factory_ when calling `session_factory`.
     83        #
     84        # Python 3.9 is the first Python version to have a documented way to
     85        # set a custom encoding (per instance).
    6786        def __init__(self, host, user, password):
    68             super().__init__()
     87            if (sys.version_info.major, sys.version_info.minor) <= (3, 8):
     88                super().__init__()
     89            else:
     90                super().__init__(encoding=encoding)
    6991            self.connect(host, port)
    7092            if debug_level is not None:
     
    78100                self.prot_p()
    79101
     102    if (sys.version_info.major, sys.version_info.minor) <= (3, 8):
     103        Session.encoding = encoding
    80104    return Session
  • ftputil/tool.py

    r1935 r2028  
    1 # Copyright (C) 2013-2020, Stefan Schwarzer
     1# Copyright (C) 2013-2021, Stefan Schwarzer
    22# and ftputil contributors (see `doc/contributors.txt`)
    33# See the file LICENSE for licensing terms.
     
    1313
    1414
    15 # Encoding to convert between byte string and unicode string. This is a
    16 # "lossless" encoding: Strings can be encoded/decoded back and forth without
    17 # information loss or causing encoding-related errors. The `ftplib` module
    18 # under Python 3 also uses the "latin1" encoding internally. It's important to
    19 # use the same encoding here, so that users who used `ftplib` to create FTP
    20 # items with non-ASCII characters can access them in the same way with ftputil.
    21 LOSSLESS_ENCODING = "latin1"
     15# Default encoding to convert between byte string and unicode string. This is a
     16# "lossless" encoding in the sense that any byte string can be decoded to a
     17# unicode string, and this unicode string can be encoded to the original byte
     18# string.
     19#
     20# The `ftplib` module under Python 3.8 and earlier also uses the "latin-1"
     21# encoding internally. In this case, paths created with Python's `ftplib` use
     22# the same encoding as our `DEFAULT_ENCODING`.
     23DEFAULT_ENCODING = "latin-1"
    2224
    2325
  • test/test_session.py

    r1935 r2028  
    1 # Copyright (C) 2014-2018, Stefan Schwarzer <sschwarzer@sschwarzer.net>
     1# Copyright (C) 2014-2021, Stefan Schwarzer <sschwarzer@sschwarzer.net>
    22# and ftputil contributors (see `doc/contributors.txt`)
    33# See the file LICENSE for licensing terms.
     
    88
    99import ftputil.session
     10from ftputil.tool import DEFAULT_ENCODING
    1011
    1112
     
    121122        assert session.calls == [("connect", "host", 21), ("login", "user", "password")]
    122123
     124    def test_encoding(self):
     125        """
     126        Test setting the default encoding and a custom encoding.
     127
     128        (The default encoding, as in earlier ftputil versions, is "latin-1".)
     129        """
     130        # Default encoding
     131        factory = ftputil.session.session_factory(
     132            base_class=MockSession,
     133        )
     134        session = factory("host", "user", "password")
     135        assert session.calls == [
     136            ("connect", "host", 21),
     137            ("login", "user", "password"),
     138        ]
     139        assert session.encoding == DEFAULT_ENCODING
     140        # Custom encoding
     141        factory = ftputil.session.session_factory(
     142            base_class=MockSession,
     143            encoding="UTF-8",
     144        )
     145        session = factory("host", "user", "password")
     146        assert session.calls == [
     147            ("connect", "host", 21),
     148            ("login", "user", "password"),
     149        ]
     150        assert session.encoding == "UTF-8"
     151
    123152    def test_debug_level(self):
    124153        """
Note: See TracChangeset for help on using the changeset viewer.