Live data from Hacker News

Ride the carousel of folly with a Python migration

mortoray.com

11–20 of 36 posts

Re: Ride the carousel of folly with a Python migration

#11

Python 2 > 3 is the next Y2K. My colleague and I have started offering Python 2 > 3 consulting services as some of our clients weren't prepared to make the migration themselves. With Django announcing that they will drop Python 2.7 support, this might become one of our more popular services!

We have "until at least April 2020" before django 1.11 (the last that works with 2.7) is EOL. Python 2.7 is EOL in 2020 as well.

Re: Ride the carousel of folly with a Python migration

#12
post #6

> The only somewhat problematic code was this: for line in iter( handle.stdout.readline, '' ): self.output.put( ( handle, line ) ) > This no longer terminated an emitted lots of odd values (one number repeatedly). It turns out it returns an empty b'' now when empty, as opposed to a ''. This could have been avoided had this API sensibly returned None instead of an empty string. For any observers, this is much more idi…

In addition to what you've pointed out, he claims that 2to3 didn't do anything to his code, and yet he had to fix print statements. 2to3 definitely fixes print statements; he likely didn't read the usage or docs at all. By default it prints a diff, you have to use 2to3 -w if you want it to modify files on disk -- I certainly don't want tools modifying files in-place by default, so that seems like the right API to me.

That was the red flag to me. That smacks of someone saying "I haven't read the docs. It didn't work. It sucks."

Heck. I haven't done any 2 to 3 porting. I just read a few articles out of idle curiosity once and even I know 2to3 doesn't work like that.

Re: Ride the carousel of folly with a Python migration

#13
In my opinion/experience, there are some important hidden costs of staying in py2:

1) Hard-to-read or quirky code. Unicode handling, args, harder unpacking, etc. The more time it passes, the more updates py3 gets, and the more outdated the py2 code looks.

For instance, after a year almost exclusively in py3, I have completely forgotten about iter(), unicode gimmics, etc. and also rely more on stuff that is just too slow on py2 (like ordered dicts). With 3.6, I can start assuming dicts are ordered, which will create further breaks for py2 users (if they want to backport anything).

2) Outdated libraries. As the other comments say, epydoc is abandonware. Had he migrated to py3 earlier, he would have stopped investing in that tool earlier and switched to the standard (sphynx).

3) Harder to interact with others in the community.

Although the folks at google might think otherwise, most people are now using py3, and most code being developed right now is on py3 (at least open source code).

If you are still on py2, it will be harder to hire (it hints at huge technical debt, and a tedious working environment), harder to sell to others (e.g. I don't use google compute because of that), and harder to collaborate on (for open source projects).

All in all, the more that py2 and py3 diverge, the harder it will be for legacy (py2) users to migrate (this was not the case a few years ago, when there were still important libraries on py2 only).

Re: Ride the carousel of folly with a Python migration

#14

> The only somewhat problematic code was this: for line in iter( handle.stdout.readline, '' ): self.output.put( ( handle, line ) ) > This no longer terminated an emitted lots of odd values (one number repeatedly). It turns out it returns an empty b'' now when empty, as opposed to a ''. This could have been avoided had this API sensibly returned None instead of an empty string. For any observers, this is much more idi…

About PyPI, it is a bit messy.

I backported a py3 project to use py2 (on behalf of a few users) and it was a real pain in the ass to have a wheel that allowed for both versions.

I ended up having a py3 build on github, and using a TravisCI build that ran pasteurize and pushed to PyPI that version. At this point, I don't even know what the travis.yml file is doing (100 lines), and regret a bit backporting the project.

Re: Ride the carousel of folly with a Python migration

#15

In my opinion/experience, there are some important hidden costs of staying in py2: 1) Hard-to-read or quirky code. Unicode handling, args, harder unpacking, etc. The more time it passes, the more updates py3 gets, and the more outdated the py2 code looks. For instance, after a year almost exclusively in py3, I have completely forgotten about iter(), unicode gimmics, etc. and also rely more on stuff that is just too s…

Nitpick, but you cannot assume dicts are ordered in Py3, even in 3.6. CPython's 3.6 implementation will make it so, but it's totally a CPython implementation detail. Please use ordered dicts when appropriate (they'll be dicts in CPython anyways)

Re: Ride the carousel of folly with a Python migration

#16
post #6

> The only somewhat problematic code was this: for line in iter( handle.stdout.readline, '' ): self.output.put( ( handle, line ) ) > This no longer terminated an emitted lots of odd values (one number repeatedly). It turns out it returns an empty b'' now when empty, as opposed to a ''. This could have been avoided had this API sensibly returned None instead of an empty string. For any observers, this is much more idi…

In addition to what you've pointed out, he claims that 2to3 didn't do anything to his code, and yet he had to fix print statements. 2to3 definitely fixes print statements; he likely didn't read the usage or docs at all. By default it prints a diff, you have to use 2to3 -w if you want it to modify files on disk -- I certainly don't want tools modifying files in-place by default, so that seems like the right API to me.

> By default it prints a diff, you have to use 2to3 -w if you want it to modify files on disk -- I certainly don't want tools modifying files in-place by default, so that seems like the right API to me.

Well, running 2to3.py -w -n -o [new_py3_path] [old_py2_path] got me a copy of a project with every fix already applied. Another alternative I've been thinking is doing a "last before 2to3 commit" (and leaving no pending changes), and then run 2to3 inplace and check those from the IDE (which may or may not be easier to a few folks that work with me).

I have to check a few more things, but it seems 2017 is the year I'm finally porting then two biggest projects I work on to Python 3. Luckily both projects aren't heavy offenders and should still remain Py2 compatible, but we may have the push with the clients to ask for exlusively Py3 support.

Re: Ride the carousel of folly with a Python migration

#17
post #6

Earlier quoted context omitted.

In addition to what you've pointed out, he claims that 2to3 didn't do anything to his code, and yet he had to fix print statements. 2to3 definitely fixes print statements; he likely didn't read the usage or docs at all. By default it prints a diff, you have to use 2to3 -w if you want it to modify files on disk -- I certainly don't want tools modifying files in-place by default, so that seems like the right API to me.

> By default it prints a diff, you have to use 2to3 -w if you want it to modify files on disk -- I certainly don't want tools modifying files in-place by default, so that seems like the right API to me. Well, running 2to3.py -w -n -o [new_py3_path] [old_py2_path] got me a copy of a project with every fix already applied. Another alternative I've been thinking is doing a "last before 2to3 commit" (and leaving no pendi…

You could also test the waters with a `2to3` branch.

If you have uncommitted changes, instead of dropping them in as "last before..." you can git-stash them before branching and git-stash-pop them when you come back.

Re: Ride the carousel of folly with a Python migration

#18

> The only somewhat problematic code was this: for line in iter( handle.stdout.readline, '' ): self.output.put( ( handle, line ) ) > This no longer terminated an emitted lots of odd values (one number repeatedly). It turns out it returns an empty b'' now when empty, as opposed to a ''. This could have been avoided had this API sensibly returned None instead of an empty string. For any observers, this is much more idi…

About PyPI, it is a bit messy. I backported a py3 project to use py2 (on behalf of a few users) and it was a real pain in the ass to have a wheel that allowed for both versions. I ended up having a py3 build on github, and using a TravisCI build that ran pasteurize and pushed to PyPI that version. At this point, I don't even know what the travis.yml file is doing (100 lines), and regret a bit backporting the project.

What makes it difficult? My projects are all quite simple, but I do keep them compatible with both Python 2 and Python 3.

All I had to do was create a setup.cfg that said:

    [wheel]
    universal = 1
To build, I use:

    python setup.py sdist bdist_wheel
    twine upload -s dist/*
The .travis.yml is just 7 lines. https://github.com/cgmb/guardonce/blob/v2.0.0/.travis.yml

Re: Ride the carousel of folly with a Python migration

#19
post #6

> The only somewhat problematic code was this: for line in iter( handle.stdout.readline, '' ): self.output.put( ( handle, line ) ) > This no longer terminated an emitted lots of odd values (one number repeatedly). It turns out it returns an empty b'' now when empty, as opposed to a ''. This could have been avoided had this API sensibly returned None instead of an empty string. For any observers, this is much more idi…

In addition to what you've pointed out, he claims that 2to3 didn't do anything to his code, and yet he had to fix print statements. 2to3 definitely fixes print statements; he likely didn't read the usage or docs at all. By default it prints a diff, you have to use 2to3 -w if you want it to modify files on disk -- I certainly don't want tools modifying files in-place by default, so that seems like the right API to me.

The simple syntax changes I did prior to running 2to3 as they came up on the first run I tried. The semantic changes that didn't come up in 2to3 is what I was more bothered about.

Re: Ride the carousel of folly with a Python migration

#20

> The only somewhat problematic code was this: for line in iter( handle.stdout.readline, '' ): self.output.put( ( handle, line ) ) > This no longer terminated an emitted lots of odd values (one number repeatedly). It turns out it returns an empty b'' now when empty, as opposed to a ''. This could have been avoided had this API sensibly returned None instead of an empty string. For any observers, this is much more idi…

The `iter` form of the `readline` doesn't load the entire stream first, whereas the second form you posted does. This makes a significant difference when reading data from another program.

I saw that migration guide, but it has very few details about what is actually involved in migration. It doesn't include API change details.

Post reply on HN