<div dir="ltr"><div><div>I was originally proposing these encodings under different names, and that's what I think they should have. Indeed, that helps because a pip installable library can backport the new encodings to previous versions of Python.<br></div><div><br></div><div><div>Having a pip installable library as the _only_ way to use
these encodings is the status quo that I am very familiar with. It's awkward. To use a package that 
registers new codecs, you have to import something from that package, 
even if you never call anything from what you imported, and that makes 
flake8 complain. The idea that an encoding name may or may not be registered, based on what has been imported, breaks our intuition about reading Python code and is very hard to statically analyze.<br></div><div><br></div>I disagree with calling the WHATWG encodings that are implemented in every Web browser "non-standard". WHATWG may not have a typical origin story as a standards organization, but it _is_ the standards organization for the Web.<br></div></div><div><br></div>I'm really not interested in best-fit mappings that turn infinity into "8" and square roots into "v". Making weird mappings like that sounds like a job for the "unidecode" library, not the stdlib.</div><br><div class="gmail_quote"><div dir="ltr">On Wed, 10 Jan 2018 at 13:36 Rob Speer <<a href="mailto:rspeer@luminoso.com">rspeer@luminoso.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div><div>I'm looking at the documentation of "best fit" mappings, and that seems to be a different matter. It appears that best-fit mappings are designed to be many-to-one mappings used only for encoding.<br><br>"Examples of best fit are converting fullwidth letters to their counterparts when converting to single byte code pages, and mapping the Infinity character to the number 8." (Mapping ∞ to 8? Seriously?!) It also does things such as mapping Cyrillic letters to Latin letters that look like them.<br></div></div><br></div>This is not what I'm interested in implementing. I just want there to be encodings that match the WHATWG encodings exactly. If they have to be given a different name, that's fine with me.<br></div><br><div class="gmail_quote"><div dir="ltr">On Wed, 10 Jan 2018 at 03:38 M.-A. Lemburg <<a href="mailto:mal@egenix.com" target="_blank">mal@egenix.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 10.01.2018 00:56, Rob Speer wrote:<br>
> Oh that's interesting. So it seems to be Python that's the exception here.<br>
><br>
> Would we really be able to add entries to character mappings that haven't<br>
> changed since Python 2.0?<br>
<br>
The Windows mappings in Python come directly from the Unicode<br>
Consortium mapping files.<br>
<br>
If the Consortium changes the mappings, we can update them.<br>
<br>
If not, then we have a problem, since consumers are not only<br>
the win32 APIs, but also other tools out there running on<br>
completely different platforms, e.g. Java tools or web servers<br>
providing downloads using the Windows code page encodings.<br>
<br>
Allowing such mappings in the existing codecs would then result<br>
failures when the "other" sides see the decoded Unicode version and<br>
try to encode back into the original encoding - you'd move the<br>
problem from the Python side to the "other" side of the<br>
integration.<br>
<br>
I had a look on the Unicode FTP site and they have since added<br>
a new directory with mapping files they call "best fit":<br>
<br>
<a href="http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/readme.txt" rel="noreferrer" target="_blank">http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/readme.txt</a><br>
<br>
The WideCharToMultiByte() defaults to best fit, but also offers<br>
a mode where it operates in standards compliant mode:<br>
<br>
<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx" rel="noreferrer" target="_blank">https://msdn.microsoft.com/en-us/library/windows/desktop/dd374130%28v=vs.85%29.aspx</a><br>
<br>
See flag WC_NO_BEST_FIT_CHARS.<br>
<br>
Unicode TR#22 is also clear on this:<br>
<br>
<a href="https://www.unicode.org/reports/tr22/tr22-3.html#Illegal_and_Unassigned" rel="noreferrer" target="_blank">https://www.unicode.org/reports/tr22/tr22-3.html#Illegal_and_Unassigned</a><br>
<br>
It allows such best fit mappings to make encodings round-trip<br>
safe, but requires to keep these separate from the original<br>
standard mappings:<br>
<br>
"""<br>
It is very important that systems be able to distinguish between the<br>
fallback mappings and regular mappings. Systems like XML require the use<br>
of hex escape sequences (NCRs) to preserve round-trip integrity; use of<br>
fallback characters in that case corrupts the data.<br>
"""<br>
<br>
If you read the above section in TR#22 you quickly get reminded<br>
of what the Unicode error handlers do (we basically implement<br>
the three modes it mentions... raise, ignore, replace).<br>
<br>
Now, for unmapped sequences an error handler can opt for<br>
using a fallback sequence instead.<br>
<br>
So in addition to adding best fit codecs, there's also the<br>
option to add an error handler for best fit resolution of<br>
unmapped sequences.<br>
<br>
Given the above, I don't think we ought to change the existing<br>
standards compliant mappings, but use one of two solutions:<br>
<br>
a) add "best fit" encodings (see the Unicode FTP site for<br>
   a list)<br>
<br>
b) add an error handlers "bestfit" which implements the<br>
   fallback modes for the encodings in question<br>
<br>
<br>
> On Tue, 9 Jan 2018 at 16:53 Ivan Pozdeev via Python-ideas <<br>
> <a href="mailto:python-ideas@python.org" target="_blank">python-ideas@python.org</a>> wrote:<br>
><br>
>> First of all, many thanks for such a excellently writen letter. It was a<br>
>> real pleasure to read.<br>
>> On 10.01.2018 0:15, Rob Speer wrote:<br>
>><br>
>> Hi! I joined this list because I'm interested in filling a gap in Python's<br>
>> standard library, relating to text encodings.<br>
>><br>
>> There is an encoding with no name of its own. It's supported by every<br>
>> current web browser and standardized by WHATWG. It's so prevalent that if<br>
>> you ask a Web browser to decode "iso-8859-1" or "windows-1252", you will<br>
>> get this encoding _instead_. It is probably the second or third most common<br>
>> text encoding in the world. And Python doesn't quite support it.<br>
>><br>
>> You can see the character table for this encoding at:<br>
>> <a href="https://encoding.spec.whatwg.org/index-windows-1252.txt" rel="noreferrer" target="_blank">https://encoding.spec.whatwg.org/index-windows-1252.txt</a><br>
>><br>
>> For the sake of discussion, let's call this encoding "web-1252". WHATWG<br>
>> calls it "windows-1252", but notice that it's subtly different from<br>
>> Python's "windows-1252" encoding. Python's windows-1252 has bytes that are<br>
>> undefined:<br>
>><br>
>>>>> b'\x90'.decode('windows-1252')<br>
>> UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 0:<br>
>> character maps to <undefined><br>
>><br>
>> In web-1252, the bytes that are undefined according to windows-1252 map to<br>
>> the control characters in those positions in iso-8859-1 -- that is, the<br>
>> Unicode codepoints with the same number as the byte. In web-1252, b'\x90'<br>
>> would decode as '\u0090'.<br>
>><br>
>> According to <a href="https://en.wikipedia.org/wiki/Windows-1252" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Windows-1252</a> , Windows does<br>
>> the same:<br>
>><br>
>>     "According to the information on Microsoft's and the Unicode<br>
>> Consortium's websites, positions 81, 8D, 8F, 90, and 9D are unused;<br>
>> however, the Windows API MultiByteToWideChar<br>
>> <<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072%28v=vs.85%29.aspx" rel="noreferrer" target="_blank">http://msdn.microsoft.com/en-us/library/windows/desktop/dd319072%28v=vs.85%29.aspx</a>><br>
>> maps these to the corresponding C1 control codes<br>
>> <<a href="https://en.wikipedia.org/wiki/C0_and_C1_control_codes" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/C0_and_C1_control_codes</a>>."<br>
>> And in ISO-8859-1, the same handling is done for unused code points even<br>
>> by the standard ( <a href="https://en.wikipedia.org/wiki/ISO/IEC_8859-1" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/ISO/IEC_8859-1</a> ) :<br>
>><br>
>>     "*ISO-8859-1* is the IANA<br>
>> <<a href="https://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Internet_Assigned_Numbers_Authority</a>><br>
>> preferred name for this standard when supplemented with the C0 and C1<br>
>> control codes <<a href="https://en.wikipedia.org/wiki/C0_and_C1_control_codes" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/C0_and_C1_control_codes</a>><br>
>> from ISO/IEC 6429 <<a href="https://en.wikipedia.org/wiki/ISO/IEC_6429" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/ISO/IEC_6429</a>>"<br>
>> And what would you think -- these "C1 control codes" are also the<br>
>> corresponding Unicode points! (<br>
>> <a href="https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)" rel="noreferrer" target="_blank">https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)</a> )<br>
>><br>
>> Since Windows is pretty much the reference implementation for<br>
>> "windows-xxxx" encodings, it even makes sense to alter the existing<br>
>> encodings rather than add new ones.<br>
>><br>
>><br>
>> This may seem like a silly encoding that encourages doing horrible things<br>
>> with text. That's pretty much the case. But there's a reason every Web<br>
>> browser implements it:<br>
>><br>
>> - It's compatible with windows-1252<br>
>> - Any sequence of bytes can be round-tripped through it without losing<br>
>> information<br>
>><br>
>> It's not just this one encoding. WHATWG's encoding standard (<br>
>> <a href="https://encoding.spec.whatwg.org/" rel="noreferrer" target="_blank">https://encoding.spec.whatwg.org/</a>) contains modified versions of<br>
>> windows-1250 through windows-1258 and windows-874.<br>
>><br>
>> Support for these encodings matters to me, in part, because I maintain a<br>
>> Unicode data-cleaning library, "ftfy". One thing it does is to detect and<br>
>> undo encoding/decoding errors that cause mojibake, as long as they're<br>
>> detectible and reversible. Looking at real-world examples of text that has<br>
>> been damaged by mojibake, it's clear that lots of text is transferred<br>
>> through what I'm calling the "web-1252" encoding, in a way that's<br>
>> incompatible with Python's "windows-1252".<br>
>><br>
>> In order to be able to work with and fix this kind of text, ftfy registers<br>
>> new codecs -- and I implemented this even before I knew that they were<br>
>> standardized in Web browsers. When ftfy is imported, you can decode text as<br>
>> "sloppy-windows-1252" (the name I chose for this encoding), for example.<br>
>><br>
>> ftfy can tell people a sequence of steps that they can use in the future<br>
>> to fix text that's like the text they provided. Very often, these steps<br>
>> require the sloppy-windows-1252 or sloppy-windows-1251 encoding, which<br>
>> means the steps only work with ftfy imported, even for people who are not<br>
>> using the features of ftfy.<br>
>><br>
>> Support for these encodings also seems highly relevant to people who use<br>
>> Python for web scraping, as it would be desirable to maximize compatibility<br>
>> with what a Web browser would do.<br>
>><br>
>> This really seems like it belongs in the standard library instead of being<br>
>> an incidental feature of my library. I know that code in the standard<br>
>> library has "one foot in the grave". I _want_ these legacy encodings to<br>
>> have one foot in the grave. But some of them are extremely common, and<br>
>> Python code should be able to deal with them.<br>
>><br>
>> Adding these encodings to Python would be straightforward to implement.<br>
>> Does this require a PEP, a pull request, or further discussion?<br>
>><br>
>><br>
>> _______________________________________________<br>
>> Python-ideas mailing listPython-ideas@python.orghttps://<a href="http://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">mail.python.org/mailman/listinfo/python-ideas</a><br>
>> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
>><br>
>><br>
>> --<br>
>> Regards,<br>
>> Ivan<br>
>><br>
>> _______________________________________________<br>
>> Python-ideas mailing list<br>
>> <a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
>> <a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
>> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
>><br>
><br>
><br>
><br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
><br>
<br>
--<br>
Marc-Andre Lemburg<br>
eGenix.com<br>
<br>
Professional Python Services directly from the Experts (#1, Jan 10 2018)<br>
>>> Python Projects, Coaching and Consulting ...  <a href="http://www.egenix.com/" rel="noreferrer" target="_blank">http://www.egenix.com/</a><br>
>>> Python Database Interfaces ...           <a href="http://products.egenix.com/" rel="noreferrer" target="_blank">http://products.egenix.com/</a><br>
>>> Plone/Zope Database Interfaces ...           <a href="http://zope.egenix.com/" rel="noreferrer" target="_blank">http://zope.egenix.com/</a><br>
________________________________________________________________________<br>
<br>
::: We implement business ideas - efficiently in both time and costs :::<br>
<br>
   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48<br>
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg<br>
           Registered at Amtsgericht Duesseldorf: HRB 46611<br>
               <a href="http://www.egenix.com/company/contact/" rel="noreferrer" target="_blank">http://www.egenix.com/company/contact/</a><br>
                      <a href="http://www.malemburg.com/" rel="noreferrer" target="_blank">http://www.malemburg.com/</a><br>
</blockquote></div></blockquote></div>