Django: migrations.

Bardzo mi odpowiada ewolucja Django od czasu kiedy ostatni raz coś w nim robiłem, a było to kilka lat temu. Krótko mówiąc, nadal mam wrażenie jakby to były spodnie szyte na miarę lub śrubokręt, który idealnie leży w łapie i odkręci każdą śrubkę ;). Nie mam uczucia ewolucyjnego zagubienia. To tylko dobrze świadczy o projekcie, bo to co było kiedyś, nie zostało w ciągu tych kilku lat przepisane, najlepiej od zera. Mogło się tak stać tylko dlatego, że już na etapie 1.0-1.4, kiedy poznawałem ten framework, wszystko było zrobione jak należy.

Dziś trafiłem na prezentację o Django Migrations wygłoszoną podczas tegorocznego Pycon. Piękna sprawa:

Msys2/Mingw-w64, Cython i Ipython Notebook.

Ipython Notebook z Mingw-w64-gcc/MSYS2 działa ładnie pod Windows.

cython_notebook Zeromq, jinja2 i sqlite są w repo MSYS2 więc można je zainstalować pacmanem. pyzmq, tornado i pysegments instaluje się przez pip, który jest w paczce mingw-w64-i686-python3-pip.

Super sprawa do testów Cythona i Pythona. W oficjalnym Pythonie nie udało mi się zmusić mingw-w64-gcc do kompilowania Cythona, choć wszystkie zależności notepada instalują się ładnie z pip.

Python vs Cython vs PyPy.

Moich tendencyjnych eksperymentów ciąg dalszy. Zrezygnowałem z Numpy i jestem pod wrażeniem memoryviews w Cythonie. Poniższe to tak na prawdę test wydajności adresowania tablic jednowymiarowych.

Python:

import sys
import random

def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return a

def showfib(n):
    r = []
    for i in range(n):
        t = fib(random.randint(0,49))
        r.append(t)
        print(t, end=" ")
    print()

if __name__ == '__main__':
    n=int(sys.argv[1])
    showfib(n)

Cython:

#cython: language_level=3, boundscheck=False

import sys
from libc.stdio cimport printf
from libc.stdlib cimport rand, srand
from cython.view cimport array
from time import time

cdef unsigned int fib(int m) nogil:
    cdef unsigned int a, b, i
    a, b = 0, 1
    for i in range(m):
        a, b = b, a + b
    return a

cdef showfib(n):
    cdef r = array(shape=(n,), itemsize=sizeof(unsigned int), format="I")
    cdef unsigned int [:] rv = r

    cdef int i
    cdef unsigned int t
    for i in range(n):
        t = fib(rand()%49)
        rv[i] = t
        printf("%u ", t)
    printf("\n")

if __name__ == '__main__':
    n=int(sys.argv[1])
    srand(int(time()))
    showfib(n)

Python-3.4.2:
$ time python fib.py 300000 > /dev/null
real 0m7.564s
user 0m7.543s
sys 0m0.013s

PyPy3-2.4 (portable):
$ time pypy fib.py 300000 > /dev/null
real 0m1.838s
user 0m1.813s
sys 0m0.020s

Cython-0.21.1:
$ time ./fib 300000 > /dev/null
real 0m0.189s
user 0m0.190s
sys 0m0.000s

Cython vs Python: 40,02 x szybciej.
Pypy vs Python: 4,11 x szybciej.
Cython vs PyPy: 9,72 x szybciej.

Msys2 – toolchain idealny.

Idąc jak po nitce do kłębka, w końcu trafiłem na Msys2, czyli minimalny zestaw narzędzi systemowych, oparty o narzędzia uniksowe (głównie GNU) dla Windows.

msys2
Co się najbardziej rzuca w oczy w tym zrzucie? 🙂 Ano pacman. Tak, ten sam pacman co w Arch Linuksie, którego używam na co dzień. Co za tym idzie? Wszystkie pakiety (kompilator, biblioteki, python, narzędzia) i kompletne środowisko GNU, są w repo projektu, więc aktualizacja (pod Windows!) to standardowe: pacman -Suy, a przebudowanie pakietu wg własnego uznania to edycja prostych, jak konstrukcja przysłowiowego cepa plików PKGBUILD.

Dla mnie Msys2 to brakujący element systemów Windowsowych.

Cython – kompilacja programów w Pythonie mingw-w64 dla Windows.

Dawno nie miałem takiej motywacji do programowania. Cztery dni poszukiwań, grzebania w strzępkach dokumentacji i przykładach. W końcu się udało. Ale od początku. Postanowiłem trochę odświeżyć wiadomości o Pythonie i natrafiłem na Cythona, który mnie zafascynował, ale miałem problem z kodowaniem argumentów programów (sys.argv) do obiektów unikodowych pod Windows (argv w Windows jest w UTF-16, wchar_t **). W żaden sposób nie dało się ich dekodować do Unicode, a binarki dla Linuksa działały bez problemu. Pal licho argv ale to samo dotyczyło kodowania nazw plików. Przetestowałem kilkadziesiąt funkcji C-API Pythona i nic.  Skonwertowanie windowsowych szerokich argumentow (wchar_t **) argv z UTF-16 do UTF-8 wydawało się niemożliwe. Aż w jakimś archiwum ircowym trafiłem na wzmiankę, że bez flagi -municode mingw-gcc nie obsługuje pod Windows poprawnie kodowania linii cmd.

Co ciekawe, od początku wydawało mi się celowe generowanie entrypoint-a przez Cythona dla Windows jako:

int wmain(int argc, wchar_t **argv)

Okazuje się, że po dodaniu -municode do gcc mingw-w64 jako entrypoint traktuje właśnie wmain() i używa odpowiednich wersji funkcji z obsługą unicode. Niestety w mingw-gcc 4.8.1 nie ma opcji -municode i wiele osób pewnie z tego powodu ma problemy.  W gcc-4.8.1 z mingw-w64 działa jak należy, jest nawet o tym informacja na stronie projektu:

http://sourceforge.net/p/mingw-w64/wiki2/Unicode%20apps/

Szkoda, że wcześniej tego nie znalazłem ;(.

aconv

Przykładowa konwersja i kompilacja wygląda tak, w Windows w MSYS:

/c/Python34/Scripts/cython.exe -3 --embed aconv.py
gcc aconv.c -I /c/mingw/python/include/python3.4m -L /c/mingw/python/lib/ -lpyth
on3.4m -municode -o aconv

Podsumowując. Bardzo mnie to cieszy. W Cythonie, poza niemal pełną zgodnością z Pythonem można includować nagłówki z bibliotek w C i bezpośrednio z nich korzystać w modułach pythonowych, z całą dobrocią typów C a pozwala na przyspieszenie kluczowych fragmentów kodu i kompilację nawet całych programów skonwertowanych do C. A w składni wygląda to jak Python.

Pełen respect dla twórców Cythona.