How to finally fix that damned MySQLdb module on Leopard

Ciao ragazzi,

no, non mi sono impazzito, l’articolo √® in italiano ūüėÄ

Oggi voglio parlarvi di un mio esperimento portato a termine con successo. Molti di voi (spero nessuno) avranno perso il sonno nel tentare di far funzionare su leopard il modulo python MySQLdb, assolutamente indispensabile per gestire i database mysql con python, altrettanto indispensabile per usare Django.

Nota ai naviganti:  Se siete su Leopard e dovete ancora installare mysql, allora installate la versione mysql-5.0.67-osx10.4-universal.tar. gz, perchè pare che risolva i problemi di architettura. 

Cosa centra l’architettura? Il problema nasce dal fatto che √® molto facile avere installata una versione di python a 32 bit, il server apache della apple a 64 bit e mysql o a 64 o a 32bit.. di conseguenza quando si prova ad importare il modulo di incappa nel seguente errore:

Traceback (most recent call last):
File ‚Äú‚ÄĚ, line 1, in
File ‚ÄúMySQLdb/__init__.py‚ÄĚ, line 19, in
import _mysql
File ‚Äúbuild/bdist.macosx-10.5-i386/egg/_mysql.py‚ÄĚ, line 7, in
File ‚Äúbuild/bdist.macosx-10.5-i386/egg/_mysql.py‚ÄĚ, line 6, in __bootstrap__
ImportError: dynamic module does not define init function (init_mysql)
>>>

Ma andiamo con ordine.

Installazione e configurazione

Ci sono un sacco di guide sull’ installazione, che vi riporto come references a fine articolo, ma vediamo speditamente cosa fare. Prima di tutto scaricate il modulo dal sito ufficiale di MySQLdb, decomprimetelo ed entrate nella cartella. Per prima cosa dovete aprire il file _mysql.c e ¬†commentare le seguenti linee:

37 //#ifndef uint 
38 //#define uint unsigned int 
39 //#endif 

dove i numeri sono i numeri di riga per una facile individuazione. Dopodichè cambiate queste altre:

484 unit port = MYSQL_PORT;

deve diventare: unsigned int port = MYSQL_PORT; 
485 unit client_flag = 0;

deve diventare: unsigned int client_flag = 0;

Bene. Ora aprite il file site.cfg e cambiate:

threadsafe = True 

in

threadsafe = False

Ora scaricatevi la versione di mysql che vi ho consigliato qualche riga fa ma NON INSTALLATELA! Piuttosto scompattatela in una cartella a vostro piacere: (es. /Users/vostrahome/mysql/).

A questo punto sempre nel file site.cfg¬†aggiungete (o modificate se c’√®) la seguente riga:

 

mysql_config = /Users/vostrahome/mysql/bin/mysql_config

dove /Users/vostrahome/mysql è la cartella dove avete decompresso la versione scaricata di mysql.

Perfetto! Adesso la procedura d’installazione dovrebbe andare per il meglio. Lanciate da shell:

python setup.py build
sudo python setup.py install

E dovrebbe filare tutto liscio. Adesso create un soft link in questo modo:

sudo ln -s /usr/local/mysql/lib/ /usr/local/mysql/lib/mysql

Poichè siamo su Mac o non su Linux. Di solito a questo punto dovreste avere una versione di MySQLdb funzionante. Per me non è stato così. Nel mio caso ha funzionato copiare la cartella lib contenuta in /Users/vostrahome/mysql dentro la mia directory di installazione di mysql, cioè /usr/local/mysql/lib/.

Per chi non fosse pratico di permessi e cose varie, prima fate un backup delle vecchie librerie :

cd /usr/local/mysql/
sudo cp -R lib lib.bak
cd lib
sudo rm *
cd ..
sudo rmdir lib
sudo cp -R /Users/vostrahome/mysql/lib /usr/local/mysql/

A questo punto se tutto è andato bene dovreste avere il vostro MySQLdb funzionante!

Ogni macchina √® diversa dalle altre, quindi c’√® la possibilit√† che la procedura che vi ho descritto possa non funzionare sui vostri computer. Per questo vi lascio dei link utili dove viene spiegato lo stesso procedimento ma con approcci diversi. Alla prossima, ciao!

Alfredo

REFERENCES:

Problems in Building 1.2.2 on Mac Os 10.5

David Cramer.net – MySQLdb on Leopard

Antonio Cangiano – How to install Django with MySQLdb on MacOSx

Annunci

PyPills – Lezione 2 – Stream, parsing and many more!

Buongiorno a tutti. Oggi vi voglio parlare di come è fatto un processo. Potete immaginare un processo come una scatola nera o meglio ancora, per chi ha fatto un minimo di elettronica, come un tripolo (sennò cercate transistor su wikipedia).

Un processo nasce, cresce e muore con 3 stream “attaccati” ad esso:

Stdin, anche noto come Standard Input, √® lo stream da cui il processo legge gli input provenienti dall’ esterno, tipicamente dall’ utente che l’ha lanciato o da un altro programma.

Stdout, anche noto come Standard Output, è lo stream di dati che un processo produce alla fine del suo job, volgarmente detto risultato.

Stderr, anche noto come Standard Error √® lo stream in cui il programma “vomita” eventuali codici d’errore a seguito di un comportamento inaspettato.

Perchè vi dico tutto questo? Il python nasce come glue, come colla, è infatti molto usato come collante tra vari programmi. Fortunatamente per noi esiste una tecnica nota come pipelining che permette di destinare lo stdout di un processo A come stdin di un altro processo, creano cosi vere e proprie pipeline (catene di montaggio). Chi ha familiarità con il mondo Unix non si stupirà delle mie parole. Un esempio?

cat /etc/pippo.txt | wc -l

Cosa abbiamo fatto? Abbiamo letto un file con cat e abbiamo mandato lo stdout di cat in input a wc, che ci ha calcolato il numero di linee del nostro file di testo. Ma ora veniamo al python.

Su Python-it.org si era intavolata una conversazione su come fosse possibile recuperare le informazioni da un file, ad esempio come da un file MP3 fosse possibile recuperare le ID3. L’utente Flame_Alchemist, che ringrazio, ha fatto osservare che tali info, qualora presenti, risiedono nei primi 128 byte del file Mp3.

Ecco allora l’idea: sfruttiamo un tool Unix chiamato hexdump (calma Linuxofili, funziona anche da voi ūüėÄ ) che permette di fare il dump esadecimale di qualsiasi file e poi, col nostro amato Python, ci andiamo a recuperare le informazioni che vogliamo. E’ rozzo e probabilmente non lo userete mai, l’ho scritto solo per farvi vedere due cose:

-Come sia possibile gestire il pipeline in un programma python

-Uno studio di caso di come si realizza un banale parser a partire da un dump esadecimale.

import sys

import os

class Id3Parser:

    def __init__(self):

        self.input = str.split(str.rstrip(sys.stdin.read()),"\n")

    def get_char_list(self):

        '''Ritorna il dump cosi come e' stato preso in stdin, ogni carattere

        rappresenta una cifra esadecimale'''

        return self.input

    def get_hex_list(self):

        '''Permette di ottenere una lista con il valore decimale di tutti

        i caratteri esadecimale presi da stdin'''

        hex_list = [self.hexstr2ascii(el) for el in self.input]

        return hex_list

    def get_ascii_list(self):

        '''Questa funzione preso un valore decimale ne trova il corrispettivo

        valore ascii, comprimento la lista in modo che i caratteri non ascii

        (minori di 32 in decimale) facciano da spaziatore tra un carattere

        valido e l'altro'''

        lst =[]

        prev=0

        for el in self.get_hex_list():

            if el < 32 and prev < 32:

                continue

            elif el < 32 and prev > 32:

                lst.append("00")

            else:

                lst.append(chr(el))

            prev = el

        return lst

    def hexstr2ascii(self, value):

        '''Questa funzione, preso un qualsiasi valore ascii rappresentante un

        esadecimale (es. '4B') ne trova il corrispettivo valore decimale.'''

        symbol_dict={'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,

                     '6':6,'7':7,'8':8,'9':9,

                     'A':10,'B':11,'C':12,'D':13,'E':14,'F':15}

        fst_hex = symbol_dict[value[0]]

        snd_hex = symbol_dict[value[1]]

        return (fst_hex*16 + snd_hex)

    def get_info_list(self):

        '''Questa funzione ritorna una lista delle informazioni sensibili.'''

        lst=[]

        info=""

        for el in self.get_ascii_list():

            if (el == "00"):

                lst.append(info)

                info=""

                continue

            else:

                info+=el

        return lst

if __name__ == "__main__":

    from id3parser import Id3Parser

    parser = Id3Parser()

    print parser.get_info_list()

COME SI USA:

Da shell:

$ hexdump -n 128 -v -e ‘1/1 “%02X” “\n”‘ <nome_file> | python id3parser.py

dove al posto di nome_file dovete mettere il titolo della canzone.

NOTA: Poichè il blog converte gli apici e i doppi apici in backquote, vi invito a riscrivervi tali apici se copiate ed incollate il codice nella shell, altrimenti non funziona (ringrazio Eugenio per la segnalazione).

Ci sono altri n-mila modi di farlo, mi interessava farlo così per farvi vedere come python sia un valido collante tra processi applicativi.

Vi allego come sempre il codice, alla prossima!

Alfredo Di Napoli

Codice: id3parser.py

Crittografia pure-python? Si, grazie!

Articolo scritto da Simone Ramacci “Simosito” e pubblicato prima su python-it.org e poi qui per sua gentile concessione.

¬†Oggi vi voglio segnalare l’implementazione¬†pure-python¬†di due algoritmi abbastanza celebri: Blowfish e Rijndael (per gli amici AES).

Blowfish.py

Grazie all’impegno di Ivan Voras √® possibile utilizzare¬†Blowfish¬†per testi di lunghezza arbitraria.

Esempio (test1a.py)

import blowfish 

from hashlib import sha256

testo="Ciao, come va?" 

cipher = blowfish.Blowfish(sha256('key').digest()) 

print('Cripto')

#inizializzo CTR 

cipher.initCTR() 

ctxt=cipher.encryptCTR(testo) 

print('DeCripto') 

#idem 

cipher.initCTR() 

txt=cipher.decryptCTR(ctxt) 

print(txt)

Questo semplice codice mostra abbastanza bene l’uso di questo modulo.
√ą importante ricordarsi di inizializzare sempre CTR altrimenti si rimane per mesi a sbattere la testa su un errore di encoding molto antipatico.

Rijndael.py

Jeffrey Clement ci porta invece un simpatico modulo per utilizzare AES

Esempio (test2a.py)

import rijndael as r
from hashlib import sha256
key=sha256('key').digest()
testo="Ciao, come va?"
print("Cripto")
ctxt=r.EncryptData(key,testo)
print("DeCripto")
txt=r.DecryptData(key,ctxt)
print(txt)

Questo semplice codice mostra abbastanza bene l’uso di questo modulo.¬†
Come si pu√≤ notare non c’√® bisogno di nessuna inizializzazione.

Performances

Per questo test √® stato usato un file di 66926 byte contenente caratteri Unicode, il¬†Romeo e Giulietta¬†di Bandello, che ispir√≤ l’opera di Shakespeare.

Codifica e decodifica


 Algoritmo  real time
user time
 Blowfish 0m2.812s 0m2.804s
 Rijndael 0m10.576s  0m10.381s
 Blowfish+psyco 0m1.440s 0m1.300s
Rijndael+psyco 0m2.400s 0m2.344s

 

Codifica

 Algoritmo  real time
user time
 Blowfish 0m1.477s 0m1.416s
 Rijndael 0m5.163s 0m5.040s
 Blowfish+psyco 0m0.693s 0m0.668s
Rijndael+psyco 0m1.216s 0m1.200s

 

Il computer utilizzato per il test è un dual core 1.8 GHz con 2 Gb di RAM (24.5 % già occupato).
Nello scegliere uno dei due algoritmi si tenga presente che forniscono livelli di sicurezza differenti.”

Buon 2009

Ed eccoci qui, tra un panettone,un pandoro, un torronte, un panforte, un […] , anche un altro anno √® passato. Come √® stato per voi questo 2008?

Da un punto di vista universitario (A.A 2007/2008 ) √® stata un annata eccezionale, 11 esami in 9 mesi, e spero di tenere alto questo ritmo in modo da potermi laureare ad ottobre con un buon voto (io spero 110). Spero che per voi quest’ anno sia un anno positivo, pieno di soddisfazioni.. Per ora studiate il Python pi√Ļ che potete !

Buon 2009!

Alfredo