2009-04-22 02:42:06 -04:00
|
|
|
|
PEP: 383
|
|
|
|
|
Title: Non-decodable Bytes in System Character Interfaces
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Martin v. Löwis <martin@v.loewis.de>
|
2009-04-30 12:25:22 -04:00
|
|
|
|
Status: Accepted
|
2009-04-22 02:42:06 -04:00
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 22-Apr-2009
|
|
|
|
|
Python-Version: 3.1
|
|
|
|
|
Post-History:
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
File names, environment variables, and command line arguments are
|
|
|
|
|
defined as being character data in POSIX; the C APIs however allow
|
|
|
|
|
passing arbitrary bytes - whether these conform to a certain encoding
|
|
|
|
|
or not. This PEP proposes a means of dealing with such irregularities
|
|
|
|
|
by embedding the bytes in character strings in such a way that allows
|
|
|
|
|
recreation of the original byte string.
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
The C char type is a data type that is commonly used to represent both
|
|
|
|
|
character data and bytes. Certain POSIX interfaces are specified and
|
|
|
|
|
widely understood as operating on character data, however, the system
|
|
|
|
|
call interfaces make no assumption on the encoding of these data, and
|
|
|
|
|
pass them on as-is. With Python 3, character strings use a
|
|
|
|
|
Unicode-based internal representation, making it difficult to ignore
|
|
|
|
|
the encoding of byte strings in the same way that the C interfaces can
|
|
|
|
|
ignore the encoding.
|
|
|
|
|
|
2009-04-22 15:08:10 -04:00
|
|
|
|
On the other hand, Microsoft Windows NT has corrected the original
|
2009-04-22 02:42:06 -04:00
|
|
|
|
design limitation of Unix, and made it explicit in its system
|
|
|
|
|
interfaces that these data (file names, environment variables, command
|
|
|
|
|
line arguments) are indeed character data, by providing a
|
|
|
|
|
Unicode-based API (keeping a C-char-based one for backwards
|
|
|
|
|
compatibility).
|
|
|
|
|
|
|
|
|
|
For Python 3, one proposed solution is to provide two sets of APIs: a
|
|
|
|
|
byte-oriented one, and a character-oriented one, where the
|
|
|
|
|
character-oriented one would be limited to not being able to represent
|
|
|
|
|
all data accurately. Unfortunately, for Windows, the situation would
|
|
|
|
|
be exactly the opposite: the byte-oriented interface cannot represent
|
|
|
|
|
all data; only the character-oriented API can. As a consequence,
|
|
|
|
|
libraries and applications that want to support all user data in a
|
|
|
|
|
cross-platform manner have to accept mish-mash of bytes and characters
|
|
|
|
|
exactly in the way that caused endless troubles for Python 2.x.
|
|
|
|
|
|
|
|
|
|
With this PEP, a uniform treatment of these data as characters becomes
|
|
|
|
|
possible. The uniformity is achieved by using specific encoding
|
|
|
|
|
algorithms, meaning that the data can be converted back to bytes on
|
|
|
|
|
POSIX systems only if the same encoding is used.
|
|
|
|
|
|
2009-04-25 08:31:23 -04:00
|
|
|
|
Being able to treat such strings uniformly will allow application
|
|
|
|
|
writers to abstract from details specific to the operating system, and
|
|
|
|
|
reduces the risk of one API failing when the other API would have
|
|
|
|
|
worked.
|
|
|
|
|
|
2009-04-22 02:42:06 -04:00
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
|
|
|
|
On Windows, Python uses the wide character APIs to access
|
|
|
|
|
character-oriented APIs, allowing direct conversion of the
|
2009-04-30 03:02:13 -04:00
|
|
|
|
environmental data to Python str objects ([1]).
|
2009-04-22 02:42:06 -04:00
|
|
|
|
|
|
|
|
|
On POSIX systems, Python currently applies the locale's encoding to
|
2009-04-29 16:01:33 -04:00
|
|
|
|
convert the byte data to Unicode, failing for characters that cannot
|
2009-05-03 13:32:27 -04:00
|
|
|
|
be decoded. With this PEP, non-decodable bytes >= 128 will be
|
2009-05-05 17:01:44 -04:00
|
|
|
|
represented as lone surrogate codes U+DC80..U+DCFF. Bytes below
|
2009-04-30 05:50:16 -04:00
|
|
|
|
128 will produce exceptions; see the discussion below.
|
2009-04-22 02:42:06 -04:00
|
|
|
|
|
2009-05-03 04:16:57 -04:00
|
|
|
|
To convert non-decodable bytes, a new error handler ([2]) "utf8b" is
|
2009-05-05 17:01:44 -04:00
|
|
|
|
introduced, which produces these surrogates. On encoding, the error
|
|
|
|
|
handler converts the surrogate back to the corresponding byte. This
|
|
|
|
|
error handler will be used in any API that receives or produces file
|
|
|
|
|
names, command line arguments, or environment variables.
|
2009-04-22 02:42:06 -04:00
|
|
|
|
|
|
|
|
|
The error handler interface is extended to allow the encode error
|
|
|
|
|
handler to return byte strings immediately, in addition to returning
|
2009-04-30 04:34:04 -04:00
|
|
|
|
Unicode strings which then get encoded again (also see the discussion
|
|
|
|
|
below).
|
2009-04-22 02:42:06 -04:00
|
|
|
|
|
2009-04-29 02:26:43 -04:00
|
|
|
|
Byte-orientied interfaces that already exist in Python 3.0 are not
|
|
|
|
|
affected by this specification. They are neither enhanced nor
|
|
|
|
|
deprecated.
|
|
|
|
|
|
2009-04-30 12:24:32 -04:00
|
|
|
|
External libraries that operate on file names (such as GUI file
|
|
|
|
|
chosers) should also encode them according to the PEP.
|
|
|
|
|
|
2009-04-22 02:42:06 -04:00
|
|
|
|
Discussion
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
While providing a uniform API to non-decodable bytes, this interface
|
|
|
|
|
has the limitation that chosen representation only "works" if the data
|
2009-05-06 03:42:38 -04:00
|
|
|
|
get converted back to bytes with the utf8b error handler
|
2009-04-22 02:42:06 -04:00
|
|
|
|
also. Encoding the data with the locale's encoding and the (default)
|
|
|
|
|
strict error handler will raise an exception, encoding them with UTF-8
|
2009-04-30 05:24:24 -04:00
|
|
|
|
will produce non-sensical data.
|
|
|
|
|
|
|
|
|
|
Data obtained from other sources may conflict with data produced
|
|
|
|
|
by this PEP. Dealing with such conflicts is out of scope of the PEP.
|
2009-04-22 02:42:06 -04:00
|
|
|
|
|
2009-04-30 05:50:16 -04:00
|
|
|
|
Encodings that are not compatible with ASCII are not supported by
|
|
|
|
|
this specification; bytes in the ASCII range that fail to decode
|
|
|
|
|
will cause an exception. It is widely agreed that such encodings
|
|
|
|
|
should not be used as locale charsets.
|
|
|
|
|
|
2009-04-22 02:42:06 -04:00
|
|
|
|
For most applications, we assume that they eventually pass data
|
|
|
|
|
received from a system interface back into the same system
|
2009-04-22 15:08:10 -04:00
|
|
|
|
interfaces. For example, an application invoking os.listdir() will
|
2009-04-22 02:42:06 -04:00
|
|
|
|
likely pass the result strings back into APIs like os.stat() or
|
|
|
|
|
open(), which then encodes them back into their original byte
|
|
|
|
|
representation. Applications that need to process the original byte
|
|
|
|
|
strings can obtain them by encoding the character strings with the
|
2009-05-06 03:42:38 -04:00
|
|
|
|
file system encoding, passing "utf8b" as the error handler name. For
|
|
|
|
|
example, a function that works like os.listdir, except for accepting
|
|
|
|
|
and returning bytes, would be written as::
|
2009-04-29 02:26:43 -04:00
|
|
|
|
|
|
|
|
|
def listdir_b(dirname):
|
|
|
|
|
fse = sys.getfilesystemencoding()
|
2009-05-06 03:42:38 -04:00
|
|
|
|
dirname = dirname.decode(fse, "utf8b")
|
2009-04-29 02:26:43 -04:00
|
|
|
|
for fn in os.listdir(dirname):
|
|
|
|
|
# fn is now a str object
|
2009-05-06 03:42:38 -04:00
|
|
|
|
yield fn.encode(fse, "utf8b")
|
2009-04-22 02:42:06 -04:00
|
|
|
|
|
2009-04-30 04:34:04 -04:00
|
|
|
|
The encode error handler interface presently requires replacement
|
|
|
|
|
Unicode to be provide in lieu of the non-encodable Unicode from the
|
|
|
|
|
source string. It promptly encodes that replacement Unicode. In some
|
2009-05-06 03:42:38 -04:00
|
|
|
|
error handlers, such as the utf8 proposed here, it is simpler
|
2009-04-30 04:34:04 -04:00
|
|
|
|
and more efficient for the error handler to provide a pre-encoded
|
|
|
|
|
replacement byte string, rather than forcing it to calculating Unicode
|
|
|
|
|
from which the encoder would create the desired bytes. In fact, with
|
2009-05-06 03:42:38 -04:00
|
|
|
|
utf8b, there are required byte sequences which cannot be
|
2009-04-30 04:34:04 -04:00
|
|
|
|
generated from replacement Unicode.
|
|
|
|
|
|
2009-04-30 05:24:24 -04:00
|
|
|
|
A few alternative approaches have been proposed:
|
|
|
|
|
|
|
|
|
|
* create a new string subclass that supports embedded bytes
|
|
|
|
|
* use different escape schemes, such as escaping with a NUL
|
|
|
|
|
character, or mapping to infrequent characters.
|
2009-04-30 04:34:04 -04:00
|
|
|
|
|
2009-04-30 11:56:46 -04:00
|
|
|
|
Of these proposals, the approach of escaping each byte XX
|
|
|
|
|
with the sequence U+0000 U+00XX has the disadvantage that
|
|
|
|
|
encoding to UTF-8 will introduce a NUL byte in the UTF-8
|
|
|
|
|
sequence. As a consequence, C libraries may interpret this
|
|
|
|
|
as a string termination, even though the string continues.
|
|
|
|
|
In particular, the gtk libraries will truncate text in this
|
|
|
|
|
case; other libraries may show similar problems.
|
|
|
|
|
|
2009-04-30 03:02:13 -04:00
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
|
|
|
|
[1] PEP 277
|
|
|
|
|
"Unicode file name support for Windows NT"
|
|
|
|
|
http://www.python.org/dev/peps/pep-0277/
|
|
|
|
|
|
|
|
|
|
[2] PEP 293
|
|
|
|
|
"Codec Error Handling Callbacks"
|
|
|
|
|
http://www.python.org/dev/peps/pep-0293/
|
|
|
|
|
|
2009-04-22 02:42:06 -04:00
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|