Visualizzazione post con etichetta programmazione. Mostra tutti i post
Visualizzazione post con etichetta programmazione. Mostra tutti i post

Ack: uno strumento raffinato per curiosare nei file di testo

Nel mondo unix lo strumento principe per cercare stringhe nei file di testo e' sempre stato grep

Il programma grep (acronimo di global / regular expression / print) e' uno strumento che non puo' mancare nella cassetta degli attrezzi di uno sviluppatore. Anni e anni di sviluppo ne hanno affinato le potenzialita'. La pagina di manuale di grep e' una vera fonte di nuovi ed interessanti utilizzi per questo capolavoro di software.

Nel mio lavoro mi sono spesso giovato dalla definizione di un alias che mi permette di adattare grep alle mie esigenze:

[ale@chandra ~]$grep grep .bashrc
alias grep="grep --color --exclude-dir=.svn --exclude={*.pyc,*~,*.pyo}"

Questo alias mi garantisce un output colorato, esclude le directory svn e file che non mi interessano.

Nonostante il mio infinito rispetto per grep, ultimamente devo ammettere di usarlo meno del solito. La regione di tutto cio' e' che ho cominciato ad usare ack (link).

Ack, a differenza di grep, e' meno "general purpose": mentre grep cerca in ogni file, ack evita di perdere tempo in file binary, in cartelle di sistemi di revisione del codice (svn, git, mercurial, ecc...) e in file di backup. Inoltre ha gia' di default l'output colorato, e la cosa non guasta di certo! Praticamente tutte le cose che ho dovuto specificare nel mio alias, ack le fa di default. Ma non e' finita :)

Caratteristica peculiare di ack e' la possibilita' specificare tipi di file per gruppi. Per esempio uno sviluppatore plone trarra' vantaggio dall'opzione --plone (che restringe la ricerca a file con estensione py, cpy, pt, metadata, ecc... ) mentre uno sviluppatore c++ potra usare il flag --cpp (che ricerca nei file cpp, cc, h ecc...). Ovviamente tali gruppi sono personalizzabili.

Come se non bastasse, ack di default analizza ricorsivamente la directory corrente, mentre grep di default analizza lo standard input, cosa che si adatta sicuramente di piu' alle mie esigenze.

Ma non voglio andare oltre nell'illustrarvi le peculiarita' di questo software. Mi limito ad invitarvi a provarlo sicuro che anche voi, come me, ne apprezzerete la comodita'.

Ack homepage: http://petdance.com/ack/

Ripristinare lo stato delle variabili locali in Python

Esempio istruttivo che mostra come cancellare variabili in un programma Python
Quanto leggerete qui di seguito vi mostrera' alcune tecniche che raramente userete in codice di produzione, ma nonostante tutto sono di indubbio interesse le enormi potenzialita' che il linguaggio di programmazione mette a disposizione dei suoi utenti.


Utilizzeremo in questo esempio, una shell Python interattiva, ma il codice funzionera' altrettanto bene se lanciato dall'interprete.
Il nostro scopo e' definire un numero indefinito di nuove variabili e poi cancellarle. E' possibile ottenere un dizionario delle variabili locali usando la funzione builtin locals.
Subito dopo aver avviato la shell fotografiamo lo stato delle variabili locali, salvando le chiavi di suddetto dizionario in una variabile di nome oldlocals.

>>> oldlocals=locals().keys()

Definiamo ora alcune variabili nuove.

>>> a,b,c,d = 1,2,3,4

Il contenuto di locals sara' diversi ora:

>>> newlocals=locals().keys()
>>> oldlocals
['__builtins__', '__file__', '__name__', 'readline', 'rlcompleter', '__doc__']
>>> newlocals
['a', 'oldlocals', 'b', 'd', '__builtins__', '__file__', 'c', '__name__', 'readline', 'rlcompleter', '__doc__']

Per cancellare le variabili definite dopo la nostra "foto" possiamo usare le funzioni insiemistiche del tipo set.

>>> newly_defined=set(newlocals).difference(oldlocals).difference(set(('oldlocals',)))
>>> newly_defined
set(['a', 'c', 'b', 'd'])
>>> a,b,c,d
(1, 2, 3, 4)

Ora andiamo a cancellare le variabili che siamo andati a definire.

>>> for var in newly_defined: del(locals()[var])
...
>>> a,b,c,d
Traceback (most recent call last):
File "", line 1, in
NameError: name 'a' is not defined
>>>

Perfetto, ora le variabili a,b,c e d sono libere!

Il discorso si potrebbe approfondire con risvolti molto interessanti: ad esempio potrete eliminare solo le variabili di un determinato tipo o le istanze di una certa classe.
Lascio a voi tutto il divertimento.

Python nose: scrivere test senza fatica per il nostro codice

Presto o tardi chi scrive codice deve fare i conti con imprevisti!
Uno dei modi per evitare sorprese e' quello di testare il codice scrivendo dei test che ne confermino la validita' di funzionamento.

Chi scrive codice in Python potra' giovarsi dalle comodita' offerte da Python Nose per scrivere test senza grossa fatica. La particolarita' di Python Nose e' che riesce a scovare le funzioni e le classi di test nel codice basandosi sul loro nome e senza bisogno di importare moduli esterni.

Per esempio...

Supposto che abbiate installato nose, andiamo a cimentarci con una funzione molto semplice ma che puo' riservare sorprese!
Guardate qua:
def fattoriale(n):
"""Funzione ricorsiva per il calcolo del fattoriale di un mnumero
"""
if n == 0:
return 1
else:
return fattoriale(n-1)*n
Che ne pensate? A prima vista sembra scritta bene, ma in realta' riserva qualche sorpresa.
Prima di tutto siamo sicuri funzioni?

Per esserne certi salviamo questa funzione in un file con estensione ".py" e aggiungiamo ad essa una prima funzione di validazione che controlli che i risultati siano corretti.
Affinche' nose si accorga della funzione di test, il suo nome dovra' contenere il prefisso "test" (geniale! :)). Il concetto e' che il test avra' successo la funzione ritornera' dei valori coerenti con quelli che sono calcolabili per altra via. Ad esempio i fattoriali dei numeri 0,1,2,3,4,5 corrispondono ai valori 1,1,2,6,24 e 120.
E' ovvio che se troviamo risultati diversi da questi significa che qualcosa nella funzione non torna.

La funzione che fa il test assomigliera' a questa:
def test_fattoriale():
"""Funzione invocata per testare la correttezza nel calcolo
"""
checks = (1,1,2,6,25,120)
for i, check in enumerate(checks):
f = fattoriale(i)
assert f == check,\
"Il fattoriale di %s e' %s" % (f, check)
Come vedete definiamo nella variabile checks i valori "corretti" e li confrontiamo con quelli che andremo a calcolare con la nostra fantastica funzione!

Il vostro file, fatto questo, assomigliera' a questo:

#!/usr/bin/env python
def fattoriale(n):
"""Funzione ricorsiva per il calcolo del fattoriale di un mnumero
"""
if n == 0:
return 1
else:
return fattoriale(n-1)*n

def test_fattoriale():
"""Funzione invocata per testare la correttezza nel calcolo
"""
checks = (1,1,2,6,25,120)
for i, check in enumerate(checks):
f = fattoriale(i)
assert f == check,\
"Il fattoriale di %s e' %s" % (f, check)
E' arrivato il momento della verita'!!!
Per lanciare il test date il comando nosetest seguito dal nome del file, ad es.:
nosetests prova.py

A questo punto dovreste scoprire che il test e' miseramente fallito!
Il motivo di questo non sta nella funzione bensi' nel test, che e' scritto male... Infatti come ci dice l'output si aspettava che il fattoriale di 4 fosse 25 (non 24 come si puo' ottenere moltiplicando i numeri interi da uno a quattro e come giustamente sostiene la funzione scritta).

Correggiamo la tupla di controllo, sostituendo 25 con 24 e rilanciamo il test. Questa volta tutto dovrebbe filare liscio.

Aggiungiamo test meno banali
Come avete visto la funziona supera brillantemente il test. Pero' fallira' quest'altro test:
def test_tipo():
"""Controlla che la funzione fattoriale ritorni un numero di tipo long
"""
for i in (0,1,2,10,200):
assert type(fattoriale(i)) == long ,\
"Il fattoriale di %s non e' di tipo long!" % i

Questo potrebbe rappresentare un problema in certi casi!
Per far passare alla funzione il test occorre modificarla in questo modo:
#!/usr/bin/env python
def fattoriale(n):
"""Funzione ricorsiva per il calcolo del fattoriale di un mnumero
"""
if n == 0:
return 1L
else:
return fattoriale(n-1)*n

Come vedete nel caso n sia 0 ritorna 1L, (prima ritornava semplicemente 1) ovvero un intero di tipo long. Questo forzera' il tipo del risultato ritornato dalle altre iterazioni, facendoci passare il test!

Fattoriale di un numero molto alto
La nostra funzione non e' ancora a prova di bomba. Facciamola scoppiare!
def test_boom():
"""Controlliamo che la funzione reagisca bene quando si trova a che fare
con numeri grandi
"""
fattoriale(1e10)
Per fare in modo che la funzione gestisca questo test occorrera' gestire l'eccezione che viene sollevata nel caso in cui il numero di cui si vuole calcolare il fattoriale sia troppo alto.

Gmail e kontact amici per la pelle

Tempo fa avevo trovato questo articolo e mi era piaciuto molto.
L'ho seguito passo passo ed ora vi posso dire che ha funzionato proprio per bene: e' oramai un mese che l'unica account di posta che uso e' gmail, che mi ringrazio di tutto cuore perche' mi offre la comodita' di avere la mia posta al sicuro[1], sempre accessibile [2].
In aggiunta l'enorme spazio disco disponibile si puo' sfruttare anche per caricare dei file (vedi il mio articolo su gmailfs).

Essendomi trovato bene ho pensato di tradurlo.
Purtroppo mi ci vorra' un po' di tempo :(
Nell'attesa che renda disponibile la traduzione, vi invito a dare un'occhiata alla versione originale in lingua inglese.

[1] Ebbene si', mi fido di Google! O meglio, mi fido poco della segretezza dei miei dati personali in generale: piuttosto che diventare paranoico, cercando di prendere precauzioni inutili per impedire che si sappia cosa faccio al mondo, ne approfitto e concedo un favore a chi mi fa un favore!

[2] Qualora sia connesso. In realta' e' pure possibile scaricare una copia della casella di posta e sincronizzarla periodicamente, rendendo di fatto fruibile gmail off-line.

PyQt4: inserire una icona nel vassoio di sistema

Una applicazione ospitata nel vassoio di sistema (system tray, in inglese) da grandi vantaggi, quale quello di essere facilmente accessibile, pur occupando uno spazio ridotto. Lo svantaggio di questo tipo di applicazioni e' che spesso il vassoio di sistema e' pieno zeppo di icone.

Qualora trovaste indispensabile aggiungere nel vassoio di sistema la vostra iconcina ma non sapete come fare, allora siete nel posto giusto!
Ecco un esempio commentato che vi spieghera' come cominciare
from PyQt4 import QtCore, QtGui
# Creiamo un'applicazione Qt, ...
app = QtGui.QApplication([])
# e un'icona
icon=QtGui.QIcon("/usr/lib/firefox-2.0.0.10/res/samples/raptor.jpg")
# Mettiamola nel systray
systray=QtGui.QSystemTrayIcon(icon)
# e mostriamola
systray.show()
# Interagiamo con l'utente
titolo="Titolo" # Ma che fantasia!
messaggio="Messaggio per l'utente!\nClicca per chiudere l'applicazione"
tempo=10000 # in millisecondi
systray.showMessage(titolo,
messaggio,
QtGui.QSystemTrayIcon.Information,
tempo)
# connettiamo il click alla chiusura dell'applicazione
QtCore.QObject.connect(systray, QtCore.SIGNAL("messageClicked()"), app.quit)
# Eseguiamo l'applicazione
app.exec_()

Ovviamente potete cambiare il titolo, il messaggio, l'icona, ecc...
Quel che e' certo e' che per rendere l'applicazione interessante e fruibile potreste aggiungerci un menu' contestuale e altre amenita' e impostare connessioni piu' sensate.

PyQt4: creare connessioni signal slot senza usare Qt designer

Qt designer 3 permetteva di creare connessioni a funzioni definite dall'utente. Questa caratteristica e' stata rimossa nella versione 4 poiche' si e' preferito rimanere quanto piu' fedeli possibile al concetto che il designer serve per disegnare e non per programmare.
Le connessioni andranno quindi scritte a mano nel codice.

Il metodo da usare per le connessioni e' QtCore.QObject.connect. Al posto di QtCore.QObject ovviamente mettere qualsiasi oggetto erede di questa classe (una QApplicatio per esempio). Vediamo quali sono gli argomenti corretti da inserire in questo metodo.
Le connessioni ammesse sono tra uno o piu' segnali con uno o piu' slot o segnale e sono schematizzate qui di seguito:
QtCore.QObject.connect(widget1, Segnale, Funzione o metodo Python)
QtCore.QObject.connect(widget1, Segnale, widget2, Slot)
Nel primo caso, che molto probabilmente e' il piu' frequente, viene emesso un segnale dalla widget1 e viene collegato ad una funzione o ad un metodo definito nel nostro codice.
Nel secondo caso il segnale viene collegato ad uno slot della widget 2.

Allo stesso modo e' possibile scollegare gli oggetti in questione con il metodo QtCore.QObject.disconnect.

PyQt4: un tutorial facile facile

Python e qt4 sono un binomio vincente che permette a tutti di realizzare velocemente applicazioni con un accattivante interfaccia grafica. Vediamo come!

Nel corso del mio lavoro di scienziato mi e' capitato di dover sviluppare interfaccie grafiche a programmi scritti da me o da qualcun altro. La prima che sviluppai fu in IDL (per dirla all'ammericana... a pain in the 455!)
Poi mi sono avvicinato alle librerie wx, attratto dalla loro portabilita' e dal fatto di poterle utilizzare con Python. Programmare con le wx mi ha dato parecchie soddisfazioni, ma mai quanto programmare con PyQt4!

Come si fa?
Ora vi mostro come essere operativi da subito!
Realizzeremo un software minimale, in grado di accettare parametri di input e rielaborarli, presentando il risultato ottenuto all'utente!
Posto che le librerie siano installate, aprite qt4 designer:
/usr/lib/qt4/bin/designer # per mandriva
Se designer vi apre una marea di finestre e non vi piace potete usare la modalita' "docked windows" (si setta da un dialogo che si apre dal menu' della finestra principale: "Edit->Preferences...").

A questo punto create un nuovo Form dal menu' file. Per questo tutorial scegliamo la strada della comodita': scegliete "Dialog with buttons: bottom" (vedi Fig. 1)!
Fig.1: Cominciamo da qualcosa di gia' preimpostato
Se tutto e' andato bene dovreste avere qualcosa di simile a quanto mostrato in figura 2... Ora siete pronti a lavorare sul serio!
Fig. 2: L'ambiente di lavoro e' pronto!
Come vedete a sinistra ci sono elementi per creare la parte grafica della nostra applicazione. Mettiamone uno per l'input (il LineEdit) e uno per l'output, un text browser (Fig. 3):
Fig. 3: Inseriamo widget per l'input e l'output
Come vedete fa schifo! Ma non e' un problema! Basta
cliccare su una parte vuota del dialog e poi sul bottone "Lay Out Vertically"... Gia' questo e' sufficiente per ottenere un risultato piu' che gradevole (Fig.4)!
Fig. 4: l'interfacia e' pronta!
Salvatelo in una directory che vi piace con il nome di "myGui.ui" (o quello che vi pare...).
Bene! La parte grafica e' finita... anche se di Python, per ora, non c'e' neanche l'ombra!!!

Comincia la pythonificazione!!!!!
Ora dovrete trasformare la vostra applicazione in codice Python. Facilissimo, basta usare il comando:
pyuic4 myGui.ui -o myGui.py
e siete a posto! Se non trovate pyuic4 probabilmente dovrete installare le librerie di sviluppo di qt4 (per mandriva urpmi python-qt4-devel).
Ora create un altro file chiamato myApp.py, che vi servira' per usare la GUI e per farle fare qualcosa di interessante.

Il motivo per cui e' comodo usare due file e' che se volete potete modificare la GUI con designer e poi riconvertirla in codice Python senza preoccuparvi di perdere del codice!

Nel file metteci questo codice:
#!/usr/bin/env python
from myGui import * # Importa la parte grafica

# La funzione che fa girare il programma
app = QtGui.QApplication([]) # Crea un'applicazione Qt, ...
Dialog = QtGui.QDialog() # ... un dialogo, ...
ui = Ui_Dialog() # ... e una user interface.
ui.setupUi(Dialog) # Infila il dialog nella user interface

def run():
Dialog.show() # mostra il dialog precedentemente creato
return app.exec_() # esegue l'applicazione ed esce dal
# programma ritornando lo stesso intero che ritorna app.exec_()

if __name__ == "__main__":
run()
Il comando python myApp.py gia' dovrebbe presentarvi la vostra interfaccia, perfettamente funzionante: se cliccate sui pulsanti si chiudera'! E cosa doveva fare di piu'?!

Facciamo fare qualcosa di utile alla nostra applicazione!
Effettivamente il programma non e' stato istruito sulle azioni da compiere. La cosa piu' stupida che mi viene in mente e' copiare quello che mettiamo in input, rielaborarlo, e presentarlo come output. Modificate il codice come mostrato aggiungendo le righe in rosso.
#!/usr/bin/env python
from myGui import * # Importa la parte grafica

# La funzione che fa girare il programma
app = QtGui.QApplication([]) # Crea un'applicazione Qt, ...
Dialog = QtGui.QDialog() # ... un dialogo, ...
ui = Ui_Dialog() # ... e una user interface.
ui.setupUi(Dialog) # Infila il dialog nella user interface

# Reimpostiamo la gestione del bottone Ok
def action():
"""Quando Ok viene premuto ricopia il testo in grassetto nel textbrowser"""
ui.textBrowser.setText("%s" % ui.lineEdit.text())

app.disconnect(ui.buttonBox,QtCore.SIGNAL("accepted()"),Dialog.accept)
app.connect(ui.buttonBox,QtCore.SIGNAL("accepted()"),action)

def run():
Dialog.show() # mostra il dialog precedentemente creato
return app.exec_() # esegue l'applicazione ed esce dal
# programma ritornando lo stesso codice che ritorna app.exec_()

if __name__ == "__main__":
run()
Le righe in piu' ridefiniscono il comportamento del bottone Ok, facendogli eseguire il codice nella funzione "action".
Facile no!
Adesso e' compito vostro far fare ai vostri programmi qualcosa di utile per voi e il modo della comunita' open source!

Se avete dubbi o suggerimenti per migliorare questo micro tutorial vi prego di contattarmi!