<div dir="ltr"><div><div>> Well, one of your main arguments was that the Windows API follows these best fit encodings.<br><br></div>No, that wasn't me, that was Ivan. My argument has been based on compatibility with Web technologies; I wanted these encodings before I knew what Windows did (and now what Windows does kind of horrifies me).<br><br></div>Calling a register() function makes flake8 happy, at the cost of convenience, but it still has no clear connection to the place where you use the registered encodings.<br></div><br><div class="gmail_quote"><div dir="ltr">On Wed, 10 Jan 2018 at 14:57 M.-A. Lemburg <<a href="mailto:mal@egenix.com">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 20:13, Rob Speer wrote:<br>
> I was originally proposing these encodings under different names, and<br>
> that's what I think they should have. Indeed, that helps because a pip<br>
> installable library can backport the new encodings to previous versions of<br>
> Python.<br>
><br>
> Having a pip installable library as the _only_ way to use these encodings<br>
> is the status quo that I am very familiar with. It's awkward. To use a<br>
> package that registers new codecs, you have to import something from that<br>
> package, even if you never call anything from what you imported, and that<br>
> makes flake8 complain. The idea that an encoding name may or may not be<br>
> registered, based on what has been imported, breaks our intuition about<br>
> reading Python code and is very hard to statically analyze.<br>
<br>
You can have a function in the package which registers the<br>
codecs. That way you do have a call into the library and intuition<br>
is restored :-) (and flake should be happy as well):<br>
<br>
import mycodecs<br>
mycodecs.register()<br>
<br>
> I disagree with calling the WHATWG encodings that are implemented in every<br>
> Web browser "non-standard". WHATWG may not have a typical origin story as a<br>
> standards organization, but it _is_ the standards organization for the Web.<br>
<br>
I don't really want to get into a discussion here. Browsers<br>
use these modified encodings to cope with mojibake or web content<br>
which isn't quite standard compliant. That's a valid use case,<br>
but promoting such wrong use by having work-around encodings in<br>
the stdlib and having Python produce non-standard output<br>
doesn't strike me as a good way forward. We do have error handlers<br>
for dealing with partially corrupted data. I think that's good<br>
enough.<br>
<br>
> I'm really not interested in best-fit mappings that turn infinity into "8"<br>
> and square roots into "v". Making weird mappings like that sounds like a<br>
> job for the "unidecode" library, not the stdlib.<br>
<br>
Well, one of your main arguments was that the Windows API follows<br>
these best fit encodings.<br>
<br>
I agree that best fit may not necessarily be best fit for<br>
everyone :-)<br>
<br>
<br>
> On Wed, 10 Jan 2018 at 13:36 Rob Speer <<a href="mailto:rspeer@luminoso.com" target="_blank">rspeer@luminoso.com</a>> wrote:<br>
><br>
>> I'm looking at the documentation of "best fit" mappings, and that seems to<br>
>> be a different matter. It appears that best-fit mappings are designed to be<br>
>> many-to-one mappings used only for encoding.<br>
>><br>
>> "Examples of best fit are converting fullwidth letters to their<br>
>> counterparts when converting to single byte code pages, and mapping the<br>
>> Infinity character to the number 8." (Mapping ∞ to 8? Seriously?!) It also<br>
>> does things such as mapping Cyrillic letters to Latin letters that look<br>
>> like them.<br>
>><br>
>> This is not what I'm interested in implementing. I just want there to be<br>
>> encodings that match the WHATWG encodings exactly. If they have to be given<br>
>> a different name, that's fine with me.<br>
>><br>
>> 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>
>><br>
>>> On 10.01.2018 00:56, Rob Speer wrote:<br>
>>>> Oh that's interesting. So it seems to be Python that's the exception<br>
>>> here.<br>
>>>><br>
>>>> Would we really be able to add entries to character mappings that<br>
>>> 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>
>>><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>
>>><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<br>
>>> 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<br>
>>> 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<br>
>>> if<br>
>>>>> you ask a Web browser to decode "iso-8859-1" or "windows-1252", you<br>
>>> will<br>
>>>>> get this encoding _instead_. It is probably the second or third most<br>
>>> 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<br>
>>> are<br>
>>>>> undefined:<br>
>>>>><br>
>>>>>>>> b'\x90'.decode('windows-1252')<br>
>>>>> UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position<br>
>>> 0:<br>
>>>>> character maps to <undefined><br>
>>>>><br>
>>>>> In web-1252, the bytes that are undefined according to windows-1252<br>
>>> 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,<br>
>>> 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>
>>>>> <<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>
>>>><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<br>
>>> 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<br>
>>> 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<br>
>>> a<br>
>>>>> Unicode data-cleaning library, "ftfy". One thing it does is to detect<br>
>>> 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<br>
>>> 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<br>
>>> 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<br>
>>> text as<br>
>>>>> "sloppy-windows-1252" (the name I chose for this encoding), for<br>
>>> example.<br>
>>>>><br>
>>>>> ftfy can tell people a sequence of steps that they can use in the<br>
>>> 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<br>
>>> not<br>
>>>>> using the features of ftfy.<br>
>>>>><br>
>>>>> Support for these encodings also seems highly relevant to people who<br>
>>> use<br>
>>>>> Python for web scraping, as it would be desirable to maximize<br>
>>> compatibility<br>
>>>>> with what a Web browser would do.<br>
>>>>><br>
>>>>> This really seems like it belongs in the standard library instead of<br>
>>> 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://<br>
>>> <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>
>>><br>
>><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>
<br>
</blockquote></div>