News for hackers. Stuff that matters.
Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @09:09AM (#18154947)
As far as I can tell this is a long-form “I used to be able to ignore encoding issues and now it’s a ‘mess’ because the language is forcing me to be correct”. Each of the examples cited is something which was a source of latent bugs which he thought was working because they were ignored.

Only his third bit of advice isn’t wrong and treating it as something unusual shows the problem: the only safe way to handle text has always been to decode bytes as soon as you get them, work with Unicode, and then encode it when you send them out. Anything else is extremely hard to get right, even if many English-native programmers were used to being able to delay learning why for long periods of time.

Re:The Python Unicode Mess by masklinn on Saturday October 06, 2018 @09:19AM (#18154993)
> As far as I can tell this is a long-form “I used to be able to ignore encoding issues and now it’s a ‘mess’ because the language is forcing me to be correct”.

The problem with that view is that there are things for which you can not be correct, and there are no encoding issues because there is no encoding (or if there is one it does not map to proper unicode):

* UNIX files and paths have no encoding, they're just bags of bytes, with specific bytes (not codepoints, not characters, bytes) having specific meaning

* Windows file and path names are sequences of UTF-16 code units but not actually UTF-16 (they can and do contain unpaired surrogates), as above with specific code units (again not codepoints or characters) having specific meaning

These are issues you will encounter on user systems, there is no "forcing you to be correct". A non-unicode path is not incorrect. On many systems it just is. OSX is one of the few systems where a non-unicode path is actually incorrect, and that means you will not encounter one as input so you have no reason to handle this issue at all.

> Only his third bit of advice isn’t wrong and treating it as something unusual shows the problem: the only safe way to handle text

That's where you fail, and to an extent so does Python: some text-like things are not actually text. Path names famously is one of this case. You're trying to hammer the square peg of path names in the round hole of unicode.

Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @09:29AM (#18155026)
That’s just restating my point: Unix filenames are bytes (on most filesystems, anyway). The fact that many people were able to conflate them with text strings was a convenient fiction. Python no longer allows you to maintain that pretense but it’s easy to deal with by treating them as opaque blobs, attempt to decode and handle errors, or perform manipulations as bytes.
Re:The Python Unicode Mess by izacus on Saturday October 06, 2018 @10:47AM (#18155390)
> That’s just restating my point: Unix filenames are bytes (on most filesystems, anyway). The fact that many people were able to conflate them with text strings was a convenient fiction.

Python tools for backups are my worst terror beacuse of that - they kept destroying data of our clients because they dared (gasp!) name files with characters from their own language or do unthinkable things, like create documents titled "CV - <name with non-unicode characters>.docx".

The fact that Python3 at least tries to make programmers not destroy data as soon as you type in a foreign name (which happens even in USA) is a good thing.

Re:The Python Unicode Mess by guitarbill on Saturday October 06, 2018 @04:51PM (#18157193)
> Python tools for backups are my worst terror beacuse of that

You can have badly written tools in any language. There are even functions to get file paths as bytes (e.g. [os.getcwdb](https://docs.python.org/3/library/os.html#os.getcwdb), it's just most people don't use them because it's rare-ish to see horribly broken filenames and not convenient.

Do other languages get this right 100% of the time on all platforms? I don't think so, it's just you've never noticed.

* C: has no concept of unicode strings per se, may or may not work depending on the implementation and how you choose to display them (CLI probably "works", GUI probably not)

* Rust: seems to assume UTF-8? (https://doc.rust-lang.org/std/ffi/index.html#conversions)

* Go: gets this right, but probably breaks on Windows? "string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text" (https://golang.org/pkg/builtin/#string)

In short, either I don't understand what point you're making, or it isn't unique to Python.

Re:The Python Unicode Mess by Reelin on Saturday October 06, 2018 @09:30PM (#18158375)
Not to bring up one of my favorite languages or anything, but I do think D got this completely right.

https://tour.dlang.org/tour/en/basics/alias-strings

> This means that a plain string is defined as an array of 8-bit Unicode code units. All array operations can be used on strings, but they will work on a code unit level, and not a character level. At the same time, standard library algorithms will interpret strings as sequences of code points, and there is also an option to treat them as sequence of graphemes by explicit usage of std.uni.byGrapheme.

And perhaps my favorite part (https://tour.dlang.org/tour/en/gems/unicode):

> According to the spec, it is an error to store non-Unicode data in the D string types; expect your program to fail in different ways if your string is encoded improperly.

I should note that what I really like about this approach is the total lack of ambiguity. There is no question about what belongs in a string, and if it's not UTF then you had better be using a byte or ubyte array or you are doing it wrong by definition.

Re:The Python Unicode Mess by 1wd on Sunday October 07, 2018 @03:22AM (#18159275)
So in D it's impossible to work with files if their filename is not Unicode?
Re:The Python Unicode Mess by Reelin on Sunday October 07, 2018 @03:53AM (#18159367)
Rather it would be an error to grab a Unix filename, figure your job was done, and store it directly into a string. So you'd... handle things correctly. Somehow. I admit I've never had the bad luck of encountering a non-UTF8 encoded filename under Linux before and can't claim with any confidence that my code would handle it gracefully. In any language, assuming you're using the standard library facilities it provides things will hopefully mostly be taken care of behind the scenes anyway.

What I like about the D approach isn't that declaring it an error actually solves anything directly (obviously it doesn't) but that it removes any ambiguity about how things are expected to work. If the encoding of strings isn't well defined, then if you're writing a library which encodings are the users going to expect you to accept? Or worse, which encodings does that minimally documented library function you're about to call accept?

Re:The Python Unicode Mess by steveklabnik on Saturday October 06, 2018 @04:58PM (#18157234)
OsString/OsStr are not utf-8.
Re:The Python Unicode Mess by guitarbill on Saturday October 06, 2018 @05:15PM (#18157317)
Would you care to elaborate? I'm not claiming to know Rust, but the link I provided clearly says "[t]hese do inexpensive conversions from and to UTF-8 byte slices".
Re:The Python Unicode Mess by steveklabnik on Saturday October 06, 2018 @05:27PM (#18157368)
https://doc.rust-lang.org/std/ffi/struct.OsString.html has it pretty clearly: on unixes it’s a bag of bytes, on Windows it’s the modified UTF-16 they’ve got going on. There’s a trick called WTF-8 that bridges some gaps, though that’s considered an implementation detail: https://simonsapin.github.io/wtf-8/

They’re conversions because they’re not UTF-8 in the first place, that is, they’re not String/str. The conversions are as cheap as we can make them. That language is meant to talk about converting from OsString to String, not from the OS to OsString.

Re:The Python Unicode Mess by mehrdadn on Saturday October 06, 2018 @05:56PM (#18157489)
Why do people say "bag" instead of string/sequence/vector/array/list/etc.? Bags are multisets... they're by definition unordered. It's already a niche technical term so it's really weird to see it used differently in a technical context...
Re:The Python Unicode Mess by steveklabnik on Saturday October 06, 2018 @06:49PM (#18157760)
I think it feels really evocative. Like, a bag of dice or something. You can’t see what’s inside, you have no idea what’s on them. It reinforces the “no encoding” thing well.
Re:The Python Unicode Mess by jschwartzi on Saturday October 06, 2018 @08:44PM (#18158221)
I think it is more eloquently stated that "you shouldn't make assumptions about what's inside." Saying "you can't see what's inside" ignores the biggest cause of the conflation. Userspace tools allow you to trivially interpret the bag of bytes as a text string for the purpose of naming it for other people.
Re:The Python Unicode Mess by steveklabnik on Saturday October 06, 2018 @09:14PM (#18158339)
Yeah, that might be better, good point.
Re:The Python Unicode Mess by ubernostrum on Saturday October 06, 2018 @09:53AM (#18155120)
One thing that amuses me given the number of complaints about the Python 3 string transition is how vastly better Python 3 is for working with bytes. The infrastructure available is light-years ahead of what Python 2 offered, precisely because it gave up on trying to also make bags of bytes be the default string type.
Re:The Python Unicode Mess by ak217 on Saturday October 06, 2018 @10:06AM (#18155166)
Thank you for saying that. Working with strings and bytes in Python 3 is nothing short of a joy compared to the dodgy stuff Python 2 did. People who complain about the change are delusional.
Re:The Python Unicode Mess by necovek on Saturday October 06, 2018 @02:15PM (#18156435)
The only problem I have with Python3 strings/bytes handling is the fact that there are standard library functions which accept bytestrings in Py2 (regular "" strings), and Unicode strings in Py3 (again, regular "" strings in Py3).

This has led to developers attempting to conflate the two distinctly different concepts and make APIs support both while behaving differently.

A simple solution is there in plain sight: just use exclusively b"" and u"" strings for any code you wish to work in both Py2 and Py3, and forget about "". All and any libraries should be using those exclusively if they support both. Python3-only code should be using b"" and "" instead.

One could consider this a design oversight in Python 3: the fact that the syntax is so similar elsewhere makes people want to run the same code in both, yet a core type is basically incompatible.

Re:The Python Unicode Mess by joshuamorton on Saturday October 06, 2018 @02:22PM (#18156468)
u"" is a syntax error in python3 (or at least it was for a while, apparently its not anymore, that said...). The correct cross-platform solution is to do

    from __future__ import unicode_literals
which makes python2 string literals unicode unless declared bytes. Then "" strings are always unicode and b"" strings are always bytes, no matter the language version.
Re:The Python Unicode Mess by ak217 on Saturday October 06, 2018 @03:17PM (#18156741)
> u"" is a syntax error in python3

This has not been the case since 2012. The last release of Python 3 for which this was the case reached end of life in February 2016. Please stop misinforming people.

Re:The Python Unicode Mess by Gorgor on Saturday October 06, 2018 @05:33PM (#18157386)
While u"" is accepted in current Python 3, for some reason they ignored the raw unicode string ur"" which still is a syntax error in Python 3. So, unicode_literals is definitely preferable.
Re:The Python Unicode Mess by masklinn on Sunday October 07, 2018 @06:45AM (#18159927)
> The correct cross-platform solution is to do

It's absolutely not correct, because there are many APIs which take "native strings" across versions aka they take an `str` (byte string) in Python 2 and an `str` (unicode string) in Python 3. unicode_literals causes significantly more problems than they solve.

The correct cross-platform solution (and the very reason why the `u` prefix was reintroduced after having initially been removed from Python 3) is in fact to use b"" for known byte strings, u"" for known text, and "" for "native strings" to interact with APIs which specifically need that.

Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @09:55AM (#18155132)
Agreed. So many of the complaints leave me wanting to suggest that someone try it for longer than 15 minutes and see what they think then.
Re:The Python Unicode Mess by hermitdev on Saturday October 06, 2018 @05:20PM (#18157333)
I haven't noticed much pain from the ASCII -> UNICODE migration from 2->3, but the one thing that still bothers me is that they did not update the CSV module to be transparent. In particular, the need to explicitly set the newline argument to `csv.reader`[0]. For me, dealing with a lot of data translation/extraction/loading work (ETL), this has been a big annoyance in migrating from 2 to 3.

I've not really had many other issues porting from 2 -> 3 from my own code; issues usually arise from 3rd-party libs that are relied upon (especially if they utilize C/C++ extensions). DB libs have sometimes been problematic. IIRC, pysybase requires you to set the encoding of strings now (which wasn't required before). I use pysybase to talk to both Sybase & MS SQL (it talks the TDS protocol).

[0] https://docs.python.org/3/library/csv.html#csv.reader

Re:The Python Unicode Mess by masklinn on Sunday October 07, 2018 @06:50AM (#18159951)
I haven't noticed much pain from the ASCII -> UNICODE migration from 2->3, but the one thing that still bothers me is that they did not update the CSV module to be transparent. In particular, the need to explicitly set the newline argument to `csv.reader`[0]. For me, dealing with a lot of data translation/extraction/loading work (ETL), this has been a big annoyance in migrating from 2 to 3.

???

The Python 3 CSV module works on text only (unicode), and you seem to be misreading the note: the module does in fact do newline transparency: https://docs.python.org/3/library/csv.html#id3

`newline=''` is to be specified on the file so it doesn't perform newline translation, because that would change the semantics of newlines in quoted strings: by default, `open` will universally translate newlines to `\n`, `newline=''` means it still does universal newlines (for purpose of iteration) but it doesn't do translation, returning newline sequences unchanged.

The Python 2 CSV module only worked on byte strings, and magic bytes.

Re:The Python Unicode Mess by marcosdumay on Saturday October 06, 2018 @12:51PM (#18156001)
Edit: I didn't try to handle files with Python for a long time. All of the following is stuff that can change as an ecosystem matures. All that may not hold anymore.

It's better in some ways. But then, I gave up long ago on manipulating files with Python, because Python 3 simply decided that anything on my filesystem is utf-8 by default.

Want to get an stream out of a file? Better have utf-8 content. Otherwise all the documentation will be buried 15 meters deep, outdated on some aspects and dependent on some not-released yet features.

Want to name a file? Better have an utf-8 name. I gave-up on python before I was able to open a file with a name that doesn't conform to utf-8.

Want to read a line at a time? Sorry, we only do that to text. Go get an utf-8 file.

Want to match with a regular expression or parse it somehow? Sorry, we only do that to text.

And so on.

Re:The Python Unicode Mess by ak217 on Saturday October 06, 2018 @01:28PM (#18156215)
Perhaps your information is out of date? I think none of what you said is true. Maybe some of it was true in the past.

> Want to get an stream out of a file? Better have utf-8 content. Otherwise all the documentation will be buried 15 meters deep, outdated on some aspects and dependent on some not-released yet features.

    f = open("myfile.txt", "r", encoding=ENCODING)
> Want to name a file? Better have an utf-8 name. I gave-up on python before I was able to open a file with a name that doesn't conform to utf-8.

    export NAME="$(head -c 5 /dev/urandom)"; touch "$NAME"; python -c 'import os; open(os.environ["NAME"])'
> Want to read a line at a time? Sorry, we only do that to text. Go get an utf-8 file.

    fh = open("foo", "rb"); lines=[l for l in fh]
> Want to match with a regular expression or parse it somehow? Sorry, we only do that to text.

    import re; re.match(b"abc", b"abcdef")
Re:The Python Unicode Mess by marcosdumay on Saturday October 06, 2018 @01:47PM (#18156326)
Yes, my experience is probably out of date.
Re:The Python Unicode Mess by ryandrake on Saturday October 06, 2018 @12:11PM (#18155815)
This isn't really about Python, though. There is so much crappy software out there, in all languages, that make incorrect assumptions about things like text and filenames. To this day, I'm amazed when anything works even remotely correctly when when you throw something other than ISO-8859-1 and UTF-8 at it.

I lean towards "programmer problem" rather than "language problem".

Re:The Python Unicode Mess by roel_v on Saturday October 06, 2018 @10:16AM (#18155213)
"Unix filenames are bytes"

Are they? Is the separator 0x2f or / ? Or are you talking about the filename only, not paths?

Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @11:07AM (#18155489)
The main point was that they’re not validated as Unicode so you can store values which cannot be decoded. It’s easy to find cases where someone could find a way to create a file which couldn’t easily be renamed or deleted using the OS’s built-in tools because even they forgot about this.

Similarly, Unicode normalization means that you can have multiple visually indistinguishable values which may or may not point to the same file depending on the OS and filesystem. I’ve had to help very confused users who were told that a file they could see wasn’t present because their tools didn’t handle that, too.

Re:The Python Unicode Mess by gvx on Saturday October 06, 2018 @10:37AM (#18155330)
The former. The separator a byte with the value 0x2F, which is equivalent to `/` in ASCII.
Re:The Python Unicode Mess by treve on Saturday October 06, 2018 @10:40AM (#18155352)
0x2f is / in ASCII and UTF-8, so this question doesn't make that much sense.
Re:The Python Unicode Mess by masklinn on Saturday October 06, 2018 @10:55AM (#18155428)
> Are they? Is the separator 0x2f or / ? Or are you talking about the filename only, not paths?

It's 0xf2. Encode a path to UTF-16 and watch the entire thing burn, with the FS seeing the path you provided end up right before or after the first / (because it encodes as either 0x00f2 or 0xf200 depending on BE versus LE).

Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @02:55PM (#18156629)
Unix paths are nul-byte-terminated, so UTF-16 generally doesn't make any sense in this context. Valid Unicode paths are encoded as UTF-8 on unix systems. UTF-16 and UTF-32 are invalid ways to encode Unicode paths. (That's not to say no one has tried to do it, just that it doesn't make any sense.)

(As other commenters have pointed out, Unix paths do not require a specific encoding, so robust applications cannot rely on any assumptions about encoding of existing files. But when creating new files, they must not try to encode paths as UTF-16.)

Re:The Python Unicode Mess by masklinn on Sunday October 07, 2018 @06:53AM (#18159963)
> Unix paths are nul-byte-terminated

That's the point. The separator is not "/", because "/" would be a character to encode. The separator is a specific byte, and so is the terminator.

> Valid Unicode paths are encoded as UTF-8 on unix systems.

There is no such thing as "unicode paths" on UNIX systems, valid or invalid.

Re:The Python Unicode Mess by daeken on Saturday October 06, 2018 @12:10PM (#18155812)
Endianness affects order of bytes (0xbeef vs 0xefbe), not nibbles (0xfeeb).
Re:The Python Unicode Mess by BeeOnRope on Saturday October 06, 2018 @01:55PM (#18156360)
The GP's example shows it affecting bytes, not nibbles.
Re:The Python Unicode Mess by Sir_Cmpwn on Saturday October 06, 2018 @11:02AM (#18155460)
>UNIX files and paths have no encoding, they're just bags of bytes, with specific bytes (not codepoints, not characters, bytes) having specific meaning

Yes, and you should treat them as such. If you decode them you're doing it wrong. os.listdir lets you treat paths like bytes and responds in kind:

https://docs.python.org/3.5/library/os.html#os.listdir

The problems you mentioned do exist, and Python 3's response is to make you deal with them. This is the whole point, not a mark against it. Often when you find that Python 3 is making it hard for you, it's because you're doing it wrong.

Re:The Python Unicode Mess by bartwe on Saturday October 06, 2018 @12:13PM (#18155823)
While correct that also means that you cant ever correctly show filenames to users either. At somepoint you need to relate it to an encoding as a user displays or enters it. "utf-8 everywhere now!"
Re:The Python Unicode Mess by Sir_Cmpwn on Saturday October 06, 2018 @12:21PM (#18155852)
Hi again. This was addressed in my other comment.

>You shouldn't decode them except if you need to for display (and in that case, you should be prepared to handle filenames which cannot be decoded as text).

Re:The Python Unicode Mess by ubernostrum on Saturday October 06, 2018 @11:40PM (#18158721)
you cant ever correctly show filenames to users either

If I create a file whose name consists entirely of bytes that correspond to non-printable characters, how would you display that in the language of your choice?

If I create a file whose name cannot possibly be valid UTF-8, how would you display that in the language of your choice?

Both of these things are legal to do on at least some systems. Presumably you have in mind a language which will magically handle this case with no extra effort from the programmer, though, so I'm curious to know the language and what it would do.

Re:The Python Unicode Mess by rstuart4133 on Sunday October 07, 2018 @12:01AM (#18158785)
> Yes, and you should treat them as such.

Of course you should. But the debate here is not about how a programmer should do it. The debate here is that Python3 doesn't do it that way by default and at the very least it takes extra code to do it, and as the article points out in some cases like command line arguments makes it impossible to do it that way.

A well designed computer language encourages good code by making it easy and obvious to write it. By that metric Python3's handling of bytes and strings is not well designed.

By the by I have been bitten by this. As others have mentioned a backup program turns out to be a worst case. I had to redo the string / file name handling twice before I was confident it was correct. I'm an experienced Python programmer both Python2 & 3. The final design wasn't obvious to me, and took substantially more code than I thought it would.

Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @02:56PM (#18156639)
How is that different from Python 2? You have to deal with it either way.
Re:The Python Unicode Mess by Sir_Cmpwn on Saturday October 06, 2018 @03:02PM (#18156667)
Python 2 encourages the unaware to silently write broken, anglocentric code. Python 3 puts the problem in your face.
Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @03:17PM (#18156740)
I don't see how that is responsive to the question about using bytes/Py2 string for path names.
Re:The Python Unicode Mess by Sir_Cmpwn on Saturday October 06, 2018 @03:21PM (#18156760)
Python 2 encourages the unaware to silently write broken, anglocentric code [which interacts with paths].
Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @03:54PM (#18156947)
Python 3 encourages the unaware to write broken code in a utf8-centric way instead. The unaware are going to write broken code.
Re:The Python Unicode Mess by Sir_Cmpwn on Saturday October 06, 2018 @04:08PM (#18157014)
Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @05:24PM (#18157355)
What specific difference are you trying to highlight? The only distinction I see is that Python 3.3 adds support for file descriptors.
Re:The Python Unicode Mess by joshuamorton on Saturday October 06, 2018 @07:22PM (#18157923)
Likely the existence and explicit mention of os.fsencode, as well as the api giving what you put in, so accepting bytes if you do things safely.
Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @07:37PM (#18157995)
The 2 API also returns the same type you put in.

os.fsencode() was changed in Python 3 longer after the 3.0 fork and isn't inherent to 3 -- the same change could be made to Python 2. It only wasn't because Python.org has been intentionally neglecting Python 2 since 2015.

(The Python 2 equivalent of os.fsencode() is just encoding with sys.getfilesystemencoding(). The primary difference is that fsencode() uses the surrogateescape error handler by default. Since this is a relaxed behavior, it seems like it could be added to Python 2 without regressing existing programs.)

Re:The Python Unicode Mess by joshuamorton on Saturday October 06, 2018 @07:42PM (#18158020)
Yes, so the documentation and language explicitly have tools to avoid encoding issues and make you aware of them. It encourages writing good, unbroken, code.
Re:The Python Unicode Mess by someguydave on Saturday October 06, 2018 @10:52AM (#18155412)
In my mind dealing with binary data and dealing with textual encodings are entirely separable issues. They should not be forced together by the language.
Re:The Python Unicode Mess by ajross on Saturday October 06, 2018 @10:53AM (#18155417)
> the only safe way to handle text has always been to decode bytes as soon as you get them, work with Unicode, and then encode it when you send them out

Which is a lossy process. The example given in the article is dealing with legacy filenames -- strings from environments where the source encoding isn't necessarily even known.

You're doing the classic Programmer Thing here where you assume that the real problem is choosing a correct algorithm. It's not. Real problems are about dealing with data, and you don't always have access to a time machine to fix the algorithms that created that data in the first place.

Honestly the poster is correct as far as it goes: modern python (and modern string libraries more generally) are pretty bad at handling dirty input. It's just not a problem area they've been interested in treating, because they'd like to work on stuff that feels like the correct algorithm instead of making tools for dirty data.

Re:The Python Unicode Mess by ddevault on Saturday October 06, 2018 @10:58AM (#18155442)
Filenames aren't text, they're bytes. You shouldn't decode them except if you need to for display (and in that case, you should be prepared to handle filenames which cannot be decoded as text). You should decode data into it's canonical representation as early as possible and encode it as late as possible, but the canonical representation of a filename is not text.
Re:The Python Unicode Mess by bartwe on Saturday October 06, 2018 @12:16PM (#18155838)
Filenames are text if you ever want to let a user interact with them by name.
Re:The Python Unicode Mess by ProblemFactory on Sunday October 07, 2018 @02:48AM (#18159184)
The two conditions

* OS treats filenames as bytes and allows arbitrary byte strings,

* Users want to edit filenames as text

are in conflict and you can't solve it without forcing some encoding or giving them a byte editor. The solution "filenames are bytes but we'll treat it as ASCII because 0x32-0x7E should be enough for anybody" is not acceptable for möst of thé wõrld.

Re:The Python Unicode Mess by Sir_Cmpwn on Saturday October 06, 2018 @12:20PM (#18155850)
I addressed this in my original comment.
Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @11:16AM (#18155536)
> Honestly the poster is correct as far as it goes: modern python (and modern string libraries more generally) are pretty bad at handling dirty input.

This is incorrect: Python is fine for working with messy data. The difference is that when you CONVERT that data you have to handle the possibility of errors rather than hoping for the best. If you’re working with filenames, you can pass bytes around all day long without actually decoding them; it’s only when you decode them that you’re forced to handle errors.

Re:The Python Unicode Mess by ajross on Saturday October 06, 2018 @02:39PM (#18156563)
> The difference is that when you CONVERT that data

Heh, "convert" it by concatenating it with a different directory path? Print it for the user? Stuff it into some kind of output format? Every one of those actions is going to toss an exception in python[1], and there are no tools available for reliably doing this in a safe and lossless way that matches the obvious syntax you'd use with "good" strings.

Maybe that's "fine" to you, I guess.

[1] And in lots of other environments. The quibble I have with the linked article is, again, that this kind of thinking is pervasive in modern string handling. Python certainly isn't alone.

Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @07:18PM (#18157901)
Changing paths and other filename manipulations are supposed to be done using os.path or pathlib. The discussion at https://docs.python.org/3/library/os.path.html starts with this problem and notes that the functions support all bytes or all Unicode but you have to be consistent. Don’t force a conversion to text and it works fine.

Similarly once you’re talking about output other than passing it through unmodified to a format which can handle that, you are by definition converting it and need to handle what can go wrong. It’s easy to handle this in several ways, either by reporting an error or using some sort of escaped representation with an indication that this doesn’t match the document encoding, but you no long have the luxury of pretending that treating string as a synonym for bytes was ever safe.

Re:The Python Unicode Mess by ajross on Sunday October 07, 2018 @01:58PM (#18161806)
And the need to use special libraries to handle objects that have been strings since the dawn of Unix is precisely the kind of mess the poster is talking about. Yes, yes, everyone agrees that these problems "can" be solved in Python. The question treated is whether or not Python (and modern utf8-centric string libraries) solves them WELL.
Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @03:02PM (#18156664)
Pathlib[0] is kind of a step in the right direction. I think you could do something like subclass it to track each component (and component encoding) separately if that makes sense for your application.

I'm not a fan of Python3's language fork in any way (I think it was completely unnecessary to fork the language to make the improvements they wanted to) but I'll admit things like Pathlib and UTF-8b are a step in the right direction for handling arbitrary Unix paths. (I work with a large Python 2 code base and a product that has to interact with a variety of path encodings, so this subject is... sensitive for me.)

[0]: https://www.python.org/dev/peps/pep-0428/

Re:The Python Unicode Mess by loeg on Saturday October 06, 2018 @02:58PM (#18156649)
Python 3.1+ use a non-lossy decoding of disk filenames called UTF-8b by default. You can read more about it here: https://www.python.org/dev/peps/pep-0383/ . I don't like Python3 at all, but I think it's a reasonable approach.
Re:The Python Unicode Mess by majewsky on Saturday October 06, 2018 @09:20AM (#18154997)
I didn't read the article as saying "I hate the complexity of Unicode", I read it as a complaint about language/library ergonomics. Comparing a string to a bytestring should not just always evaluate to false, it should (IMHO) raise a type error.
Re:The Python Unicode Mess by acdha on Saturday October 06, 2018 @09:37AM (#18155065)
It read to me as not learning how things worked and then blaming the language when an upgrade revealed that misunderstanding rather than taking the time to learn how things actually work.
Re:The Python Unicode Mess by slavik81 on Sunday October 07, 2018 @01:50AM (#18159028)
Even Python 3 makes it easy to ignore how things work. open happily accepts a string. Regex works on bytes. open and the standard streams can be used for reading and writing without explicitly specifying any encoding or error handling strategy. There's a default value for encoding on codec.encode and codec.decode. And nothing is checked statically, so you get to discover all your mistakes at runtime—and often only with a specific combination of inputs and environment.

People don't think about these things because Python encourages you to ignore them. Until it doesn't. There'd be a lot less confusion if Python 3 were more strict/explicit about conversions.

Re:The Python Unicode Mess by erdewit on Saturday October 06, 2018 @09:46AM (#18155101)
> Comparing a string to a bytestring should not just always evaluate to false, it should (IMHO) raise a type error.

Equality testing is implicitly done in a lot of places (like searching), it would become a bit of a hassle if the basic types were to throw exceptions when compared with each other.

Re:The Python Unicode Mess by sly010 on Saturday October 06, 2018 @10:56AM (#18155434)
It would also result in correct code sooner.
Re:The Python Unicode Mess by paulddraper on Saturday October 06, 2018 @09:58PM (#18158467)
Perhaps, but the ship sailed long ago on that one

    >>> 1 == '1'
    False
Re:The Python Unicode Mess by josteink on Saturday October 06, 2018 @11:03AM (#18155471)
Finding bugs early is considered a hastle these days? Really?
Re:The Python Unicode Mess by adjkant on Saturday October 06, 2018 @11:59AM (#18155757)
Not saying it's right but:

For something like Unicode, I think the point is that it "just worked" before where it would have been a lot more time and effort to get it "working" in say Java. Types and compile/runtime errors are a balance in the end that depends on the use case and if the programmer wants something that works (for the short term usually) or is resilient and will work long term. IMO, the influx in popularity of untyped languages (Javascript being used on the server side, ew) is a sign that so much coding today is not done for the long haul. I think there are good balances to be hit though, and Unicode is a place that highlights that python could use some better optional typing aid, as Typescript brought to JS.

Re:The Python Unicode Mess by josteink on Saturday October 06, 2018 @12:07PM (#18155798)
As someone with so called “Unicode-characters” in my name, I have encountered bugs and issues on every single American website in the history of the internets, and you will have to forgive me for preferring correctness over programmer convenience.

For me it’s literally personal.

Re:The Python Unicode Mess by im3w1l on Saturday October 06, 2018 @03:03PM (#18156671)
How many more ads are you willing to watch to pay for the correctness?
Re:The Python Unicode Mess by josteink on Saturday October 06, 2018 @03:25PM (#18156786)
While your comment is trollish, I’ll let you know I’ve had many issues with payments because shitty web-sites have been unable to 1. Validate my name and 2. Correlate whatever their whitelist permits with actual information returned from the payment processor.

So your inability to handle basic stuff like this is actually costing you money.

Re:The Python Unicode Mess by wool_gather on Saturday October 06, 2018 @09:54AM (#18155129)
Why would this be a type error? "Are these two things equivalent?" has an unambiguous answer regardless of whether the things are of different types. When they are not the same kind of thing, the answer is simply `False`. There's no reason to have a third answer "You're not allowed to ask that" for that case.
Re:The Python Unicode Mess by uryga on Saturday October 06, 2018 @10:39AM (#18155348)
It's not unambiguous at all. If I do

    "część" == "część".encode('<some-obscure-encoding>')
should it return True? They are 'equivalent' after all. But that would mean it should work for any encoding, so testing `s == b` would entail trying to decode `b` as every known encoding to see if any of them gives `s`.

My point is, `s == b` is not a well-defined question. It only makes sense to ask it for a particular encoding: "Are these two things isomorphic according to cp-1252?"¹². Giving a type error is a decent way of signalling all this.

---

¹ And even then, I don't like automatic type conversions that enable things like `3 == "3"`, but I guess that's a matter of taste.

² Of course you could pick a convention like `s == b <=> s = b.decode("utf8")`, but that's a different question.

Re:The Python Unicode Mess by wool_gather on Saturday October 06, 2018 @05:47PM (#18157444)
No, it should return `False` because they're different types, as I said.

> I don't like automatic type conversions that enable things like `3 == "3"`

I didn't mention this, and Python, the language under discussion, doesn't do this.

Re:The Python Unicode Mess by uryga on Saturday October 06, 2018 @06:14PM (#18157581)
Okay, it looks like I misunderstood your original point:

> "Are these two things equivalent?" has an unambiguous answer regardless of whether the things are of different types.

as

"Isomorphic things should compare equal"

So, to respond to (what I think is) your actual point: in my view, equality is defined on values of a single type, so I prefer to distinguish

"a isn't equal to b" (= False)

and

"there's no defined way to compare a and b, because they have different types" (= some kind of error or a null-like value)

To me, conflating the two seems counterproductive, but perhaps this is personal preference (probably correlated with how much one likes static typing).

Re:The Python Unicode Mess by ubernostrum on Saturday October 06, 2018 @11:45PM (#18158736)
Python has operator overloading, though, so a flat rule that comparisons involving values of different types must always be a type error would actually reduce the power of the language. Granted, there aren't a ton of use cases where it's important to be able to do this, but it is useful on occasion.
Re:The Python Unicode Mess by uryga on Sunday October 07, 2018 @02:49PM (#18162040)
You're right – I guess I got too hung up on the types. What I meant to say is that I prefer to distinguish "`a` is not equal to `b`" and "equality between `a` and `b` is undefined"; the typing aspect is kind of orthogonal and muddles the discussion.

(I guess I ended up conflating equality and equivalence[1], but in my defense, most languages seem to do that too; and the presence of the `is` operator in Python mixes things up even more)

[1] https://en.m.wikipedia.org/wiki/Equality_(mathematics)#Relat...

Re:The Python Unicode Mess by minitech on Saturday October 06, 2018 @10:09AM (#18155176)
It would be a type error because that would be helpful. Since comparing a bytes to a str is not usually what you want, Python could make you be explicit about it. It’s too late now, and it might have been considered another backwards compatibility break (so a good thing to keep out of Python 3), but it’s not a bad idea on its own. Heterogeneous collections are pretty rare.

Also, `==` doesn’t always answer the question of whether two things are equivalent in Python:

  >>> 1.0 == 1
  True
  >>> {'a': 5} == OrderedDict({'a': 5})
  True
(OrderedDict equality isn’t transitive.)
Re:The Python Unicode Mess by gvx on Saturday October 06, 2018 @10:40AM (#18155356)
Pretty rare but not unheard of. I do know that most of the code bases I work in would require significant reworking if I have to expect `==` to throw a TypeError for basic builtin types.
Re:The Python Unicode Mess by guitarbill on Saturday October 06, 2018 @04:57PM (#18157225)
Not quite with ==, but there is precedence where operators with basic builtin types throw a TypeError when the operation doesn't make sense:

    >>> 0 > None
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: '>' not supported between instances of 'int' and 'NoneType'
Re:The Python Unicode Mess by wool_gather on Saturday October 06, 2018 @05:51PM (#18157457)
Absolutely; there's no good boolean answer for > when you have different types, so the `TypeError` is perfect there.
Re:The Python Unicode Mess by ubernostrum on Saturday October 06, 2018 @11:58PM (#18158776)
At the same time, this result is entirely dependent on the types involved. For example, "1.0 > 0" has a well-defined answer, and Python returns it.

Considering the expression "x > y", the full process is:

1. Call x.__gt__(y).

2. If that returns a bool, that's the result. If it raises an exception, propagate the exception.

3. If it returns the sentinel value NotImplemented, attempt the reflected version of the operation: y.__lt__(x).

4. If that returns a bool, that's the result. If it raises an exception, propagate the exception.

5. If it returns the sentinel value NotImplemented, raise TypeError and inform the programmer this operator is not valid on these types.

Re:The Python Unicode Mess by uryga on Saturday October 06, 2018 @10:47AM (#18155392)
Could you explain how your example shows that?
Re:The Python Unicode Mess by minitech on Saturday October 06, 2018 @11:35AM (#18155635)
Which “that”? If you’re asking about `OrderedDict`, I’m referring to equality between `OrderedDict`s:

  >>> a = OrderedDict([(1, 2), (3, 4)])
  >>> b = {1: 2, 3: 4}
  >>> c = OrderedDict(reversed(a.items()))
  >>> a == b == c
  True
  >>> a == c
  False
Re:The Python Unicode Mess by uryga on Saturday October 06, 2018 @05:53PM (#18157471)
I was referring to this:

> Also, `==` doesn’t always answer the question of whether two things are equivalent

because the examples you posteda kinda make it look like it does, i.e. `1.0 == 1` even though one is a float and the other is an int.

Re:The Python Unicode Mess by zbentley on Saturday October 06, 2018 @10:56AM (#18155431)
> "Are these two things equivalent?" has an unambiguous answer regardless of whether the things are of different types.

Absolutely not; that's basically the OG subjective question whose lack of an obvious right answer underpins a substantial quantity of the bugs in less strongly-typed languages.

Nor is an unambiguous answer possible symbolically, or in common logic, or the semantics of spoken languages.

Re:The Python Unicode Mess by wool_gather on Saturday October 06, 2018 @05:49PM (#18157451)
I think you stopped reading before my next sentence, which says the answer is "false" if the types are different.
Re:The Python Unicode Mess by hyperbovine on Saturday October 06, 2018 @01:52PM (#18156352)
Agree, whinging about Unicode just seems like atavism for the days when computer users who did no speak English were ignored.
Re:The Python Unicode Mess by Razengan on Saturday October 06, 2018 @10:25AM (#18155274)
> As far as I can tell this is a long-form “I used to be able to ignore encoding issues and now it’s a ‘mess’ because the language is forcing me to be correct”.

That’s one of the reasons I love Swift and appreciate that it wants to get these things right, even if it means changing every year in the first few versions.