<div dir="ltr">Accepted. Congrats with marshalling yet another quite contentious discussion, and putting up with my last-minute block-headedness!<br><br>If you're going to commit another change, may I suggest to add, to the section stating that %r is not supported, that %a is usually a suitable replacement for %r?<br>

</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Mar 27, 2014 at 1:07 PM, Ethan Furman <span dir="ltr"><<a href="mailto:ethan@stoneleaf.us" target="_blank">ethan@stoneleaf.us</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Requesting pronouncement on PEP 461.  Full text below.<br>
<br>
==============================<u></u>==============================<u></u>===================<br>
PEP: 461<br>
Title: Adding % formatting to bytes and bytearray<br>
Version: $Revision$<br>
Last-Modified: $Date$<br>
Author: Ethan Furman <<a href="mailto:ethan@stoneleaf.us" target="_blank">ethan@stoneleaf.us</a>><br>
Status: Draft<br>
Type: Standards Track<br>
Content-Type: text/x-rst<br>
Created: 2014-01-13<br>
Python-Version: 3.5<br>
Post-History: 2014-01-14, 2014-01-15, 2014-01-17, 2014-02-22, 2014-03-25,<br>
              2014-03-27<br>
Resolution:<br>
<br>
<br>
Abstract<br>
========<br>
<br>
This PEP proposes adding % formatting operations similar to Python 2's ``str``<br>
type to ``bytes`` and ``bytearray`` [1]_ [2]_.<br>
<br>
<br>
Rationale<br>
=========<br>
<br>
While interpolation is usually thought of as a string operation, there are<br>
cases where interpolation on ``bytes`` or ``bytearrays`` make sense, and the<br>
work needed to make up for this missing functionality detracts from the overall<br>
readability of the code.<br>
<br>
<br>
Motivation<br>
==========<br>
<br>
With Python 3 and the split between ``str`` and ``bytes``, one small but<br>
important area of programming became slightly more difficult, and much more<br>
painful -- wire format protocols [3]_.<br>
<br>
This area of programming is characterized by a mixture of binary data and<br>
ASCII compatible segments of text (aka ASCII-encoded text).  Bringing back a<br>
restricted %-interpolation for ``bytes`` and ``bytearray`` will aid both in<br>
writing new wire format code, and in porting Python 2 wire format code.<br>
<br>
Common use-cases include ``dbf`` and ``pdf`` file formats, ``email``<br>
formats, and ``FTP`` and ``HTTP`` communications, among many others.<br>
<br>
<br>
Proposed semantics for ``bytes`` and ``bytearray`` formatting<br>
==============================<u></u>==============================<u></u>=<br>
<br>
%-interpolation<br>
---------------<br>
<br>
All the numeric formatting codes (``d``, ``i``, ``o``, ``u``, ``x``, ``X``,<br>
``e``, ``E``, ``f``, ``F``, ``g``, ``G``, and any that are subsequently added<br>
to Python 3) will be supported, and will work as they do for str, including<br>
the padding, justification and other related modifiers (currently ``#``, ``0``,<br>
``-``, `` `` (space), and ``+`` (plus any added to Python 3)).  The only<br>
non-numeric codes allowed are ``c``, ``b``, ``a``, and ``s`` (which is a<br>
synonym for b).<br>
<br>
For the numeric codes, the only difference between ``str`` and ``bytes`` (or<br>
``bytearray``) interpolation is that the results from these codes will be<br>
ASCII-encoded text, not unicode.  In other words, for any numeric formatting<br>
code `%x`::<br>
<br>
   b"%x" % val<br>
<br>
is equivalent to::<br>
<br>
   ("%x" % val).encode("ascii")<br>
<br>
Examples::<br>
<br>
   >>> b'%4x' % 10<br>
   b'   a'<br>
<br>
   >>> b'%#4x' % 10<br>
   ' 0xa'<br>
<br>
   >>> b'%04X' % 10<br>
   '000A'<br>
<br>
``%c`` will insert a single byte, either from an ``int`` in range(256), or from<br>
a ``bytes`` argument of length 1, not from a ``str``.<br>
<br>
Examples::<br>
<br>
    >>> b'%c' % 48<br>
    b'0'<br>
<br>
    >>> b'%c' % b'a'<br>
    b'a'<br>
<br>
``%b`` will insert a series of bytes.  These bytes are collected in one of two<br>
ways:<br>
<br>
  - input type supports ``Py_buffer`` [4]_?<br>
    use it to collect the necessary bytes<br>
<br>
  - input type is something else?<br>
    use its ``__bytes__`` method [5]_ ; if there isn't one, raise a ``TypeError``<br>
<br>
In particular, ``%b`` will not accept numbers nor ``str``.  ``str`` is rejected<br>
as the string to bytes conversion requires an encoding, and we are refusing to<br>
guess; numbers are rejected because:<br>
<br>
  - what makes a number is fuzzy (float? Decimal? Fraction? some user type?)<br>
<br>
  - allowing numbers would lead to ambiguity between numbers and textual<br>
    representations of numbers (3.14 vs '3.14')<br>
<br>
  - given the nature of wire formats, explicit is definitely better than implicit<br>
<br>
``%s`` is included as a synonym for ``%b`` for the sole purpose of making 2/3 code<br>
bases easier to maintain.  Python 3 only code should use ``%b``.<br>
<br>
Examples::<br>
<br>
    >>> b'%b' % b'abc'<br>
    b'abc'<br>
<br>
    >>> b'%b' % 'some string'.encode('utf8')<br>
    b'some string'<br>
<br>
    >>> b'%b' % 3.14<br>
    Traceback (most recent call last):<br>
    ...<br>
    TypeError: b'%b' does not accept 'float'<br>
<br>
    >>> b'%b' % 'hello world!'<br>
    Traceback (most recent call last):<br>
    ...<br>
    TypeError: b'%b' does not accept 'str'<br>
<br>
<br>
``%a`` will give the equivalent of<br>
``repr(some_obj).encode('<u></u>ascii', 'backslashreplace')`` on the interpolated<br>
value.  Use cases include developing a new protocol and writing landmarks<br>
into the stream; debugging data going into an existing protocol to see if<br>
the problem is the protocol itself or bad data; a fall-back for a serialization<br>
format; or any situation where defining ``__bytes__`` would not be appropriate<br>
but a readable/informative representation is needed [6]_.<br>
<br>
Examples::<br>
<br>
    >>> b'%a' % 3.14<br>
    b'3.14'<br>
<br>
    >>> b'%a' % b'abc'<br>
    b"b'abc'"<br>
<br>
    >>> b'%a' % 'def'<br>
    b"'def'"<br>
<br>
<br>
Unsupported codes<br>
-----------------<br>
<br>
``%r`` (which calls ``__repr__`` and returns a ``str``) is not supported.<br>
<br>
<br>
Compatibility with Python 2<br>
===========================<br>
<br>
As noted above, ``%s`` is being included solely to help ease migration from,<br>
and/or have a single code base with, Python 2.  This is important as there<br>
are modules both in the wild and behind closed doors that currently use the<br>
Python 2 ``str`` type as a ``bytes`` container, and hence are using ``%s``<br>
as a bytes interpolator.<br>
<br>
However, ``%b`` should be used in new, Python 3 only code, so ``%s`` will<br>
immediately be deprecated, but not removed until the next major Python<br>
release.<br>
<br>
<br>
Proposed variations<br>
===================<br>
<br>
It has been proposed to automatically use ``.encode('ascii','strict')`` for<br>
``str`` arguments to ``%b``.<br>
<br>
  - Rejected as this would lead to intermittent failures.  Better to have the<br>
    operation always fail so the trouble-spot can be correctly fixed.<br>
<br>
It has been proposed to have ``%b`` return the ascii-encoded repr when the<br>
value is a ``str`` (b'%b' % 'abc'  --> b"'abc'").<br>
<br>
  - Rejected as this would lead to hard to debug failures far from the problem<br>
    site.  Better to have the operation always fail so the trouble-spot can be<br>
    easily fixed.<br>
<br>
Originally this PEP also proposed adding format-style formatting, but it was<br>
decided that format and its related machinery were all strictly text (aka<br>
``str``) based, and it was dropped.<br>
<br>
Various new special methods were proposed, such as ``__ascii__``,<br>
``__format_bytes__``, etc.; such methods are not needed at this time, but can<br>
be visited again later if real-world use shows deficiencies with this solution.<br>
<br>
A competing PEP, ``PEP 460 Add binary interpolation and formatting`` [7]_,<br>
also exists.<br>
<br>
<br>
Objections<br>
==========<br>
<br>
The objections raised against this PEP were mainly variations on two themes:<br>
<br>
  - the ``bytes`` and ``bytearray`` types are for pure binary data, with no<br>
    assumptions about encodings<br>
<br>
  - offering %-interpolation that assumes an ASCII encoding will be an<br>
    attractive nuisance and lead us back to the problems of the Python 2<br>
    ``str``/``unicode`` text model<br>
<br>
As was seen during the discussion, ``bytes`` and ``bytearray`` are also used<br>
for mixed binary data and ASCII-compatible segments: file formats such as<br>
``dbf`` and ``pdf``, network protocols such as ``ftp`` and ``email``, etc.<br>
<br>
``bytes`` and ``bytearray`` already have several methods which assume an ASCII<br>
compatible encoding.  ``upper()``, ``isalpha()``, and ``expandtabs()`` to name<br>
just a few.  %-interpolation, with its very restricted mini-language, will not<br>
be any more of a nuisance than the already existing methods.<br>
<br>
Some have objected to allowing the full range of numeric formatting codes with<br>
the claim that decimal alone would be sufficient.  However, at least two<br>
formats (dbf and pdf) make use of non-decimal numbers.<br>
<br>
<br>
Footnotes<br>
=========<br>
<br>
.. [1] <a href="http://docs.python.org/2/library/stdtypes.html#string-formatting" target="_blank">http://docs.python.org/2/<u></u>library/stdtypes.html#string-<u></u>formatting</a><br>
.. [2] neither string.Template, format, nor str.format are under consideration<br>
.. [3] <a href="https://mail.python.org/pipermail/python-dev/2014-January/131518.html" target="_blank">https://mail.python.org/<u></u>pipermail/python-dev/2014-<u></u>January/131518.html</a><br>
.. [4] <a href="http://docs.python.org/3/c-api/buffer.html" target="_blank">http://docs.python.org/3/c-<u></u>api/buffer.html</a><br>
       examples:  ``memoryview``, ``array.array``, ``bytearray``, ``bytes``<br>
.. [5] <a href="http://docs.python.org/3/reference/datamodel.html#object.__bytes__" target="_blank">http://docs.python.org/3/<u></u>reference/datamodel.html#<u></u>object.__bytes__</a><br>
.. [6] <a href="https://mail.python.org/pipermail/python-dev/2014-February/132750.html" target="_blank">https://mail.python.org/<u></u>pipermail/python-dev/2014-<u></u>February/132750.html</a><br>
.. [7] <a href="http://python.org/dev/peps/pep-0460/" target="_blank">http://python.org/dev/peps/<u></u>pep-0460/</a><br>
<br>
<br>
Copyright<br>
=========<br>
<br>
This document has been placed in the public domain.<br>
<br>
<br>
..<br>
   Local Variables:<br>
   mode: indented-text<br>
   indent-tabs-mode: nil<br>
   sentence-end-double-space: t<br>
   fill-column: 70<br>
   coding: utf-8<br>
   End:<br>
______________________________<u></u>_________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" target="_blank">https://mail.python.org/<u></u>mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" target="_blank">https://mail.python.org/<u></u>mailman/options/python-dev/<u></u>guido%40python.org</a><br>
</blockquote></div><br><br clear="all"><br>-- <br>--Guido van Rossum (<a href="http://python.org/~guido">python.org/~guido</a>)
</div>