Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a1a0eb4

Browse files
bpo-39380: Change ftplib encoding from latin-1 to utf-8 (GH-18048)
Add the encoding in ftplib.FTP and ftplib.FTP_TLS to the constructor as keyword-only and change the default from "latin-1" to "utf-8" to follow RFC 2640.
1 parent 258f517 commit a1a0eb4

5 files changed

Lines changed: 101 additions & 54 deletions

File tree

Doc/library/ftplib.rst

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ as mirroring other FTP servers. It is also used by the module
1919
:mod:`urllib.request` to handle URLs that use FTP. For more information on FTP
2020
(File Transfer Protocol), see Internet :rfc:`959`.
2121

22+
The default encoding is UTF-8, following :rfc:`2640`.
23+
2224
Here's a sample session using the :mod:`ftplib` module::
2325

2426
>>> from ftplib import FTP
@@ -41,7 +43,7 @@ Here's a sample session using the :mod:`ftplib` module::
4143

4244
The module defines the following items:
4345

44-
.. class:: FTP(host='', user='', passwd='', acct='', timeout=None, source_address=None)
46+
.. class:: FTP(host='', user='', passwd='', acct='', timeout=None, source_address=None, *, encoding='utf-8')
4547

4648
Return a new instance of the :class:`FTP` class. When *host* is given, the
4749
method call ``connect(host)`` is made. When *user* is given, additionally
@@ -50,7 +52,8 @@ The module defines the following items:
5052
parameter specifies a timeout in seconds for blocking operations like the
5153
connection attempt (if is not specified, the global default timeout setting
5254
will be used). *source_address* is a 2-tuple ``(host, port)`` for the socket
53-
to bind to as its source address before connecting.
55+
to bind to as its source address before connecting. The *encoding* parameter
56+
specifies the encoding for directories and filenames.
5457

5558
The :class:`FTP` class supports the :keyword:`with` statement, e.g.:
5659

@@ -74,9 +77,11 @@ The module defines the following items:
7477

7578
.. versionchanged:: 3.9
7679
If the *timeout* parameter is set to be zero, it will raise a
77-
:class:`ValueError` to prevent the creation of a non-blocking socket
80+
:class:`ValueError` to prevent the creation of a non-blocking socket.
81+
The *encoding* parameter was added, and the default was changed from
82+
Latin-1 to UTF-8 to follow :rfc:`2640`.
7883

79-
.. class:: FTP_TLS(host='', user='', passwd='', acct='', keyfile=None, certfile=None, context=None, timeout=None, source_address=None)
84+
.. class:: FTP_TLS(host='', user='', passwd='', acct='', keyfile=None, certfile=None, context=None, timeout=None, source_address=None, *, encoding='utf-8')
8085

8186
A :class:`FTP` subclass which adds TLS support to FTP as described in
8287
:rfc:`4217`.
@@ -110,7 +115,9 @@ The module defines the following items:
110115

111116
.. versionchanged:: 3.9
112117
If the *timeout* parameter is set to be zero, it will raise a
113-
:class:`ValueError` to prevent the creation of a non-blocking socket
118+
:class:`ValueError` to prevent the creation of a non-blocking socket.
119+
The *encoding* parameter was added, and the default was changed from
120+
Latin-1 to UTF-8 to follow :rfc:`2640`.
114121

115122
Here's a sample session using the :class:`FTP_TLS` class::
116123

@@ -259,9 +266,10 @@ followed by ``lines`` for the text version or ``binary`` for the binary version.
259266

260267
.. method:: FTP.retrlines(cmd, callback=None)
261268

262-
Retrieve a file or directory listing in ASCII transfer mode. *cmd* should be
263-
an appropriate ``RETR`` command (see :meth:`retrbinary`) or a command such as
264-
``LIST`` or ``NLST`` (usually just the string ``'LIST'``).
269+
Retrieve a file or directory listing in the encoding specified by the
270+
*encoding* parameter at initialization.
271+
*cmd* should be an appropriate ``RETR`` command (see :meth:`retrbinary`) or
272+
a command such as ``LIST`` or ``NLST`` (usually just the string ``'LIST'``).
265273
``LIST`` retrieves a list of files and information about those files.
266274
``NLST`` retrieves a list of file names.
267275
The *callback* function is called for each line with a string argument
@@ -291,7 +299,7 @@ followed by ``lines`` for the text version or ``binary`` for the binary version.
291299

292300
.. method:: FTP.storlines(cmd, fp, callback=None)
293301

294-
Store a file in ASCII transfer mode. *cmd* should be an appropriate
302+
Store a file in line mode. *cmd* should be an appropriate
295303
``STOR`` command (see :meth:`storbinary`). Lines are read until EOF from the
296304
:term:`file object` *fp* (opened in binary mode) using its :meth:`~io.IOBase.readline`
297305
method to provide the data to be stored. *callback* is an optional single
@@ -309,10 +317,9 @@ followed by ``lines`` for the text version or ``binary`` for the binary version.
309317
If optional *rest* is given, a ``REST`` command is sent to the server, passing
310318
*rest* as an argument. *rest* is usually a byte offset into the requested file,
311319
telling the server to restart sending the file's bytes at the requested offset,
312-
skipping over the initial bytes. Note however that :rfc:`959` requires only that
313-
*rest* be a string containing characters in the printable range from ASCII code
314-
33 to ASCII code 126. The :meth:`transfercmd` method, therefore, converts
315-
*rest* to a string, but no check is performed on the string's contents. If the
320+
skipping over the initial bytes. Note however that the :meth:`transfercmd`
321+
method converts *rest* to a string with the *encoding* parameter specified
322+
at initialization, but no check is performed on the string's contents. If the
316323
server does not recognize the ``REST`` command, an :exc:`error_reply` exception
317324
will be raised. If this happens, simply call :meth:`transfercmd` without a
318325
*rest* argument.

Doc/whatsnew/3.9.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,9 @@ Changes in the Python API
790790
environment variable when the :option:`-E` or :option:`-I` command line
791791
options are being used.
792792

793+
* The *encoding* parameter has been added to the classes :class:`ftplib.FTP` and
794+
:class:`ftplib.FTP_TLS` as a keyword-only parameter, and the default encoding
795+
is changed from Latin-1 to UTF-8 to follow :rfc:`2640`.
793796

794797
CPython bytecode changes
795798
------------------------

Lib/ftplib.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,14 @@ class FTP:
7575
'''An FTP client class.
7676
7777
To create a connection, call the class using these arguments:
78-
host, user, passwd, acct, timeout
78+
host, user, passwd, acct, timeout, source_address, encoding
7979
8080
The first four arguments are all strings, and have default value ''.
81-
timeout must be numeric and defaults to None if not passed,
82-
meaning that no timeout will be set on any ftp socket(s)
81+
The parameter ´timeout´ must be numeric and defaults to None if not
82+
passed, meaning that no timeout will be set on any ftp socket(s).
8383
If a timeout is passed, then this is now the default timeout for all ftp
8484
socket operations for this instance.
85+
The last parameter is the encoding of filenames, which defaults to utf-8.
8586
8687
Then use self.connect() with optional host and port argument.
8788
@@ -102,15 +103,16 @@ class FTP:
102103
file = None
103104
welcome = None
104105
passiveserver = 1
105-
encoding = "latin-1"
106106

107107
def __init__(self, host='', user='', passwd='', acct='',
108-
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
108+
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *,
109+
encoding='utf-8'):
109110
"""Initialization method (called by class instantiation).
110111
Initialize host to localhost, port to standard ftp port.
111112
Optional arguments are host (for connect()),
112113
and user, passwd, acct (for login()).
113114
"""
115+
self.encoding = encoding
114116
self.source_address = source_address
115117
self.timeout = timeout
116118
if host:
@@ -706,9 +708,10 @@ class FTP_TLS(FTP):
706708
'''
707709
ssl_version = ssl.PROTOCOL_TLS_CLIENT
708710

709-
def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
710-
certfile=None, context=None,
711-
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None):
711+
def __init__(self, host='', user='', passwd='', acct='',
712+
keyfile=None, certfile=None, context=None,
713+
timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *,
714+
encoding='utf-8'):
712715
if context is not None and keyfile is not None:
713716
raise ValueError("context and keyfile arguments are mutually "
714717
"exclusive")
@@ -727,7 +730,8 @@ def __init__(self, host='', user='', passwd='', acct='', keyfile=None,
727730
keyfile=keyfile)
728731
self.context = context
729732
self._prot_p = False
730-
super().__init__(host, user, passwd, acct, timeout, source_address)
733+
super().__init__(host, user, passwd, acct,
734+
timeout, source_address, encoding=encoding)
731735

732736
def login(self, user='', passwd='', acct='', secure=True):
733737
if secure and not isinstance(self.sock, ssl.SSLSocket):

0 commit comments

Comments
 (0)