Live data from Hacker News

Using both Python 2 and 3 in Windows

spapas.github.io

41–44 of 44 posts

Re: Using both Python 2 and 3 in Windows

#41
post #32

Earlier quoted context omitted.

I have a Python project with 28KLOC of Python, 22KLOC for a Python/C extension, and 26KLOC for the tests, so about 4x larger. It took me about 6-8 weeks to port. Part of it was because I had to change the API. I had an API with a method like "X.to_string(fmt)" where the format specifier could be something like 'csv' for text and 'csv.gz' for gzip-compressed text. I had to split that out into a "X.to_string()" and "X.…

You took my "port 20K LOC python code" to "take 70K LOC of mixed of Python and C and make it compatible with 2 and 3". That's an entirely different story, and is definitely the average project.

Agreed, but are you saying the scaleup is non-linear in LOC?

Because simple linear scaleup suggests 6 days of work, not 30-40 days of work.

I also pointed out that just the test suite, which not much bigger than 20KLOC, required hours of work to tweak all of the b"" strings correctly.

One of the other tedious difficulties is that this code base started during Python 2.5, so there were many submodules with print statements which needed to turned into print functions.

(Annoyingly, some "print >> f, s" debug lines, enabled with an undocumented environment variable, made it to release, because that is still valid syntax under Python 3 ("unsupported operand type(s) for >>: 'builtin_function_or_method'") and it wasn't part of the test suite.)

I looked at another code base of mine, which is 18.5 KLOC (9.5KLOC my source, 4.5KLOC for a third-party submodule which already supported Python 3, and 4.5KLOC of a machine generated table which needed no porting). This one started under Python 2.7, and made sure to use __future__ compatibility even when it was Python 2.7-only. That helped reduce the porting cost.

There are 23 commits which specifically mention fixing compatibility problems. However, I did the Python 3 update during a major refactor, and included Python 3 changes as part of the refactoring. I then re-tested under Python 2 to check for compatibility. This means I can't identify all of the changes which are 2->3 specific.

These are mostly the usual iteritems()->items(), zip()->list(zip()), itertools.izip()->zip(), a compatibility shim for isinstance(obj, basestring), open(name, "U") vs. open(name, "r", newline=None), etc.

Some of the trickier ones were: how to read bytes from stdin (sys.stdin.buffer); explicit flushes on sys.stderr (not needed for Python 2.x); a StringIO-like wrapper around BytesIO so I could write() both bytes and Unicode strings containing only ASCII (which is what cStringIO.StringIO did); and a few workarounds for changes in argparse behavior.

The trickiest is that I allow the user to pass in an eval-able mathematical expression on the command-line. My code first compiles the expression and checks that all of the global variables are known, in order to generate a more detailed error message than Python itself would. In Python 3, True and False are keywords, while in Python 2 they are built-ins. I didn't originally allow "True"/"False" in the expression, so there could be simple expressions which were valid under the Python 3 version which weren't valid under the Python 2.

While the change was easy, figuring out that I needed the change was harder.

I don't know how long it took for this code base. Based on the bunching of the commit messages, it looks like I spent at least 16 hours (= 2 days) on it, figuring from first commit of each bunch to the last.

  % hg history | grep --before 1 -i 'python.*[23]' | grep date
  date:        Fri Jun 02 05:04:30 2017 +0200
  date:        Fri Jun 02 03:51:28 2017 +0200
  date:        Thu Jun 01 03:37:37 2017 +0200
  date:        Thu Jun 01 01:16:33 2017 +0200
  date:        Mon May 29 17:07:00 2017 +0200
  date:        Sun May 28 04:48:14 2017 +0200
  date:        Sun May 28 03:38:34 2017 +0200
  date:        Sun May 28 03:18:56 2017 +0200
  date:        Sat May 27 00:28:08 2017 +0200
  date:        Fri May 26 16:29:03 2017 +0200
  date:        Fri May 26 16:28:43 2017 +0200
  date:        Fri May 26 15:37:40 2017 +0200
  date:        Fri May 26 14:26:47 2017 +0200
  date:        Fri May 26 13:56:42 2017 +0200
  date:        Thu May 25 04:38:45 2017 +0200
  date:        Thu May 25 03:52:04 2017 +0200
  date:        Thu May 25 03:51:29 2017 +0200
  date:        Thu May 25 03:51:01 2017 +0200
  date:        Thu May 25 03:36:34 2017 +0200
  date:        Thu May 25 01:33:26 2017 +0200
  date:        Wed May 24 18:44:42 2017 +0200
  date:        Wed May 24 16:52:40 2017 +0200
  date:        Wed May 24 16:51:47 2017 +0200
This is about twice as long as your estimate would suggest. (I'm excluding the auto-generated data table and the third-party package from my LOC count.)

Re: Using both Python 2 and 3 in Windows

#42
post #41

Earlier quoted context omitted.

You took my "port 20K LOC python code" to "take 70K LOC of mixed of Python and C and make it compatible with 2 and 3". That's an entirely different story, and is definitely the average project.

Agreed, but are you saying the scaleup is non-linear in LOC? Because simple linear scaleup suggests 6 days of work, not 30-40 days of work. I also pointed out that just the test suite, which not much bigger than 20KLOC, required hours of work to tweak all of the b"" strings correctly. One of the other tedious difficulties is that this code base started during Python 2.5, so there were many submodules with print state…

> Agreed, but are you saying the scaleup is non-linear in LOC?

Yes. Complexity is always exponential.

> Because simple linear scaleup suggests 6 days of work, not 30-40 days of work.

Well, again your project is particularly hard: c extension + Python 2 / 3 compatible code base. That's not the common case.

You can always find somebody with a particular situation. And we hear those persons more, and not the hundred ons with just a few scripts or a website.

> I also pointed out that just the test suite, which not much bigger than 20KLOC, required hours of work to tweak all of the b"" strings correctly.

That's Python 2 / 3 compatible code base for you. This tweak is almost a no brainer in pure python 3.

> many submodules with print statements which needed to turned into print functions.

2to3 does that automatically, and many other things, that you can even cherry-pick. If you don't use the provided tooling, you make your life harder.

> These are mostly the usual iteritems()->items(), zip()->list(zip()), itertools.izip()->zip(), a compatibility shim for isinstance(obj, basestring), open(name, "U") vs. open(name, "r", newline=None), etc.

python-future provide all the helpers for that: normalized builtins, import aliases, wrappers, etc. It has existed since 2013. People need to spread the word about the proverbial wheel on this one.

It's like using

> Some of the trickier ones were: how to read bytes from stdin (sys.stdin.buffer); explicit flushes on sys.stderr (not needed for Python 2.x); a StringIO-like wrapper around BytesIO so I could write() both bytes and Unicode strings containing only ASCII (which is what cStringIO.StringIO did); and a few workarounds for changes in argparse behavior.

Yeah, that's the hard part. You can't automate that. But it's what, 3% of your code ? Unless you hate DRY.

It's quite fair that bumping an entire project to an non compatible version of your plateform requires you do this.

> The trickiest is that I allow the user to pass in an eval-able mathematical expression on the command-line. My code first compiles the expression and checks that all of the global variables are known, in order to generate a more detailed error message than Python itself would.

Quite a cool project :)

> This is about twice as long as your estimate would suggest. (I'm excluding the auto-generated data table and the third-party package from my LOC count.)

Granted. Still, 4 days of porting for an entire project one time in a 25 years old language feels ok in my book.

Don't forget that since 2000:

- Perl 6 has been late for a decade. - PHP failed its V6 and jumped to V7. - NodeJS forked and merged twice.

From this point of view, what Python did is an amazing accomplishment.

Re: Using both Python 2 and 3 in Windows

#43
post #41

Earlier quoted context omitted.

Agreed, but are you saying the scaleup is non-linear in LOC? Because simple linear scaleup suggests 6 days of work, not 30-40 days of work. I also pointed out that just the test suite, which not much bigger than 20KLOC, required hours of work to tweak all of the b"" strings correctly. One of the other tedious difficulties is that this code base started during Python 2.5, so there were many submodules with print state…

> Agreed, but are you saying the scaleup is non-linear in LOC? Yes. Complexity is always exponential. > Because simple linear scaleup suggests 6 days of work, not 30-40 days of work. Well, again your project is particularly hard: c extension + Python 2 / 3 compatible code base. That's not the common case. You can always find somebody with a particular situation. And we hear those persons more, and not the hundred ons…

If "Complexity is always exponential." then a 10KLOC project should take less than 1/2 of the 2 days time that you estimated for a 20KLOC project. Which is contrary to my experience.

> This tweak is almost a no brainer in pure python 3.

The timing estimate I made assumed 4 changes per minute. That's already pretty no-brainer. Are you suggesting it should have been faster than that? I don't know how. Not all of the strings needed to be converted to byte strings.

> python-future provide all the helpers for that

First time I heard of it. I thought we were supposed to be using 'six', which is where I got the shims from.

If I understand correctly, that package should not be used for Python libraries which want to maintain Python 2 compatibility. That is, if I have library X, and some of my users are on Python 2, then I shouldn't use python-future because the 'standard_library.install_aliases()' call modifies builtins, which may change how Python 2 works for those users.

> 4 days of porting for an entire project one time in a 25 years old language feels ok in my book.

Yes. My point is that I think your original numbers are optimistic, not that they are fundamentally flawed.

Re: Using both Python 2 and 3 in Windows

#44

Earlier quoted context omitted.

I think the library ecosystem has tipped over to focusing on Python 3. That doesn't really matter to people with large Python 2 codebases and no economic reason to transition them to 3.

Don't know how updated http://py3readiness.org/ is but according to it 346 of the top 360 libs support py3. Interesting missing libs for me is supervisor and ansible.

I'm quite curious as to how many of those are python3-ONLY.
Post reply on HN