discontinuing Flattr for lxml    Posted:

I removed lxml from Flattr. The outcome is just way below ground. The Flattr revenue for the project over the last years was a pretty constant 6 EUR per month. Minus taxes. And Flattr already kept their 10% share, which is what bugs me most, I guess. That leaves Paypal as the current (and certainly better) alternative if you want to support the development behind lxml.

Cython 0.20 will make everything better :)    Posted:

It`s been a while since the last major Cython release, so here`s a little update on what`s going to be new in 0.20. We`ve managed to improve the compiler in several important areas.

I`ve been working on making Cython a serious string processing tool for a couple of releases now, and the next release will add another piece to the puzzle. Cython has four string types now: bytes, str, unicode and, newly added, basestring. The special types str and basestring help with writing portable code for both Python 2 and 3. The str type expands to bytes in Py2 and to the Unicode string type in Py3, i.e. to whatever the platform calls "str" natively. This is really nice, because it allows you to get the native string type by simply saying "str" or by writing an unprefixed string literal. However, the problem was that when you type a variable or function argument as str, you couldn't assign a Unicode string to it in Py2, thus unnecessarily rejecting some text input. So I added the basestring type, which accepts both str and unicode in Py2, but only Unicode strings in Py3. Anything else will raise a TypeError on assignment.

Another corner where string processing was improved is the bytearray type. Cython recognises it as a known type now and allows it to coerce from and to C's char* values for much faster interaction with C/C++ code.

Cython`s own internal types, such as the function type or generators, are shared between modules now. Basically, the first imported Cython module in a running interpreter registers a shared (versioned) module that all later Cython modules use for initialisation. This allows multiple installed modules to recognise each others types, which allows for much faster interoperability.

Type inference has also gained new capabilities. It`s based on control flow analysis now (instead of function-global type analysis), which allows for more fine-grained typing. It`s also used in some cases to remember assignments to local constants, which allows Cython to see the current value of that variable and to optimise code based on it. For example, assignments of bound methods (like "append = some_list.append") can be traced back to the underlying object now, which improves the performance of some untyped Python code out there.

As for usability, the compiler has gained a new frontend script "cythonize" that mimics the capabilities of the cythonize() function used in setup.py scripts. To compile a module, or even an entire package down to extension modules, you can simply say "cythonize -i some/package", where "-i" requests to compile and build the extensions "in place", i.e. next to their sources. Oh, and while we`re at it, compiling packages (i.e. "__init__.py" files) actually works in Python 3.3 now.

Extension types behave a bit more smartly at garbage collection time. When an attribute is declared with a known builtin type that cannot produce reference cycles (e.g. strings), then it is automatically excluded from the garbage collection visitor. This reduces the traversal overhead when searching for unreachable objects. It can even exclude a type completely from garbage collection traversal if none of its object attributes requires it. And for the previously tricky case that object attributes had to be accessed at finalisation time, there is a new type decorator "@cython.no_gc_clear" that prevents them from being cleared ahead of time when they participate in reference cycles. Certainly way better than a crash.

And finally, the try-finally statement has been optimised to handle each exit case separately, which allows the C compiler to generate much faster code for the "normal" cases.

Since 0.20 isn`t out yet, this list might still grow a bit, but that`s what is there now. Not bad, if you ask me.

No Cython talk at PyCon-US 2014    Posted:

I recently got the rejection notice for the Cython talk I had submitted to next year`s PyCon-"US" (in Montréal). Since none of the Cython core developers had ever managed to go to that conference before, and thus Cython had never had a well founded talk there (and only one talk during the last years that at least mentioned it in its title), I had hoped to catch up with that a bit and give a general overview of what Cython is and when and how to use it for speeding up Python code or for talking to external libraries.

It`s sad to get such a talk rejected, but what`s really worse was their reasoning. It was rejected due to potential lack of interest, completely misjudging it as an "internals" talk for some reason. Seriously? Lack of interest in the most widely used static Python compiler? In the only Python AoT compiler that has a substantial user base? And that loads and loads of people in the Scientific Python community use for their high performance calculations?

Instead, the list of accepted talks includes major Python topics like Lisp, JavaScript and Garbage Collectors. I`m sure those will attract a much broader audience at a Python conference than a niche topic like, you know, speeding up Python code.

Faster stdlib logging    Posted:

I keep reiterating that it would be nice if a couple of Python stdlib modules got compiled by Cython during Python's installation, simply because it makes them faster right away, without sacrificing compatibility. Besides the difflib module, another nice example I found is the logging module. The logging benchmarks in Python's benchmark suite run between 20% and 50% faster when the module is compiled. Especially the silent logging case is interesting with its ~50%, because a lot of log messages really never end up in a log somewhere, so you can leave more log statements in your code to activate them at need. And I'm sure there's still a bit more to gain here by adding a couple of static type declarations in the right spots of that module. Feel free to give it a try.

Cython vs. binding generators    Posted:

This year's PyCon-US included a talk with the rather lurid title "Cython vs. SWIG, Fight!". I'm sure many of the attendees expected something different than they actually got, which was mostly a featurewise comparison at the "this is how some basic examples might look" level. In fact, I think the difference between Cython and SWIG, or actually Cython and any of those binding generators or wrapping tools, can be summarised in two words. They are binding generators, whereas Cython is a programming language, with all its expressiveness.

Cython's main selling point is that it completely blurs the border between Python and C. A binding generator, or a foreign language interface tool like ctypes or cffi, will only ever give you the choice of two extremes:

  1. write your code in Python and let it talk to wrapped C, or
  2. write your code in C and wrap it.

Either easy or hard, nothing in between, and it's not always your choice. They give you no help at all with the parts where it needs to be hard for some reason, and some do not even reduce that unfriendly feeling of working with truly foreign code. Even worse, these tools usually have a very specific idea about how the wrapping should look like, so if you come to a point where you're not happy with the way they work, you'll have to start working against the tool.

Cython is different. With Cython, you can

  1. write your code in Python and let it talk to wrapped C
  2. compile your Python code
  3. add static type declarations to your Python code to specialise and speed up the result of the compilation
  4. change your Python code file extension to ".pyx" to start using elements of the Cython language that let your code talk to C directly (note that this makes it Cython code)
  5. write your code in the Cython language and freely mix elements of Python and C, talking to both sides natively
  6. write your code in C and wrap it

So it opens up that entire huge grey area between those two extremes that you get from other tools. It lets you freely choose the tradeoff between simplicity and speed, and makes it very easy to move gradually between one and the other.

Want to reduce complexity and use fast, high-level tools? Use Python constructs. Compiling them in Cython makes them even faster by statically analysing and optimising your code and inferring types for you. And it allows you to give the compiler explicit static type hints that reduce overhead and specialise your code even further.

Want low-level speed? Move closer to C constructs, in exactly those areas in your code that need it. Any point along that gradient is right at your finger tips. Need to talk to C, C++, Fortran, maybe other languages? Without having to go through a level of indirection that bites right into your performance benefit? You can. Cython makes this easy, actually "normal".

And, we're always interested in improving the "static type declarations in Python code" kind of usage (which we call "pure Python mode"), so if you want to help extending the expressiveness of Cython's type declarations for pure Python code to further blur the gradients for users, you should talk to us about it. We have a mailing list.

Bugs in CPython extension modules    Posted:

A while back, I wrote up my opinion on writing CPython extensions by hand, using the C-API. Most of the replies I got were asking for a proof, but the article was more of a summary of my prior experience than anything really new.

Now, David Malcolm, author of the GCC Python plugin, has given a talk at this year's PyCon-US where he used a static analysis tool chain that he's been working on based on his GCC plugin to find bugs in CPython extension modules. Being a Fedora developer, he ran it against the wealth of binary Python packages in that distribution and ended up finding a lot of bugs. Very unsurprisingly to me, most of them were refcount bugs, mainly memory leaks, especially in error handling cases, but also lots of other issues with reference handling, e.g. missing NULL/error tests etc. At the end of the talk, he was asked what bugs his tools found not only in manually written code but in generated code, specifically C code generated by Cython. He answered that it was rather the other way round: he had used Cython generated code to prune false positives from his analysis tool, because it was quite obvious that the code that Cython generated was actually correct.

I think that nicely supports what I wrote in my last post.

Writing C code is a premature optimisation    Posted:

It seems I can't repeat this often enough. People who write Python wrappers for libraries in plain C "because it's faster" tend to overestimate their C-API skills and simply have no idea how costly maintenance is. It's like the old advice about optimisation: Don't do it! (and, if you're an expert: Don't do it yet!). If you write your wrapper code in C instead of Cython, it will be
  • slower
  • less portable
  • harder to maintain
  • harder to extend
  • harder to optimise
  • harder to debug and fix

It will cost you a lot of effort, both short term and long term, that is much better spent in adding cool features and optimising the performance critical parts of your code once you got it working. Say, is your time really so cheap that you want to waste it writing C code?

Cython on Android    Posted:

I just took a quick glance at the source code of kivy. It seems that "Python on Android" is brought to you by "Cython on Android".

Stecker raus    Posted:

München sollte öfter mal ohne Strom dastehen. Ich kann mich nicht erinnern, dass die Autos schon jemals dermaßen zivilisiert durch die Stadt gefahren sind.

A static Python compiler? What's the point?    Posted:

I've finally found the time to look through the talks of this year's EuroPython (which I didn't attend - I mean, Firenze? In plain summer? Seriously?). That made me stumble over a rather lengthy talk by Kay Hayen about his Nuitka compiler project. It took more than an hour, almost one and a half. I had to skip ahead through the video more than once. Certainly reminded me that it's a good idea to keep my own talks short.

Apparently, there was a mixed reception of that talk. Some people seemed to be heavily impressed, others didn't like it at all. According to the comments, Guido was more in the latter camp. I can understand that. The way Kay presented his project was not very convincing. The only "excuse" he had for its existence was basically "I do it in my spare time" and "I don't like the alternatives". In the stream of details that he presented, he completely failed to make the case for a static Python compiler at all. And Guido's little remark in his keynote that "some people still try to do this" showed once again that this case must still be made.

So, what's the problem with static Python compilers, compared to static compilers for other languages? Python can obviously be translated into static code, the mere fact that it can be interpreted shows that. Simply chaining all code that the interpreter executes will yield a static code representation. However, that doesn't answer the question whether it's worth doing. The interpreter in CPython is a much more compact piece of code than the result of such a translation would be, and it's also much simpler. The trace pruning that HotPy does, according to another talk at the same conference, is a very good example for the complexity involved. The fact that ShedSkin and PyPy's RPython do explicitly not try to implement the whole Python language speaks volumes. And the overhead of an additional compilation step is actually something that drives many people to use the Python interpreter in the first place. Static compilation is not a virtue. Thus, I would expect an excuse for writing a static translator from anyone who attempts it. The normal excuse that people bring forward is "because it's faster". Faster than interpretation.

Now, Python is a dynamic language, which makes static translation difficult already, but it's a dynamic language where side-effects are the normal case rather than an exception. That means that static analysis and optimisation can never be as effective as runtime analysis and optimisation, not with a resonable effort. At least WPA (whole program analysis) would be required in order to make static optimisations as effective as runtime optimisations, but both ShedSkin and RPython make it clear that this can only be done for a limited subset of the language. And it obviously requires the whole program to be available at compile time, which is usually not the case, if only due to the excessive resource requirements of a WPA. PyPy is a great example, compiling its RPython sources takes tons of memory and a ridiculous amount of time.

That's why I don't think that "because it's faster" catches it, not as plain as that. The case for a static compiler must be that "it solves a problem". Cython does that. People don't use Cython because it has such a great Python code optimiser. Plain, unmodified Python code compiled by Cython, while usually faster than interpretation in CPython, will often be slower and sometimes several times slower than what PyPy's JIT driven optimiser gets out of it. No, people use Cython because it helps them solve a problem. Which is either that they want to connect to external non-Python libraries from Python code or that they want to be able to manually optimise their code, or both. It's manual code optimisation and tuning where static compilers are great. Runtime optimisers can't give you that and interpreters obviously won't give you that either. The whole selling point of Cython is not that it will make Python code magically run fast all by itself, but that it allows users to tremendously expand the range of manual optimisations that they can apply to their Python code, up to the point where it's no longer Python code but essentially C code in a Python-like syntax, or even plain C code that they interface with as if it was Python code. And this works completely seamlessly, without building new language barriers along the way.

So, the point is not that Cython is a static Python compiler, the point is that it is more than a Python compiler. It solves a problem in addition to just being a compiler. People have been trying to write static compilers for Python over and over again, but all of them fail to provide that additional feature that can make them useful to a broad audience. I don't mind them doing that, having fun writing code is a perfectly valid reason to do it. But they shouldn't expect others to start raving about the result, unless they can provide more than just static compilation.