Live data from Hacker News

Why Is the Migration to Python 3 Taking So Long?

stackoverflow.blog

251–260 of 355 posts

Re: Why Is the Migration to Python 3 Taking So Long?

#251
post #160

Earlier quoted context omitted.

> Unicode support was actually an anti-feature for most existing code. If you're writing a simple script you prefer 'garbage-in, garbage-out' unicode rather than scattering casts everywhere to watch it randomly explode when an invalid byte sneaks in. If you did have a big user-facing application that cared about unicode, then the conversion was incredibly painful for you because you were a real user of the old style.…

> Actually that's the behavior of python 2, it works fine, until you send invalid characters then it blows up. Not that I've seen. Example of where Python 3 has rained shit on my parade: I wrote a program that backs up files for Linux. It works fine in python 2, but in python 3 you rapidly learn you must treat filenames as bytes otherwise your backup program blows up on valid Linux filenames. It's not just decoding e…

>For them python2 was a better scripting language than bash

This! IMO Python 2 has better usability for prototyping and thinking and doing things on the fly. Python 3 also often seems to have deprecated the functions I want to use in favor of those that are more cumbersome and take more keystrokes. More explicit sure, but less fluid.

Re: Why Is the Migration to Python 3 Taking So Long?

#252

The simple reason is that there was no compelling feature to reward you for upgrading. You'd spend a tremendous amount of effort for dubious return and (until recently) a smaller ecosystem. 1. Unicode support was actually an anti-feature for most existing code. If you're writing a simple script you prefer 'garbage-in, garbage-out' unicode rather than scattering casts everywhere to watch it randomly explode when an in…

Solid take. I'd add that performance was worse for a number of releases, and there were significant warts and incompatibilities in versions before 3.4. Personally, asyncio and type annotations are a big turnoff. I know this is a bit contrarian, but I've always favored the greenlet/gevent approach to doing cooperative multi-tasking. Asyncio (neé twisted) had a large number of detractors, but now that the red/blue appr…

Another problem with python’s type annotations is that false negatives are common in partially type annotated code bases: i.e. an annotation which is untrue, but for which there are no supporting calls/usages causing the type checker to reject it. This is pretty pathological in my experience: it means that annotations have the semantic status of comments (i.e. might be true, might not, who knows) while being given the syntactic status of “real code”.

Re: Why Is the Migration to Python 3 Taking So Long?

#253
post #166

Earlier quoted context omitted.

> The nuisance of having to add self as parameter to every class method This was done intentionnaly, because "Explicit is better than implicit". It also has some uses, eg. if you want to do this: class Foo: def inject_bar(self): def new_bar(self2): pass # you can refer to both 'self' and 'self2 here other_object.bar = new_bar It's rare, but it has its uses.

> "Explicit is better than implicit" Too bad Python breaks this "commandment" pretty much whenever it wants to.

"Practicality beats purity"

Re: Why Is the Migration to Python 3 Taking So Long?

#254
post #160

Earlier quoted context omitted.

> Unicode support was actually an anti-feature for most existing code. If you're writing a simple script you prefer 'garbage-in, garbage-out' unicode rather than scattering casts everywhere to watch it randomly explode when an invalid byte sneaks in. If you did have a big user-facing application that cared about unicode, then the conversion was incredibly painful for you because you were a real user of the old style.…

> Actually that's the behavior of python 2, it works fine, until you send invalid characters then it blows up. Not that I've seen. Example of where Python 3 has rained shit on my parade: I wrote a program that backs up files for Linux. It works fine in python 2, but in python 3 you rapidly learn you must treat filenames as bytes otherwise your backup program blows up on valid Linux filenames. It's not just decoding e…

Filenames need to be treated as binary because of bad designs decades ago. Rust handles this correctly imho, by having a separate type for such strings, OsStr.

Re: Why Is the Migration to Python 3 Taking So Long?

#255

Earlier quoted context omitted.

Behold the tremendous amount of effort for Mercurial: https://www.mercurial-scm.org/repo/hg/log?rev=py3&revcount=2... They've been porting hg into Python 3 for the last 10 years and are only now nearing completion. I've written a bit more about this in Lobsters: https://lobste.rs/s/3vkmm8/why_i_can_t_remove_python_2_from_...

Yes of course there will be exceptions. But the vast majority off Python code bases are not mercurial or dropbox or imgur. Just like the vast majority of software using companies are not google or facebook. The average few hundred to few thousand loc app, which should be 98% of all production code-bases will almost certainly port with no issue.

No one wants to spend a ton of energy just to remain in place. I don't understand how software providers are so cavalier about eschewing backwards compatibility.

Re: Why Is the Migration to Python 3 Taking So Long?

#256

The simple reason is that there was no compelling feature to reward you for upgrading. You'd spend a tremendous amount of effort for dubious return and (until recently) a smaller ecosystem. 1. Unicode support was actually an anti-feature for most existing code. If you're writing a simple script you prefer 'garbage-in, garbage-out' unicode rather than scattering casts everywhere to watch it randomly explode when an in…

I am flabbergasted every time I see a software project eschew backwards-compatibility.

No one wants to spend energy re-programming to stay in place.

Especially APIs.

Re: Why Is the Migration to Python 3 Taking So Long?

#257

The simple reason is that there was no compelling feature to reward you for upgrading. You'd spend a tremendous amount of effort for dubious return and (until recently) a smaller ecosystem. 1. Unicode support was actually an anti-feature for most existing code. If you're writing a simple script you prefer 'garbage-in, garbage-out' unicode rather than scattering casts everywhere to watch it randomly explode when an in…

Solid take. I'd add that performance was worse for a number of releases, and there were significant warts and incompatibilities in versions before 3.4. Personally, asyncio and type annotations are a big turnoff. I know this is a bit contrarian, but I've always favored the greenlet/gevent approach to doing cooperative multi-tasking. Asyncio (neé twisted) had a large number of detractors, but now that the red/blue appr…

I’m writing Elixir code currently and find the red/blue approach in JavaScript a pain. Never used asyncio beyond trying a few "hello world" and it was just baffling. In Rust async seems not terrible with the newer syntax, typing, and of course, huge speed improvement making it worthwhile. But in a dynamic VM? Just a pain. Julia’s approach with "tasklets" seems intriguing as well.

Re: Why Is the Migration to Python 3 Taking So Long?

#258
post #160

Earlier quoted context omitted.

> Unicode support was actually an anti-feature for most existing code. If you're writing a simple script you prefer 'garbage-in, garbage-out' unicode rather than scattering casts everywhere to watch it randomly explode when an invalid byte sneaks in. If you did have a big user-facing application that cared about unicode, then the conversion was incredibly painful for you because you were a real user of the old style.…

> Actually that's the behavior of python 2, it works fine, until you send invalid characters then it blows up. > In python 3 it always blows up when you mix bytes with text so you can catch the issue early on. Sometimes you don't care about weird characters being print as weird things. In python 2 it works fine: you receive garbage, you pass garbage. In python 3 it shuts down your application with a backtrace. Dealin…

Those issues are common when you're having python 2 code that uses unicode datatype and you have a task to migrate it to python 3.

You run your python 2 code on python 3 and it fails, most people at that point will place encode() or decode() in place where you have a failure. When the correct fix would be to place encode/decode at I/O boundary (writing to files (and in python 3 even that is not needed if you open files in text mode), network etc).

Ironically a python 2 code that doesn't use unicode is easier to port.

When you program in python 3 from the start it's very rare to need encode/decode strings. You only do that if you are working on I/O level.

> And the documentation was particularly horrible regarding that, not even the experienced pythoners knew how to deal with it properly.

Because it's not really python specific knowledge. It's really about understanding what the unicode is, what bytes are, and when to use each.

The general practice is to keep everything you do as text, and do the conversion only when doing I/O. You should think of unicode/text as as a representation of a text, as you think of a picture or sound. Similarly to image and audio text can be encoded as bytes. Once it is bytes it can be transmitted over network or written to a file etc. If you're reading the data, you need to decode it back to the text.

This is what Python 3 is doing:

- by default all string is of type str, which is unicode - bytes are meant for binary data - you can open files in text and binary mode, if you open in text the encoding is happening for you - socket communication - here if you need to convert string to bytes and back

Python 2 is a tire fire in this area:

- text is bytes - text also can be unicode (so two ways to represent the same thing) - binary data can also be text - I/O accepts text/bytes, no conversion happening - a lot (most? all?) stdlib is actually expecting string/bytes as input and output - cherry on top is that python2 also implicitly converts between unicode and string so you can do crazy thing like my_string.encode().encode() or my_string.decode()

So now you get a python 2 code, where someone wanted to be correct (it is actually quite hard to do it, mainly because of the implicit conversion) so the existing code will have plenty of encode() and decode() because some functions now expect str some unicode.

At different functions you might then have bytes or unicode as a string.

Now you take such code and try to move it to python 3, which no longer has implicit conversion and will throw an error when it expected text and got bytes and vice versa. The str now is unicode, unicode type no longer exists and bytes is now not the same thing as str. So your code now blows up.

Most people see an error so they add encode() or decode() often trying which one works (like what you were removing) when the proper fix would be actually removing encodes() and decodes() in other places of the code.

It's quite difficult task when your code base is big, so this is why Guido put a lot of effort with type annotations, mypy. One of its benefits supposed to help with these issues.

Re: Why Is the Migration to Python 3 Taking So Long?

#259

Earlier quoted context omitted.

> Actually that's the behavior of python 2, it works fine, until you send invalid characters then it blows up. Not that I've seen. Example of where Python 3 has rained shit on my parade: I wrote a program that backs up files for Linux. It works fine in python 2, but in python 3 you rapidly learn you must treat filenames as bytes otherwise your backup program blows up on valid Linux filenames. It's not just decoding e…

Filenames need to be treated as binary because of bad designs decades ago. Rust handles this correctly imho, by having a separate type for such strings, OsStr.

Rust had the luxury to learn from mistakes of others :)

When python was created the Unicode didn't even exist.

Anyway in python 3, many os functions accept string and bytes, and might behave depending on it. For example os.walk, if you pass path as byte string, will output paths as bytes.

Re: Why Is the Migration to Python 3 Taking So Long?

#260
post #218

Earlier quoted context omitted.

Thank you (and it's good to say so if another reader doesn't know), but yeah, the 4 versions I was referring to were 3.5-3.8... but my point is that it's now a perpetually moving target. And fwiw "3.7 is the current version" doesn't help my users.

I think pip can select the version automatically as long as you provide the right metadata with the package. Shouldn't matter much really. Maybe write in the README that the package is only tested on 3.7 and above so users can be aware of that and check. Bet they struggle to figure out what version to upgrade to as well.

> I think pip can select the version automatically as long as you provide the right metadata with the package. Shouldn't matter much really.

I don't think pip can install new versions of python. This becomes burdensome, especially for novices.

> Maybe write in the README that the package is only tested on 3.7 and above so users can be aware of that and check. Bet they struggle to figure out what version to upgrade to as well.

I must disagree with this philosophy. As a package maintainer, I think it's my responsibility to "struggle" so that my users don't need to. And fwiw, my employer also thinks that this is part of my job.

Post reply on HN