Es mostren els missatges amb l'etiqueta de comentaris python. Mostrar tots els missatges
Es mostren els missatges amb l'etiqueta de comentaris python. Mostrar tots els missatges

diumenge, 9 d’octubre del 2011

Com accedir a bases de dades SQLite amb Python

En l'exercici d'avui, presento el mòdul pysqlite2 que proporciona una senzilla interfície per a utilitzar SQLite amb Python.

A l'Ubuntu, per a afegir aquest mòdul  n'hi ha prou amb anar al Centre de Programari de l'Ubuntu i instal·lar els paquets python-pysqlite2 i python-pysqlite2-doc.



Cal anar amb compte perquè els números de versió poden crear confusió: trobarem també els mòduls python-pysqlite, però aquests són per a taules de l'anterior SQLite2. Els python-pysqlite2, corresponen a SQLite3, que és la versió actual.

Primer de tot crearé una base de dades SQLite3 de proves amb una taula diccionari. amb tres columnes: id, PK, numèric amb autoincrement; nom, text; valor, text. 

La taula es pot crear de forma senzilla amb l'aplicació gràfica SQLiteman, que permet operar amb taules d'SQLite3. En tot cas, també es pot crear la taula de proves amb la interfície en mode text que proporciona el mateix SQLite3. En cas de no disposar de SQLiteman, aquest es pot instal·lar, com tota la resta, des del Centre de Programari de l'Ubuntu.




L'esquema  

CREATE TABLE "diccionari" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    "nom" TEXT NOT NULL,
    "valor" TEXT NOT NULL
);
CREATE TABLE sqlite_sequence(name,seq);

Un cop creada la taula, la informo amb dades de prova. 

I, a continuació, el codi per a afegir, cercar, esborrar...amb Python i pysqlite2.


#!/usr/bin/python
# coding: latin-1
# python i sqlite

from pysqlite2 import dbapi2 as sqlite

# es connecta a una base de dades
con = sqlite.connect("./prova-sqlite.db")

# itera a través de la taula diccionari amb un cursor
cursor = con.cursor()

# executa el cursor
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files
# obtenir-ne només resultat un: 
print "\n-------------------------------"
print "estat inicial"
for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra
print "id: " + str(iddic) + "; nom: " + nom + "; valor: " + valor

# inserta noves files, amb una seqüència
print "\n-------------------------------"
print "insereix 3 files"
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom6","valor6") )
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom7","valor7") )
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom8","valor8") )

# commit
con.commit();

# a veure què ha fet...
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files
for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra (un mètode alternatiu)
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)

# amb un mapeig
print "\n-------------------------------"
print "insereix 3 files més"
item = {"nom": "nom9", "valor": "valor9"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)
item = {"nom": "nom10", "valor": "valor10"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)
item = {"nom": "nom11", "valor": "valor11"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)

# commit
con.commit();

# tornem a veure què ha fet...
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files
for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra 
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)


#finalment, ho deixo tot com estava al començament
cursor.execute("delete from diccionari where id > 5") 
con.commit()

# ho verifica...
cursor.execute("select id, nom, valor from diccionari")

# itera a través de les files, un mètode alternatiu amb fetchone
print "\n-------------------------------"
print "ho deixa com estava a l'inici"
fila = cursor.fetchone()
while (not (fila is None)):
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)
fila = cursor.fetchone()

# tanca el cursor
cursor.close()

# tanca la connexió
con.close()

Els comentaris del codi en proporcionen les explicacions. Només en destacaria les alternatives idiomàtiques que ofereix Python per a realitzar diverses accions:

Per exemple: un print de diferents variables, i l'alternativa a l'estil del printf de C:

print "id: " + str(iddic) + "; nom: " + nom + "; valor: " + valor

print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)

O aquesta altre: la iteració a través d'un cursor amb for, i uns alternativa amb while 
 
amb for

for fila in cursor:
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra 
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)

amb while:

fila = cursor.fetchone()
while (not (fila is None)):
# recupera els valors
iddic, nom, valor = fila[0], fila[1], fila[2]
# els mostra
print "id: %d; nom: %s; valor: %s" % (iddic, nom, valor)
fila = cursor.fetchone()


Instruccions "preparades" i l'ús de '?', o de variables vinculades a l'insert

amb '?'
cursor.execute("insert into diccionari(nom, valor) values (?, ?)", ("nom6","valor6") )

amb variables vinculades
item = {"nom": "nom11", "valor": "valor11"}
cursor.execute("insert into diccionari(nom, valor) values (:nom, :valor)", item)

I, a continuació, una execució del programa   

albert@atenea:~/wk-python/prova-sqlite$ python prova-sqlite.py 

-------------------------------
estat inicial
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5

-------------------------------
insereix 3 files
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5
id: 45; nom: nom6; valor: valor6
id: 46; nom: nom7; valor: valor7
id: 47; nom: nom8; valor: valor8

-------------------------------
insereix 3 files més
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5
id: 45; nom: nom6; valor: valor6
id: 46; nom: nom7; valor: valor7
id: 47; nom: nom8; valor: valor8
id: 48; nom: nom9; valor: valor9
id: 49; nom: nom10; valor: valor10
id: 50; nom: nom11; valor: valor11

-------------------------------
ho deixa com estava a l'inici
id: 1; nom: nom1; valor: valor1
id: 2; nom: nom2; valor: valor2
id: 3; nom: nom3; valor: valor3
id: 4; nom: nom4; valor: valor4
id: 5; nom: nom5; valor: valor5
albert@atenea:~/wk-python/prova-sqlite$ 

Per saber-ne més, una cerca a Google ens proporcionarà un munt d'enllaços. Tanmateix, cal explicitar la referència fonamental: el lloc de la documentació de Python (http://docs.python.org).

En particular, l'apartat de SQLite 3: http://docs.python.org/library/sqlite3.html


divendres, 2 de setembre del 2011

Python i Tkinter

En un post anterior vaig presentar la construcció d'interfases gràfiques amb Python i Glade. En ewl post d'avui presento la construcció d'interfaces gràfiques amb Python fent us d'una llibreria clàssica i que agermana el llenguatge amb el Tcl/Tk: em refereixo a Tkinter (o tkinter, amb el nom en minúscula, a partir de Python 3.0). Tkinter és una interface entre Python i Tk, d'aqui el nom. Tk és quelcom de diferrent de Python, però tots dos es troben a sistemes Unix. Tkinter permet a Python utilitzar Tk.

Tkinter permet desenvolupar  interfases gràfiques senzilles de forma ràpida. En aquest post faig una senzilla GUI d'exemple. Es tracta d'una pantalla que té dues caixa d'entrada, superior i inferior, i dos botons. En prémer el botó de l'esquerra la informació que hi ha a la caixa superior es mourà a la caixa inferior; i si no hi ha informació a la caixa superior es mostrarà un missatge d'avís. De forma similar, en prémer el botó de la dreta  la informació que hi ha la caixa inferior es mourà a la caixa superior; i si no hi ha  informació a la caixa inferior es mostrarà un missatge d'avís.

El codi és el següent:

#!/usr/bin/python
# coding: latin-1
#
# http://www.tutorialspoint.com/python/
# http://www.astro.washington.edu/users/rowen/TkinterSummary.html
# http://effbot.org/tkinterbook/

import tkMessageBox
from Tkinter import *
# alternativa
# import Tkinter
# Tkinter.Tk()

class App:
	def __init__(self, root):
		Label(root, text='Caixa superior').grid(row=1,column=1, ipadx=5, ipady=5, padx=5, pady=5)
		self.EntryDalt = Entry(root)
		self.EntryDalt.grid(row=1,column=2, ipadx=5, ipady=5, padx=5, pady=5)
		Label(root, text='Caixa inferior').grid(row=2,column=1, ipadx=5, ipady=5, padx=5, pady=5)
		self.EntryBaix = Entry(root)
		self.EntryBaix.grid(row=2,column=2, ipadx=5, ipady=5, padx=5, pady=5)
		Label(root, text='---------------').grid(row=3,column=1, columnspan=2, ipadx=5, ipady=5, padx=5, pady=5)
		Button1 = Button(root, text="Passa de dalt a baix", command=self.Mostra1)
		Button1.grid(row=4,column=1, ipadx=5, ipady=5, padx=5, pady=5)
		Button2 = Button(root, text="Passa de baix a dalt", command=self.Mostra2)
		Button2.grid(row=4,column=2, ipadx=5, ipady=5, padx=5, pady=5)
		
	# de dalt a baix.
	# no passa si no hi ha res a la caixa de dalt.
	def Mostra1(self):
		sEntryDalt = self.EntryDalt.get()

		if sEntryDalt == '':
			tkMessageBox.showinfo("Avís!", "No hi ha text a la caixa superior")
		else:
			# passa de dalt a baix
			self.EntryBaix.delete(0, END)		
			self.EntryDalt.delete(0, END)		
			self.EntryBaix.insert(0,sEntryDalt)

	# de baix a dalt
	# no passa si no hi ha text a la caixa de baix
	def Mostra2(self):
		sEntryBaix = self.EntryBaix.get()

		if sEntryBaix == '':
			tkMessageBox.showinfo("Avís!", "No hi ha text a la caixa inferior")
		else:
			# passa de baix a dalt
			self.EntryDalt.delete(0, END)		
			self.EntryBaix.delete(0, END)		
			self.EntryDalt.insert(0,sEntryBaix)

if __name__ == "__main__":
	root = Tk()
	root.title("Prova TK")
	App(root)	
	root.mainloop()

Uns comentaris al codi anterior,

Primer de tot, la importació de les llibreries: he utilitzat Tkinter i tkMessageBox. tkMessageBox em proporciona un popup de missatges que es pot configurar per a que sigui  d'informació, d'avís, d'error, amb botons d'OK, Cancel, Sí, no... tkMessageBox no és Tkinter, tot i que també es recolza en Tk per a proporcionar el widget de caixa de missatges.

Segon. M'en vaig al final, al main:


if __name__ == "__main__":
	root = Tk()
	root.title("Prova Tkinter")
	App(root)	
	root.mainloop()


Primer de tot, cal dir que una interface amb Tk es pot conceptualitzar com un arbre de widgets, en els que uns són fills (estan inclosos) en d'altres, fins arribar a un primer nivell on tindrem un widget arrel. El primer de tot, doncs, és obtenir  el widget arrel, amb


	root = Tk()

Ara  ja puc afegir (incloure) widgets  fills.

Un cop tinc el widget arrel, el puc configurar. Per exemple, li dono un títol "Prova Tkinter"

	root.title("Prova Tkinter")


A continuació, fent us d'una classe que anomeno App creo la interface.

	App(root)


Finalment, inicio l'interface  invocant el "bucle d'esdeveniments"

	root.mainloop()


Ara és el moment d'analitzar la classe App.

A la classe App he fet que el constructor sigui l'encarregat de col·locar els diferents widgtets a la finestra.
A més, he creat  dos mètodes Mostra1 i Mostra2 que seran la resposta als esdeveniments de prémer el botó esquerra i dret respectivament.

Vet aquí el constructor:

	def __init__(self, root):
		Label(root, text='Caixa superior').grid(row=1,column=1, ipadx=5, ipady=5, padx=5, pady=5)
		self.EntryDalt = Entry(root)
		self.EntryDalt.grid(row=1,column=2, ipadx=5, ipady=5, padx=5, pady=5)
		Label(root, text='Caixa inferior').grid(row=2,column=1, ipadx=5, ipady=5, padx=5, pady=5)
		self.EntryBaix = Entry(root)
		self.EntryBaix.grid(row=2,column=2, ipadx=5, ipady=5, padx=5, pady=5)
		Label(root, text='---------------').grid(row=3,column=1, columnspan=2, ipadx=5, ipady=5, padx=5, pady=5)
		Button1 = Button(root, text="Passa de dalt a baix", command=self.Mostra1)
		Button1.grid(row=4,column=1, ipadx=5, ipady=5, padx=5, pady=5)
		Button2 = Button(root, text="Passa de baix a dalt", command=self.Mostra2)
		Button2.grid(row=4,column=2, ipadx=5, ipady=5, padx=5, pady=5)


El que obtinc és

Els constructors dels widgets Label, Entry i Button prenen un primer paràmetre que és el widget pare del que pengen. Labels i Buttons, a més, prenen una paràmetre de configuració que, en aquest cas es refereix al text a mostrar en Labels i Buttons; els buttons, a més, prenent un tercer paràmetre de configuració que fa apunta al mètode que respondrà a l'esdeveniment per defecte del botó, que és fer-hi clic.

Com és que cada widget va al lloc que li correspon? la clau està al mètode grid() El mètode grid ens permet accedir al gestor de finestra Grid. Hi han d'altres tipus de gestor, com el gestor de finestra Pack, o el gestor de Finestra Place.

Grid és molt senzill de fer servir. La forma com ubica els widgets em recorda una mica a la maquetació amb taules en HTML. El mètode grid rep un conjunt de paràmetres. Per exemple:


Label(root, text='Caixa superior').grid(row=1,column=1, ipadx=5, ipady=5, padx=5, pady=5)


Grid conceptualitza la finestra com una graella rectangular de cel·les.  Cada cel·la pot acollir un widget. La posició d'una cel·la ve definida per la fila/columna. Les files es numeren de dalt a baix començant per l'1. Les columnes d'esquerra a dreta, començant per l'1. Puc agrupar cel·les adjacents en horitzontal i/o vertical.

Tenint en compte això, els paràmetres del Label "Caixa superior" s'expliquen fàcilment: posa el label a la cel·la de la fila 1, columna 1. L'ample de la cel·la s'ajusta automàticament al contingut. Tanmateix, per a fer que la interfase "respiri" dono un marge interior ("padding") entre el límit de la cel·la i la caixa d'entrada de 5píxels (ipadx=5, ipady=5) i un d'exterior entre cel·les, també de 5 píxels (padx=5, pady=5).

Amb la resta de widgets funciona igual. El resultat és que la meva finestra, conceptualment és una graella de dues columnes per quatre files.

A la fila 3 hi ha un exemple del que deia d'agrupar cel·les adjacents

Label(root, text='---------------').grid(row=3,column=1, columnspan=2, ipadx=5, ipady=5, padx=5, pady=5)

en aquest cas, el paràmetre columnspan em diu que la cel·la ocupa dues cel·les en horitzontal. Hi ha un paràmetre rowspan que funciona de la mateixa forma agrupant cel·les en vertical.

Per acabar, els mètodes que responen als esdeveniments Mostra1 i Mostra2 són gairebé idèntics,


	# de dalt a baix.
	# no passa si no hi ha res a la caixa de dalt.
	def Mostra1(self):
		sEntryDalt = self.EntryDalt.get()

		if sEntryDalt == '':
			tkMessageBox.showinfo("Avís!", "No hi ha text a la caixa superior")
		else:
			# passa de dalt a baix
			self.EntryBaix.delete(0, END)		
			self.EntryDalt.delete(0, END)		
			self.EntryBaix.insert(0,sEntryDalt)

	# de baix a dalt
	# no passa si no hi ha text a la caixa de baix
	def Mostra2(self):
		sEntryBaix = self.EntryBaix.get()

		if sEntryBaix == '':
			tkMessageBox.showinfo("Avís!", "No hi ha text a la caixa inferior")
		else:
			# passa de baix a dalt
			self.EntryDalt.delete(0, END)		
			self.EntryBaix.delete(0, END)		
			self.EntryDalt.insert(0,sEntryBaix)


A Mostra1, per exemple, primer de tot, s'obté el contingut del EntryDalt amb el mètode get.

		sEntryDalt = self.EntryDalt.get()


Si el valor obtingut és nul, mostra l'avís

		if sEntryDalt == '':
			tkMessageBox.showinfo("Avís!", "No hi ha text a la caixa superior")

En cas contrari, primer esborra les Entry (mètode delete(0,END))

		else:
			# passa de baix a dalt
			self.EntryDalt.delete(0, END)		
			self.EntryBaix.delete(0, END)	

I, finalment, emplena la caixa inferior

			self.EntryDalt.insert(0,sEntryBaix)


I fins aquí aquest senzill experiment per a prendre contacte amb Tkinter.

Per a més informació, podeu consultar:

La pàgina de Tkinter, http://www.python.org/topics/tkinter/doc.html
Thinking in Tkinter, http://www.ferg.org/thinking_in_tkinter/index.html
Tkinter: GUI programming with Python, http://infohost.nmt.edu/tcc/help/lang/python/tkinter.html
Python. GUI Programming (Tkinter), http://www.tutorialspoint.com/python/python_gui_programming.htm

dilluns, 8 d’agost del 2011

Un retardador de subtítols SubRip amb Python

EL cap de setmana passat em vaig dedicar a buscar subtítols en anglès per a pel·lícules en anglès. Va molt bé per a l'aprenentatge i la pràctica de l'idioma el poder veure la pel·lícula en versió original i, a l'hora, poder llegir el que estan dient en el mateix idioma. I després, tornar a veure la pel·lícula sense subtítols. Són tècniques d'aprenentatge.

El cas és que vaig trobar alguns subtítols però als posar-los al VLC amb la pel·lícula corresponent resultava que no estaven sincronitzats amb la imatge. El VLC permet adelantar o retardar el temps d'aparició dels subtítols, però és poc pràctic, ja que cal sincronitzar cada cop que obres la pel·lícula. O, almenys, no vaig veure com guardar la sincronització; i amb el reproductor de DVD del menjador és pitjor perquè no tinc la  possibilitat de sincronitzar.

Per tant, vaig decidir que la solució era fer un retardador per als subtítols i així generar fitxers de subtítols per a les pel·lícules que tinc i que estiguin correctament sincronitzats amb la imatge.


En el post d'avui, doncs,programo una petita aplicació amb python (versió 2.6.5, un pel antiga, però és la que tinc instal·lada a l'Ubuntu) que servirà per retardar o avançar el moment d'aparició de subtítols en un fitxer de subtítols del tipus SubRip (extensió .srt).

La WikiPedia diu del format SubRip qu és "probablement, el més senzill dels formats de subtítols". Els fitxers SubRip amb extensió .srt, són de text pla. El format de temps emprat és "hores:minuts:segons,milisegons". El separador decimal és una coma, en comptes d'un punt perquè l'especificació original és francesa. El salt de línia és, tot sovint,CR+LF. Els subtítols es numeren en seqüència, començant per 1. Els subtítols se separen per una línia en blanc.

En resum:

Número del subtítol
temps d'inici --> temps de fi
text del subtítol (una o més línies) 
Línia en blanc.

un exemple de fixer SubRip (prova.srt)

1
00:00:20,000 --> 00:00:24,400
Altocumulus clouds occur between six thousand

2
00:00:24,600 --> 00:00:27,800
and twenty thousand feet above ground level.

 Doncs bé, amb el següent script Python podré retardar o avançar l'aparició dels subtítols.

#!/usr/bin/python
# coding: latin-1

# L'objectiu del programa és retardar o adelantar el temps d'aparició del subtítol
# el programa pren tres arguments: fitxer original, fitxer de sortida i
# temps expressat en mili segons a avançar o retardar (un negatiu, vol dir avançar)
# El fitxer de sortida serà un fitxer .srt igual a l'original, però amb tots els
# temps retardats en la quantitat de mili segons indicada

import optparse 
from datetime import datetime
from datetime import timedelta

def main():
    # analitza els arguments rebuts
    usage = "\t%prog filein.srt fileout.srt delay"
    usage = usage + "\n\texample 1: %prog filein.srt fileout.srt 10000 --> delays 10 seconds"
    usage = usage + "\n\texample 2: %prog filein.srt fileout.srt -- -10000 --> advances 10 seconds"
    parser = optparse.OptionParser(usage)
    (options, args) = parser.parse_args()

 
    # if args != 3 (fitxer d'entrada, fitxer de sortida, delay) aleshores error
    if len(args) != 3:
        parser.error("incorrect number of arguments")

    # calcula el delta
        delta =  timedelta(milliseconds=int(args[2]))

    # obre el fitxer per llegir-lo
    f1 = open(args[0])
    f2 = open(args[1], "w")
    for line in f1:
            tokens = line.split(" --> ")
            if len(tokens) == 2:
            
        # strip() --> trim spaces
           
        TempsInici = datetime.strptime(tokens[0].strip(), "%H:%M:%S,%f") + delta
           
        TempsFi = datetime.strptime(tokens[1].strip(), "%H:%M:%S,%f") + delta

           
        # multilínia amb "\"
           
        line = \
           
        str(TempsInici.hour).zfill(2) + ":" + \
           
        str(TempsInici.minute).zfill(2) + ":" + \
           
        str(TempsInici.second).zfill(2) + "," + \
           
        str(int(TempsInici.microsecond / 1000)).zfill(3) + " --> " + \
           
        str(TempsFi.hour).zfill(2) + ":" + \
           
        str(TempsFi.minute).zfill(2) + ":" + \
           
        str(TempsFi.second).zfill(2) + "," + \
           
        str(int(TempsFi.microsecond/ 1000)).zfill(3) + "\r\n"
   
        
            f2.write(line)
    

    f1.close()
    f2.close()

#main
if __name__ == "__main__":
    main()


El programa és trivial, però en faré alguns comentaris.

Us d'optparse per a fer el tractament dels arguments d'entrada.  A partir de la versió 2.7 aquest mòdul es considera obsolet i cal fer servir argparse. Ara bé, la forma com funcionen tots dos mòduls és similar. A destacar com es fa el missatge d'us, i com es tornen en un diccionari les opcions (que en aquest cas, no n'hi han) i en un array els arguments posicionals (fitxer-d'entrada, fitxer de sortida, retard).

A destacar com passar arguments negatius (en aquest cas, això vol dir avançar l'aparició dels subtítols) fent servir  "--". El exemple que acompanya l'explicació de l'ús és aclaridor:

delayer.py entrada.srt sortida.srt -- -10000

Avança l'aparició dels subtítols 10 segons

En cas de no disposar dels arguments suficient, finalitza l'execució de l'script amb parser.error

Immediatament que ha tractat els arguments d'entrada, procedeix a calcular el retard amb:

delta =  timedelta(milliseconds=int(args[2]))

A continuació obre el fitxer original per a lectura i el fitxer de sortida.

La iteració línia a línia pel fitxer original es senzilla amb la potent sintaxi del for:

for line in f1:

Per a cada línia, verifica si es pot dividir amb -->. Les línies que tinguin --> seran les de temps i les que cal tractar.

El càlcul dels nous temps es fa amb el parell de línies

TempsInici = datetime.strptime(tokens[0].strip(), "%H:%M:%S,%f") + delta
TempsFi = datetime.strptime(tokens[1].strip(), "%H:%M:%S,%f") + delta

A destacar l'us de strptime  que converteix una cadena en un objecte datetime fent servir una cadena de format. El format "%H:%M:%S,%f" correspon a  hora:minut:segon,milisegons. El mètode strip(), per la seva part, elimina espais en blanc per davant i pel darrera de la cadena, com el trim de java.

Finalment, els camps útils dels datetime TempsInici i TempsFi es reordenen i s'ajunten en una cadena de text en la següent línia

line = \
str(TempsInici.hour).zfill(2) + ":" + \
str(TempsInici.minute).zfill(2) + ":" + \
str(TempsInici.second).zfill(2) + "," + \
str(int(TempsInici.microsecond / 1000)).zfill(3) + " --> " + \
str(TempsFi.hour).zfill(2) + ":" + \
str(TempsFi.minute).zfill(2) + ":" + \
str(TempsFi.second).zfill(2) + "," + \
str(int(TempsFi.microsecond/ 1000)).zfill(3) + "\r\n"



Aquesta instrucció llarga es divideix en vàries línies fent servir \.
Els camps numèrics es converteixen a cadena amb str().
El mètode de cadena zfill(longitud) zero fill posa zeros per l'esquerra fins a que la cadena té la longitud indicada.
Els datetime no tenen un camp millisecond, però sí que el tenen microsecond. aleshores divideixo aquest camp per 1000 i el converteixo a enter amb int(). Finalment afegeixo un CR+LF

Per acabar, fora de l'if, s'escriu al fitxer de sortida la línia. Si era una línia amb --> haurà estat processada, si no, es manté com a l'original.

Es tanquen els fitxers i s'invoca el main. Aquest if __name__ == "__main__":  és un "truc" de python que permet que aquest script pugui ser utilitzat com a llibreria des d'un altre script: en aquest cas, la variable __name__ prendria un valor diferent de __main__.

dissabte, 12 de febrer del 2011

Com fer servir MySQL amb Python. Mòdul MySQL-DB

Aquest post és molt similar al'anterior, però en aquest la base de dades és MySQL. Per a desenvolupar aplicacions que facin servir MySQL amb Python, el primer pas és instal·lar algun mòdul que permeti accedir-hi amb Python.

El mòdul més popular per accedir a MySQL amb Python és MySQL-DB (http://sourceforge.net/projects/mysql-python/).

Com en d'altres ocasions, és possible instal·lar aquest mòdul a la una distribució Ubuntu des del"Centre de Programari de l'Ubuntu".

També instal·lo l'extensió de debug, tot des del "Centre de Programari de l'Ubuntu"


És imprescindible llegir la documentació (recordem que amb pydoc podrem consultar la documentació o presentar-la en format html).


La documentació online la trobem a http://mysql-python.sourceforge.net/MySQLdb.html

A continuació, repetiré el senzill experiment del post anterior que consistia en connectar-se a una base de dades existent i executar-hi consultes, però, en aquesta ocasió, fent servir una base de dades MySQL.

Primer de tot, amb l'Anjuta, creo un projecte nou del tipus Python generic.

Hi enganxaré el següent script. Remarcar-ne només l'us dels parametres charset='utf8' i use_unicode=True en el connect. SCalen per a recuperar correctament dades de tipus text que puguin tenir accents, dièresis... La resta de l'script és molt senzill i els comentaris expliquen que fa el codi.

 #!/usr/bin/python
# coding: latin-1
#

import MySQLdb
import sys


def main():
    print "Connectant a la base de dades localhost / proves"
      
    try:

        # obté una connexió, si no es pot connectar, llença una excepció
        # charset='utf8', use_unicode=True -> necessaris per a recuperar dades amb accents
        v_conn=MySQLdb.connect(host='localhost', user='root', passwd='password', db='proves', charset='utf8', use_unicode=True)
        print "Connectat!\n"
      
        # conn.cursor retorna un objecte cursor, per a fer les consultes.
        v_cur=v_conn.cursor()
      
        #executa una query
        v_cur.execute("select id,valor,traduccio from taula1")
      
        # obté totes les files
        v_files = v_cur.fetchall()

        # mostra les files
        for v_fila in v_files:
            print str(v_fila[0]) + " ; " + v_fila[1] + " ; " + v_fila[2]

        # tanca el cursor
        v_cur.close()
      
        # tanca la connexió
        v_conn.close()
 
      
    except:
    # obté informació de l'excepció
        e_exceptionType, e_exceptionValue, e_exceptionTraceback = sys.exc_info()
        # mostra la informació i acaba.
        sys.exit("error, %s" % (e_exceptionValue))

# final
if __name__ == "__main__":
    sys.exit(main())


Des del mateix Anjuta puc provar:

EXECUTING:
/home/albert/wp-python/prova-Mysql/src/python_mysql.py
----------------------------------------------
Connectant a la base de dades localhost / proves
Connectat!

1 ; valor 1 ; traducció 1
2 ; valor 2 ; traducció 2
3 ; valor 3 ; traducció 3
4 ; valor 4 ; traducció 4
5 ; valor 5 ; traducció 5
6 ; valor 6 ; traducció 6

----------------------------------------------
Program exited successfully with errcode (0)
Press the Enter key to close this terminal ...


Un senzill experiment de com accedir a MySQL amb scripts de Python fent servir el mòdul MySQLdb.

dissabte, 5 de febrer del 2011

Com fer servir PostgreSQL amb Python. Mòdul Psycopg2

Per a desenvolupar aplicacions que facin servir PostgreSQL amb Python, el primer pas és instal·lar algun mòdul que permeti accedir a la base de dades des del llenguatge.

El mòdul més popular per accedir a PostgreSQL amb Python és Psycopg2 (http://initd.org/psycopg/).

Instal·lar aquest mòdul a la una distribució Ubuntu no presenta cap dificultat perquè està disponible al "Centre de Programari de l'Ubuntu".

També instal·lo la testsuite i l'extensió de debug, tot des del "Centre de Programari de l'Ubuntu"



Un cop instal·lats, ja es pot treballar. El primer  pas és revisar la documentació i els exemples. La documentació en línia la podem trobar a http://initd.org/psycopg/docs/. I ha un altre enllaç molt interessant a la wiki de PostgreSQL: http://wiki.postgresql.org/wiki/Using_psycopg2_with_PostgreSQL.

Encara millor: podem utilitzar la documentació local de Python. si a la consola fem pydoc -g, se'ns obrirà   aquesta petita aplicació, que és un mini servidor web de les pàgines HTML de l'ajuda de Python i els seus mòduls:


A més, compta amb un cercador molt senzill amb el que podrem consultar sobre el mòdul que acabem d'instal·lar, el psycopg2. Fent click als tòpics trobats


Ens obrirà un navegador amb la pàgina desitjada.

Doncs bé, un cop vist això, el que faré serà un experiment molt senzill que consistirà en connectar-se a una base de dades existent i executar-hi consultes.

Primer de tot, amb l'Anjuta, creo un projecte nou del tipus Python generic. Per a fer les coses més fàcils, copio l'script de prova disponible

#!/usr/bin/python
# coding: latin-1
#
import psycopg2
import sys


def main():
#Defineix la cadena de connexió
conn_string = "host='localhost' dbname='proves' user='postgres' password='postgres'"
# la mostra
print "Connectant a la base de dades\n ->%s" % (conn_string)
try:
# obté una connexió, si no es pot connectar, llença una excepció
conn = psycopg2.connect(conn_string)

# conn.cursor retorna un objecte cursor, per a fer les consultes.
cursor = conn.cursor()

print "Connectat!\n"
except:
# obté informació de l'excepció
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# mostra la informació i acaba.
sys.exit("Database connection failed!\n ->%s" % (exceptionValue))


# final
if __name__ == "__main__":
sys.exit(main()) 

Des del mateix Anjuta puc provar:


EXECUTING:
/media/DISC57GB/wk-python/ProvaPG/src/prova_pg.py 
----------------------------------------------
Connectant a la base de dades
->host='localhost' dbname='proves' user='postgres' password='postgres'
Connectat!




----------------------------------------------
Program exited successfully with errcode (0)
Press the Enter key to close this terminal ... 


Net i a la primera. Ara faré una consulta, afegeixo


#!/usr/bin/python
# coding: latin-1
#
import psycopg2
import sys


def main():
#Defineix la cadena de connexió
conn_string = "host='localhost' dbname='proves' user='postgres' password='postgres'"
# la mostra
print "Connectant a la base de dades\n ->%s" % (conn_string)
try:
# obté una connexió, si no es pot connectar, llença una excepció
conn = psycopg2.connect(conn_string)

# conn.cursor retorna un objecte cursor, per a fer les consultes.
cursor = conn.cursor()

print "Connectat!\n"

# executa una consulta
cursor.execute("SELECT * FROM taula1")


# recupera files de la taula
v_files = cursor.fetchall()

print "Retorna: " + str(cursor.rowcount) + " files"


# mostra les files 
for v_fila in v_files:
print str(v_fila[0]) + " ; " + v_fila[1] + " ; " + v_fila[2]

# i surt
conn.close()
except:
# obté informació de l'excepció
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
# mostra la informació i acaba.
sys.exit("Database connection failed!\n ->%s" % (exceptionValue))


# final
if __name__ == "__main__":
sys.exit(main())


I el resultat, com calia esperar:

EXECUTING:
/media/DISC57GB/wk-python/ProvaPG/src/prova_pg.py 
----------------------------------------------
Connectant a la base de dades
->host='localhost' dbname='proves' user='postgres' password='postgres'
Connectat!


Retorna: 5 files
1 ; valor 1 ; traducció 1
2 ; valor 2 ; traducció 2
3 ; valor 3 ; traducció 3
4 ; valor 4 ; traducció 4
5 ; valor 5 ; traducció 5


----------------------------------------------
Program exited successfully with errcode (0)
Press the Enter key to close this terminal ...

Un senzill experiment de com utilitzar PostgreSQL amb scripts de Python fent servir el mòdul Psycopg2.