Hacker News new | ask | show | jobs
by wallunit 4772 days ago
> If you have a C module written on top of the Python C API: shoot yourself. There is no tooling available for that yet from what I know and so much stuff changed.

I don't agree with that one. I have added Python 3 support two years ago to the Python bindings for libssh2 and it was straight forward. First of all it is still C and therefore you don't have to care about the syntax changed in Python. Just add some #if PY_MAJOR_VERSION < 3 for API calls that have changed, or even better wrap that code in macros. Probably you already have some backwards compatibility switches/macros like that already anyway in your code, if you already support multiple versions of 2.x. So adding some more for Python 3, isn't that a big deal.

At least at that time, when six and modernizer wasn't available it was way easier and straight forward to support Python 2 and 3 with the same codebase with extension modules, than with actual Python code. And it seems if you don't want to drop support for Python <= 2.5 or <= 3.2, it still is.

3 comments

My C module is APSW - a python wrapper around SQLite - https://code.google.com/p/apsw/

It supports every version of Python from 2.3 onwards with the exception of 3.0. I provide binaries for Windows and astonishingly people are still downloading the 2.3 version.

As you stated, most of the work is done by feeding the C preprocessor relevant information - https://code.google.com/p/apsw/source/browse/src/pyutil.c

It did take me considerably longer to make my test suite work. This is because I have 99.6% code coverage, and it exercises a lot of edge/error conditions. The test suite code (in Python) is written to run under both Python 2 and 3 as is and has to use some of the similar tricks with exec as the article mentioned. Fun challenges are constructing invalid UTF8 sequences in all Python versions and that sort of thing.

My experience is that at least with Py 2.6, 2.7, 3.2, and 3.3, it's not all that bad. I'm helping maintain Pillow, a PIL fork, and the commit to add Python 3 support touched a lot of things, but it wasn't that complicated. We've got a py3k.h file that has some ifdefs in it, all the print statements got changed to functions, and there's a few other bits and pieces.

Prior to Pycon, I wasn't really ready for python 3, now I'm missing it in my main codebase (which is on 2.7).

That again depends on how much you do with strings and integers and how many modules you construct. PyInt is gone, PyUnicode is now PyStr, module construction uses a vastly different system and on 3.x you want to support the stable ABI which looks a bit different.
Except for the module creation you can easily add some very simple compatibility macros. I don't see how that would be different from your _compat module. However module creation can't be abstracted into a uniform macro in fact, because of it requires to define a PyModuleDef struct and the the modlue's init function got a return value in Python 3. But I'm fine with using some #if PY_MAJOR_VERSION >= 3 here.

After all you have to deal with way less compatibility issues, in extension modules than in actual python code. And if needed you can always do a simple version switch. You don't have to care about changes in the syntax of Python. You also don't have to care about changes of the __*__ magic method, because of you don't call them directly, and when defining classes you use slots for stuff like that.

Fair enough. As I said you can probably get around with some macros. To the best of my knowledge no such thing currently exists and what markupsafe does is not particularly nice.