summaryrefslogtreecommitdiff
path: root/pypers/marelli
diff options
context:
space:
mode:
Diffstat (limited to 'pypers/marelli')
-rwxr-xr-xpypers/marelli/corso_py.txt144
-rwxr-xr-xpypers/marelli/deleting.py4
-rwxr-xr-xpypers/marelli/ex_thread.py20
-rwxr-xr-xpypers/marelli/frontpage.html16
-rwxr-xr-xpypers/marelli/mail/corso-python.tex164
-rwxr-xr-xpypers/marelli/mail/corso-python.txt57
-rwxr-xr-xpypers/marelli/mail/corso-python2.txt55
-rwxr-xr-xpypers/marelli/mail/polizza.txt28
-rwxr-xr-xpypers/marelli/mail/preventivo.txt40
-rwxr-xr-xpypers/marelli/mail/programma.txt96
-rwxr-xr-xpypers/marelli/materiale/README.txt14
-rwxr-xr-xpypers/marelli/materiale/corso.html1850
-rwxr-xr-xpypers/marelli/materiale/corso.txt1851
-rwxr-xr-xpypers/marelli/materiale/del_with_exc.py10
-rwxr-xr-xpypers/marelli/materiale/doctest_runner.py8
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/Makefile5
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P01.html110
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P02.html106
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P03.html102
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P04.html108
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P05.html107
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P06.html108
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P07.html107
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P08.html102
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P09.html114
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P10.html101
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P11.html114
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P12.html119
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P13.html111
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P14.html118
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P15.html115
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P16.html118
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P17.html116
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P18.html110
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P19.html113
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P20.html108
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P21.html117
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P22.html108
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P23.html115
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P24.html112
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P25.html110
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/P26.html113
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/abstract.txt11
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/doct_pkg.py22
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/doctester_frontend.py44
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/doctester_frontend.txt23
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/ex24.py17
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/ex_inner.py16
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/index.html16
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/index.txt6
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/maketalk.py98
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/more.txt33
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/refresh.txt0
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/split-failure.txt5
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/split-failure_txt.py8
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/split.html32
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/split.py15
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/split.txt18
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/talk.txt403
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/test_pkg/__init__.py6
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/test_pkg/a.py7
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/test_pkg/b.py7
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/testfile_ex.py11
-rwxr-xr-xpypers/marelli/materiale/doctest_talk/the_story.txt23
-rwxr-xr-xpypers/marelli/materiale/doctester.py71
-rwxr-xr-xpypers/marelli/materiale/esempio1.py20
-rwxr-xr-xpypers/marelli/materiale/esempio_banale.py12
-rwxr-xr-xpypers/marelli/materiale/example.py4
-rwxr-xr-xpypers/marelli/materiale/exc_debug.py19
-rwxr-xr-xpypers/marelli/materiale/gentable.py17
-rwxr-xr-xpypers/marelli/materiale/getattr_ex.py14
-rwxr-xr-xpypers/marelli/materiale/isnumber.py12
-rwxr-xr-xpypers/marelli/materiale/main.py14
-rwxr-xr-xpypers/marelli/materiale/maketable.py67
-rwxr-xr-xpypers/marelli/materiale/proc1a.py13
-rwxr-xr-xpypers/marelli/materiale/proc1b.py20
-rwxr-xr-xpypers/marelli/materiale/proc2a.py17
-rwxr-xr-xpypers/marelli/materiale/proc2b.py15
-rwxr-xr-xpypers/marelli/materiale/test_exc.py20
-rwxr-xr-xpypers/marelli/materiale/test_isnumber.py43
-rwxr-xr-xpypers/marelli/materiale/twisted_main.py37
-rwxr-xr-xpypers/marelli/modulo1/debug_me.py9
-rwxr-xr-xpypers/marelli/modulo1/try_finally.py17
-rwxr-xr-xpypers/marelli/modulo1/x.txt7
-rwxr-xr-xpypers/marelli/modulo2/TestLauncher.py2902
-rwxr-xr-xpypers/marelli/modulo2/maketable.py60
-rwxr-xr-xpypers/marelli/modulo2/mutable_immutable.py12
-rwxr-xr-xpypers/marelli/modulo2/prova.py1
-rwxr-xr-xpypers/marelli/modulo2/questionario-in-sol.txt139
-rwxr-xr-xpypers/marelli/modulo2/questionario-iniziale.txt23
-rwxr-xr-xpypers/marelli/modulo2/sort_ci.py25
-rwxr-xr-xpypers/marelli/modulo3/config.py6
-rwxr-xr-xpypers/marelli/modulo3/disaccoppiamento.txt1
-rwxr-xr-xpypers/marelli/modulo3/launcher_with_exec.py5
-rwxr-xr-xpypers/marelli/modulo3/lineinterpreter.py55
-rwxr-xr-xpypers/marelli/modulo3/runsongs.py31
-rwxr-xr-xpypers/marelli/modulo3/script_with_error.py1
-rwxr-xr-xpypers/marelli/modulo3/tester.py119
-rwxr-xr-xpypers/marelli/modulo3/tester_server.py6
-rwxr-xr-xpypers/marelli/modulo3/tester_server0.py60
-rwxr-xr-xpypers/marelli/modulo4/_main.py9
-rwxr-xr-xpypers/marelli/modulo4/code2utest.py32
-rwxr-xr-xpypers/marelli/modulo4/ex1.txt15
-rwxr-xr-xpypers/marelli/modulo4/ex2.txt5
-rwxr-xr-xpypers/marelli/modulo4/iter2thread.py15
-rwxr-xr-xpypers/marelli/modulo4/multi_iter.py22
-rwxr-xr-xpypers/marelli/modulo4/remote_tester_client.py46
-rwxr-xr-xpypers/marelli/modulo4/remote_tester_server.py59
-rwxr-xr-xpypers/marelli/modulo4/server_utest_1.py6
-rwxr-xr-xpypers/marelli/modulo4/server_utest_2.py8
-rwxr-xr-xpypers/marelli/modulo4/test2utest.py27
-rwxr-xr-xpypers/marelli/modulo4/test_1.py5
-rwxr-xr-xpypers/marelli/modulo4/test_2.py10
-rwxr-xr-xpypers/marelli/modulo4/test_3.py12
-rwxr-xr-xpypers/marelli/modulo4/test_parent_child/child.py4
-rwxr-xr-xpypers/marelli/modulo4/test_parent_child/parent.py9
-rwxr-xr-xpypers/marelli/modulo4/test_parent_child/test_kill_parent.sh7
-rwxr-xr-xpypers/marelli/modulo4/threads.txt22
-rwxr-xr-xpypers/marelli/modulo4/threads_ex.py26
-rwxr-xr-xpypers/marelli/modulo4/threads_twisted.py36
-rwxr-xr-xpypers/marelli/modulo4/utest_1.py6
-rwxr-xr-xpypers/marelli/modulo4/utest_2.py8
-rwxr-xr-xpypers/marelli/modulo4/x.py3
-rwxr-xr-xpypers/marelli/modulo5/fix-server.py48
-rwxr-xr-xpypers/marelli/modulo5/protected.py30
-rwxr-xr-xpypers/marelli/modulo5/protected2.py11
-rwxr-xr-xpypers/marelli/modulo5/threads_vs_gen.py37
-rwxr-xr-xpypers/marelli/programma-svolto.html409
-rwxr-xr-xpypers/marelli/programma-svolto.txt141
-rwxr-xr-xpypers/marelli/questionario-fin.txt6
-rwxr-xr-xpypers/marelli/questionario-iniziale.html303
-rwxr-xr-xpypers/marelli/scaletta.txt55
132 files changed, 13391 insertions, 0 deletions
diff --git a/pypers/marelli/corso_py.txt b/pypers/marelli/corso_py.txt
new file mode 100755
index 0000000..be5e092
--- /dev/null
+++ b/pypers/marelli/corso_py.txt
@@ -0,0 +1,144 @@
+- modulo string non è deprecated, ma il 90% di quello che contiene e' inutile
+- le classi normalmente iniziano con la 1a lettera maiuscola
+- nota sul coding dei caratteri
+- dalla 2.2.1 esistono True e False (1 o 0)
+- triple virgolette permettono di andare a capo
+- le costanti sono tutte maiuscole (come in C)
+- GRAFICA: librerie tk sono standard in tutte le distribuzioni
+- ipython è interessante: chiamando la funzione con due ?? ritorna il codice sorgente
+- nella normale distribuzione: import inspect, poi print inspect.getsource(nomefunzione)
+- esistono dei decompilatori che permettono di ritrovare il sorgente py partendo dal pyc
+- libro: python in a nutshell di Alex Martelli (come manuale di riferimento)
+- modulo __future__ per importare le caratteristiche future del linguaggio
+- __file__ restituisce il nome del file python in esecuzione
+- %s sostituisce il parametro nella stringa di testo (ciao)
+- %r sostituisce invece la rappresentazione della stringa ('ciao')
+- non far iniziare i files .py con un numero (i programmi), sempre con un carattere.
+ Però è possibile eseguire un programma che inizia con un numero facendo __import__("nomeprogramma").
+- IDLE non è consigliabile usarlo aperto 2 volte
+- l'attributo __name__ può essere 2 cose: il nome del modulo, se importato, oppure __main__
+- la funzione import esegue il file py, quindi se ci sono inizializzazioni ecc QUESTE VERRANNO ESEGUITE.
+ Per evitare ciò occorre (ed è bene) mettere if __name__ == '--main__' prima della parte di codice da eseguire
+ in caso quel file venga lanciato da solo (come main).
+ Questa cosa è fondamentale anche per il pydoc (documentazione).
+- nuovo modulo "decimal" per calcoli con numeri decimali (i calcoli sono ESATTI non c'e' errore di arrotondamento)
+- IMPORT: se si è modificato il modulo: reload(nomemodulo). Rifare l'import non funziona. Si può importare
+ anche con un altro nome "import pippo as pluto"; A PARITà DI NOME, L'ULTIMO IMPORT VINCE.
+ Non fare import metodo from modulo, meglio importare il modulo (si evita la confusione in caso di
+ metodi omonimi). PER FARE LA LISTA: import sys: sys.modules.
+- la prima stringa che segue la definizione di funzione rappresenta il doc help.
+- pydoc nomefunzione restiruisce la doc string della funzione o modulo
+- pydoc -g in grafico
+- pydoc -w nomefile -> scrive nomefile.html, colorato.
+- per chiamare pydoc: python -m pydoc (è un modulo).
+- attenzione a usare il backslash perchè è il codice di escape
+- quando una funzione non ritorna niente, in realtà ritorna un None.
+- usare os.path.join(dir1,dir2,ecc) per creare correttamente i nomi del path.
+- valori immutabili: numeri, stringhe e tuple. IMPORTANTE DA RICORDARE.
+- ls.sort ordina velocemente, ma cambia la lista; sorted invece no.
+- tuple (1,2,3) => usate in genere stile record database.
+- liste [1,2,3] => mutabili, hanno più metodi per lavorarci sopra.
+- modulo operator molto comodo (metodo itemgetter per ordinare).
+- potente istruzione set (nuovo tipo di dato), per fare la lista ORDINATA degli elementi.
+ Builtin solo nella 2.4, nelle precedenti occorre prendere il modulo sets dalla distro 2.3 e importarlo:
+ try: set: except Nameerror: from sets import Set as set (vedi esempio).
+- comoda ma strana libreria tkMessageBox per le finestre grafiche [non e' strana ;-)]
+- libreria urllib per leggere le pagine web
+- libreria webbrowser per aprire il browser sulla macchina e visualizzare la pagina.
+- isinstance per verificare il tipo di oggetto
+- installazione di matplotlib: indicare a mano di usare numarray (matplotlibrc) e riavviare python.
+- from pylab import *; plot(x,y) due vettori; show() per vedere il plot.
+- strumenti di sviluppo: wingide, boa x wxpython, eric (sotto linux gratis, a pagamento sotto Windows),
+ iron python x dot net, ctypes x accedere alle librerie windows.
+- è preferibile non scrivere righe di codice python più lunghe di 80 caratteri. Per andare a capo si usa semplicemente il "\".
+- Guido Var Rossum è il creatore, durante le vacanze di Natale 1989.
+- ATTENZIONE: se una funzione esce con return, è una funzione. Se esce con yeld allora è un generatore di iterazioni.
+ L'iteratore va chiamato con un ciclo, in modo da farsi restituire gli elementi, ma non ha bisogno di trappare
+ le eccezioni sulla fine del ciclo (vedi immagini2.py).
+- quando parte python viene eseguito il file pythonrc.
+- per modificare una libreria conviene fare la sovrascrittura della funzione incriminata e sovrascriverla dopo il caricamento.
+- in caso di applicazioni grafiche, conviene fare prima il kernel non grafico e validarlo, poi aggiungere la grafica.
+- per chiamare programmi esterni la 2.4 ha subprocess.call, che è più sicura di os.system.
+ Inserita a mano funziona nella 2.3; eventualmente verificare sulla 2.2. E' diverso da os.system, che chiama una nuova shell.
+- come navigatore di classi, IDLE è meglio del Pwin (?).
+- Michele ha copiato dalle FAQ una funzione per killare i processi windows (non esiste nella distro standard).
+- newsgroup: it.comp.lang.python (anche su google newsgroup: http://groups.google.it/group/it.comp.lang.python).
+- IMPORTANTE: non esistono variabili globali, ma solo relative al modulo. Però è possibile modificare __builtin__
+ in qualsiasi momento per aggiungere o cambiare qualsiasi metodo o parametro. E' ALTAMENTE SCONSIGLIATO.
+- threads: nuovo modulo "threading"
+- in generale è meglio usare i processi, invece dei thread (si maneggiano meglio). E poi i processi si possono spammare
+ su altri computer in caso di bisogno. Però sotto WIN i processi consumano molte risorse.
+- i thread non si possono uccidere, a differenza dei processi, se non usando ctrl-break.
+ L'uso di try:finally è consigliabile perchè si può trappare i ctrl-c ed eseguire le varie operazioni di abort.
+ Ma usando i thread l'unica soluzione rimane ctrl-break, e quindi non è possibile eseguire correttamente le operazioni di chiusura.
+ ATTENZIONE!!!
+- interessante trucco killme di Michele per chiudere il programma principale lanciato.
+- dir(oggetto) restituisce le proprietà di un oggetto (in pratica, qualsiasi cosa di python).
+- CLASSI: usare (object), nuova definizione per le classi "class Nomeclasse(object):"
+- modulo itertools per le iterazioni.
+- per lanciare IDLE: pythonw c:\programmi\Utils\python24\Lib\idlelib\idle.pyw
+- debugger a riga di comando: python -m pdb nomedelfile.py
+- il debugger praticamente non serve quando si usa il python (testimonianze dirette dei guru).
+- exc_debugger è comodo per il debug post mortem.
+- Classi.oggetti privati: iniziarli con "_".
+- esiste l'ereditarietà multipla, ma non è consigliato usarla. EVITARE.
+- zope3 è stata appena rifatta praticamente senza ereditarieta' multipla.
+- non usare exec, perchè restituisce poco in caso di errore; usare getattr e setattr. ATTENZIONE: in python non si è mai sicuri
+ della conformazione della classe, visto che può essere dinamicamente ridefinita -> istanze comprese!!!
+- usare Classe.mro per vedere il method resolution order.
+- pydoc nomedelmodulo(senza .py) restituisce le doc strings ordinate.
+- pydoc -w nomedelmodulo(senza .py) restituisce un file nomedelmodulo.html (colorato).
+- doctester.py (creato da Michele, chiama il doctest) permette di eseguire codice scritto all'interno della documentazione ascii.
+ GALATTICO!
+- wrapper di rst2html.py fatto da Michele per produrre sia html che pdf, partendo dalla sintassi ascii "restructured text".
+ Il pdf lo fa Latex, non c'è sotto windows. BISOGNA INSTALLARE ANCHE docutils: partendo dalla dir della distro: python setup.py install.
+Riga di comando: python rst2html.py < f:\doctest\esempio.txt >f:\doctest\esempio.html (meglio fare un batch).
+- unit test: vengono verificati solo i metodi che iniziano per "test". Si usa il modulo "unittest".
+- e' possibile convertire un doctest in unit test!!!! Si usa doctest.DocFileSuite. GALATTICO!
+- non è possibile testare un'interfaccia grafica, se non c'è la possibilità offerta dall'interfaccia stessa.
+- la classe cmd permette di costruire un interprete di comandi; per accedere ai metodi occorre che inizino per "do".
+- PACKAGE: collezione di cose che possono servire. E' una directory che contiene un file "__init__.py".
+ Va messa nel posto giusto: .\Lib\site-packages, dentro un file .pth. Si mette la dir di livello superiore.
+ Si possono indicare anche files .zip (GAGLIARDO, ma solo dalla 2.3).
+- EXCEPTION: è molto comodo specificare un messaggio. NON USARE raise "frasettina", non verrà più supportato.
+ Si può inoltre specificare una classe personale per le eccezioni, frasette incluse. Vedi esempio.
+- attualmente il metodo super non funziona con le eccezioni (sono vecchio stile).
+- gli errori non devono mai passare sotto silenzio, sempre che non siano trappati correttamente.
+ OCCORRE TRAPPARE UNA COSA ALLA VOLTA!!!
+- usando i threads in caso eccezione imprevista il programma non si ferma. ATTENZIONE.
+- "la cosa giusta è non usare i thread".... by Michele Simionato :)
+- classe queue per comunicare tra i thread. Classe deque (doppia coda).
+ USARE TRY EXCEPT per verificare la coda, non usare if. INSERIRE SEMPRE UN TRY: FINALLY:
+ -> ATTENZIONE: IL CTRL-BREAK AMMAZZA TUTTO E NON è TRAPPABILE. (Diverso il discorso tra linea
+ di comando e interfaccia grafica).
+- PEP: python enhancement proposal
+- generator conphrention: un loop entro parentesi tonde non sporca la variabile indice nel workspace.
+ La list conphrention esisteva già [parentesi quadre].
+- invece di ritornare un parametro in caso di errore conviene sollevare e gestire un'eccezione.
+- in caso di liste è molto più conveniente usare un append (o extend) invece che +=.
+- anche in caso di stringhe è meglio usare join invece di +.
+- import this -> zen di python
+- IDE: Wingide gode di buona fama; Eric/QT Designer è molto carino per le interfacce grafiche; Komodo;
+ Boa Contructor... sono a pagamento. MA I PIù GRANDI SVILUPPATORI USANO VI, EMACS...
+- INFORMAZIONI: usare il newsgroup è caldamente consigliato! Cookbook per esempi di codice ben fatto.
+- il carattere "_" è una variabile dummy.
+- il del non libera la memoria, solo le referenze. NON bisogna fidarsi ciecamente del garbage collector!!!
+ Infatti, in caso di utilizzo di debugger, rimangono dei riferimenti collegati.
+- file HISTORY.txt che spiega l'evoluzione del modulo. Ordine cronologico inverso.
+- EXEC serve solo per i guru... (doctest per esempio). Meglio usare import per eseguire altri files, oppure execfile
+ (che alimenta un dizionario), così si riesce a fare il debug.
+- revision control systems: Darts (a linea di comando).
+- DOC STRING: se manca il modulo già puzza...
+- tutti i progetti seri hanno il loro test!!!
+- ASSERT: utile per verificare una variabile rispetto uno o più valori noti.
+ Se è diversa viene alzata un'eccezione "AssertionError".
+- www.edgewall.com, trac, version control manager, Roberto Lupi (Fano) <- contatto da Michele Simionato.
+- utilizzo di __init__ per eseguire operazioni di default tipo directory.
+- ATTENZIONE: gli oggetti che hanno un wrapper c (o altro) bisogna cancellarli esplicitamente,
+ altrimente non saranno distrutti.
+- im_func per estrarre un metodo da una classe e usarlo come funzione (o metterlo dentro un'altra classe).
+ Si può cancellare un metodo da una classe usando del. COMUNQUE SONO COSE DA EVITARE!
+- il doppio underscore davanti al metodo impedisce la sovrascrittura da parte di una classe ereditata
+ che ridefinisce lo stesso metodo.
+- from __future__ import generators
+- pyserial per gestire le seriali.
diff --git a/pypers/marelli/deleting.py b/pypers/marelli/deleting.py
new file mode 100755
index 0000000..3f4ddc2
--- /dev/null
+++ b/pypers/marelli/deleting.py
@@ -0,0 +1,4 @@
+class C(object):
+ pass
+
+ls = [C() for _ in range(1000000)]
diff --git a/pypers/marelli/ex_thread.py b/pypers/marelli/ex_thread.py
new file mode 100755
index 0000000..a949d34
--- /dev/null
+++ b/pypers/marelli/ex_thread.py
@@ -0,0 +1,20 @@
+import threading, time
+
+def print_hello():
+ for i in range(10):
+ print "hello"
+ time.sleep(1)
+ if i == 5:
+ import pdb; pdb.set_trace()
+ raise RuntimeError("Ahia!")
+
+
+def print_world():
+ for i in range(10):
+ print "world"
+ time.sleep(1)
+
+threading.Thread(target=print_hello).start()
+
+threading.Thread(target=print_world).start()
+
diff --git a/pypers/marelli/frontpage.html b/pypers/marelli/frontpage.html
new file mode 100755
index 0000000..2886d8d
--- /dev/null
+++ b/pypers/marelli/frontpage.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+</head>
+<body bgcolor="lightblue">
+<center>
+<h1>Corso di Python Avanzato</h1>
+Michele Simionato<br/><br/>
+michele.simionato@gmail.com<br/><br/>
+Corso tenuto alla Magneti Marelli<br/><br/>
+Bologna, 19-23 Settembre 2005
+</center>
+</body>
+</html>
diff --git a/pypers/marelli/mail/corso-python.tex b/pypers/marelli/mail/corso-python.tex
new file mode 100755
index 0000000..2ea6c4e
--- /dev/null
+++ b/pypers/marelli/mail/corso-python.tex
@@ -0,0 +1,164 @@
+\documentclass[10pt,a4paper,english]{article}
+\usepackage{babel}
+\usepackage{ae}
+\usepackage{aeguill}
+\usepackage{shortvrb}
+\usepackage[latin1]{inputenc}
+\usepackage{tabularx}
+\usepackage{longtable}
+\setlength{\extrarowheight}{2pt}
+\usepackage{amsmath}
+\usepackage{graphicx}
+\usepackage{color}
+\usepackage{multirow}
+\usepackage{ifthen}
+\usepackage[colorlinks=true,linkcolor=blue,urlcolor=blue]{hyperref}
+\usepackage[DIV12]{typearea}
+%% generator Docutils: http://docutils.sourceforge.net/
+\newlength{\admonitionwidth}
+\setlength{\admonitionwidth}{0.9\textwidth}
+\newlength{\docinfowidth}
+\setlength{\docinfowidth}{0.9\textwidth}
+\newlength{\locallinewidth}
+\newcommand{\optionlistlabel}[1]{\bf #1 \hfill}
+\newenvironment{optionlist}[1]
+{\begin{list}{}
+ {\setlength{\labelwidth}{#1}
+ \setlength{\rightmargin}{1cm}
+ \setlength{\leftmargin}{\rightmargin}
+ \addtolength{\leftmargin}{\labelwidth}
+ \addtolength{\leftmargin}{\labelsep}
+ \renewcommand{\makelabel}{\optionlistlabel}}
+}{\end{list}}
+\newlength{\lineblockindentation}
+\setlength{\lineblockindentation}{2.5em}
+\newenvironment{lineblock}[1]
+{\begin{list}{}
+ {\setlength{\partopsep}{\parskip}
+ \addtolength{\partopsep}{\baselineskip}
+ \topsep0pt\itemsep0.15\baselineskip\parsep0pt
+ \leftmargin#1}
+ \raggedright}
+{\end{list}}
+% begin: floats for footnotes tweaking.
+\setlength{\floatsep}{0.5em}
+\setlength{\textfloatsep}{\fill}
+\addtolength{\textfloatsep}{3em}
+\renewcommand{\textfraction}{0.5}
+\renewcommand{\topfraction}{0.5}
+\renewcommand{\bottomfraction}{0.5}
+\setcounter{totalnumber}{50}
+\setcounter{topnumber}{50}
+\setcounter{bottomnumber}{50}
+% end floats for footnotes
+% some commands, that could be overwritten in the style file.
+\newcommand{\rubric}[1]{\subsection*{~\hfill {\it #1} \hfill ~}}
+\newcommand{\titlereference}[1]{\textsl{#1}}
+% end of "some commands"
+\input{style.tex}
+\title{Corso di Python avanzato per la Magneti Marelli}
+\author{}
+\date{}
+\hypersetup{
+pdftitle={Corso di Python avanzato per la Magneti Marelli}
+}
+\raggedbottom
+\begin{document}
+\maketitle
+
+
+\setlength{\locallinewidth}{\linewidth}
+
+Daniele Matteucci mi ha chiesto di stilare una breve nota per una proposta
+di un corso di Python avanzato da tenere presso la Magneti Marelli nel
+Settembre 2005.
+
+Il corso si svolgerebbe in 3 giorni di full immersion. Il mio compenso
+ordinario per questo tipologia di corsi è di 400 Euro al giorno più le
+spese (diciamo 150 Euro al giorno per vitto e alloggio). La cifra precisa
+andrà poi definita in base al programma da svolgere. Un programma indicativo
+potrebbe essere il seguente.
+\begin{itemize}
+\item {}
+Primo giorno: testing automatico di applicazioni in Python.
+
+\end{itemize}
+
+Discuterò i frameworks più usati (doctest, py.test, unittest) con
+esercitazioni pratiche.
+\begin{itemize}
+\item {}
+Secondo giorno: refactoring a buone pratiche di programmazione.
+
+\end{itemize}
+
+Esempi pratici di come convertire cattivo codice in buon codice e
+discussione dei più tipici errori di programmazione.
+\begin{itemize}
+\item {}
+Terzo giorno: argomenti specifici di programmazione avanzata.
+
+\end{itemize}
+
+Questa parte del programma è da concordare: argomenti trattabili
+potrebbero essere la programmazione multithreading, programmazione
+ad oggetti avanzata, iteratori e generatori, etc.
+
+Ho già tenuto corsi di Python di questo tipo (quest'anno a Bolzano
+e ad Oxford); il programma del corso di Oxford si può trovare a
+qui:
+
+\href{https://www.accu.org/conference/events_2005_04_19.html\#55}{https://www.accu.org/conference/events{\_}2005{\_}04{\_}19.html{\#}55}
+
+Preventivo indicativo per tre giorni:
+\begin{quote}
+
+\begin{longtable}[c]{|p{0.11\locallinewidth}|p{0.10\locallinewidth}|p{0.10\locallinewidth}|}
+\hline
+
+Compenso
+ &
+400 x 3
+ &
+1200E
+ \\
+\hline
+
+IVA
+ &
+20{\%}
+ &
+240E
+ \\
+\hline
+
+Spese
+ &
+150 x 3
+ &
+450E
+ \\
+\hline
+
+Viaggio
+ & &
+60E
+ \\
+\hline
+\multicolumn{2}{|l|}{
+Totale
+} &
+1950E
+ \\
+\hline
+\end{longtable}
+\end{quote}
+
+Roma, 23 giugno 2005
+\begin{quote}
+
+\emph{Michele Simionato}, \href{mailto:michele.simionato@gmail.com}{michele.simionato@gmail.com}
+\end{quote}
+
+\end{document}
+
diff --git a/pypers/marelli/mail/corso-python.txt b/pypers/marelli/mail/corso-python.txt
new file mode 100755
index 0000000..6561e05
--- /dev/null
+++ b/pypers/marelli/mail/corso-python.txt
@@ -0,0 +1,57 @@
+Corso di Python avanzato per la Magneti Marelli
+-------------------------------------------------------------------------
+
+
+
+Daniele Matteucci mi ha chiesto di stilare una breve nota per una proposta
+di un corso di Python avanzato da tenere presso la Magneti Marelli nel
+Settembre 2005.
+
+Il corso si svolgerebbe in 3 giorni di full immersion. Il mio compenso
+ordinario per questo tipologia di corsi è di 400 Euro al giorno più le
+spese (diciamo 150 Euro al giorno per vitto e alloggio). La cifra precisa
+andrà poi definita in base al programma da svolgere. Un programma indicativo
+potrebbe essere il seguente.
+
+- Primo giorno: testing automatico di applicazioni in Python.
+
+Discuterò i frameworks più usati (doctest, py.test, unittest) con
+esercitazioni pratiche.
+
+- Secondo giorno: refactoring a buone pratiche di programmazione.
+
+Esempi pratici di come convertire cattivo codice in buon codice e
+discussione dei più tipici errori di programmazione.
+
+- Terzo giorno: argomenti specifici di programmazione avanzata.
+
+Questa parte del programma è da concordare: argomenti trattabili
+potrebbero essere la programmazione multithreading, programmazione
+ad oggetti avanzata, iteratori e generatori, etc.
+
+Ho già tenuto corsi di Python di questo tipo (quest'anno a Bolzano
+e ad Oxford); il programma del corso di Oxford si può trovare a
+qui:
+
+https://www.accu.org/conference/events_2005_04_19.html#55
+
+
+Preventivo indicativo per tre giorni:
+
+ ======== ======= =======
+ Compenso 400 x 3 1200E
+ -------- ------- -------
+ IVA 20% 240E
+ -------- ------- -------
+ Spese 150 x 3 450E
+ -------- ------- -------
+ Viaggio 60E
+ -------- ------- -------
+ Totale 1950E
+ ================ =======
+
+Roma, 23 giugno 2005
+
+ *Michele Simionato*, michele.simionato@gmail.com
+
+
diff --git a/pypers/marelli/mail/corso-python2.txt b/pypers/marelli/mail/corso-python2.txt
new file mode 100755
index 0000000..6b1c1b8
--- /dev/null
+++ b/pypers/marelli/mail/corso-python2.txt
@@ -0,0 +1,55 @@
+Corso di Python avanzato per la Magneti Marelli
+-------------------------------------------------------------------------
+
+Daniele Matteucci mi ha chiesto di stilare una breve nota per una proposta
+di un corso di Python avanzato da tenere presso la Magneti Marelli nel
+Settembre 2005.
+
+Il corso si svolgerebbe in 3 giorni di full immersion. Il mio compenso
+ordinario per questo tipologia di corsi è di 400 Euro al giorno più le
+spese (diciamo 150 Euro al giorno per vitto e alloggio). La cifra precisa
+andrà poi definita in base al programma da svolgere. Un programma indicativo
+potrebbe essere il seguente.
+
+- Primo giorno: testing automatico di applicazioni in Python.
+
+Discuterò i frameworks più usati (doctest, py.test, unittest) con
+esercitazioni pratiche.
+
+- Secondo giorno: refactoring a buone pratiche di programmazione.
+
+Esempi pratici di come convertire cattivo codice in buon codice e
+discussione dei più tipici errori di programmazione.
+
+- Terzo giorno: argomenti specifici di programmazione avanzata.
+
+Questa parte del programma è da concordare: argomenti trattabili
+potrebbero essere la programmazione multithreading, programmazione
+ad oggetti avanzata, iteratori e generatori, etc.
+
+Ho già tenuto corsi di Python di questo tipo (quest'anno a Bolzano
+e ad Oxford); il programma del corso di Oxford si può trovare a
+qui:
+
+https://www.accu.org/conference/events_2005_04_19.html#55
+
+
+Preventivo indicativo per tre giorni:
+
+ ======== ======= =======
+ Compenso 400 x 3 1200E
+ -------- ------- -------
+ IVA 20% 240E
+ -------- ------- -------
+ Spese 150 x 3 450E
+ -------- ------- -------
+ Viaggio 60E
+ -------- ------- -------
+ Totale 1950E
+ ================ =======
+
+Roma, 23 giugno 2005
+
+ *Michele Simionato*, michele.simionato@gmail.com
+
+
diff --git a/pypers/marelli/mail/polizza.txt b/pypers/marelli/mail/polizza.txt
new file mode 100755
index 0000000..e88a8b1
--- /dev/null
+++ b/pypers/marelli/mail/polizza.txt
@@ -0,0 +1,28 @@
+Un paio di comunicazioni.
+
+1. Ho stipulato una polizza di responsabilita' civile terzi per i giorni
+19-23 Settembre, quindi adesso non ci dovrebbero essere piu' problemi.
+
+2. Stavo riguardando il programma da portare e mi sono reso conto che
+resta un po' di tempo libero (diciamo una mezza giornata). In questa
+mezza giornata potrei parlare di varie cose, ditemi voi cosa vi
+interessa di piu'. Possibilita' sono:
+
+- numeric & matplotlib (praticamente l'equivalente di Matlab ma fatto
+ da Python)
+
+- programmazione orientata agli oggetti;
+
+- un'introduzione alla programmazione con i threads;
+
+- un'introduzione alla programmazione di network (client/server, magari
+ qualche cenno su Twisted);
+
+- altro a richiesta.
+
+Le possibilita' sono esclusive perche' non si puo' far tutto!
+
+A risentirci,
+
+
+ Michele Simionato
diff --git a/pypers/marelli/mail/preventivo.txt b/pypers/marelli/mail/preventivo.txt
new file mode 100755
index 0000000..e1e5239
--- /dev/null
+++ b/pypers/marelli/mail/preventivo.txt
@@ -0,0 +1,40 @@
+Stavo preparando il preventivo per il corso di Settembre.
+Ho ridotto la stima delle spese a 120 Euro al giorno per
+5 giorni. Il compenso resta a 400 Euro al giorno per 5
+giorni. Tuttavia c'è da dire che:
+
+1. ho speso un'intera giornata lunedì scorso (4 Luglio) dalle
+ 10.30 alle 16:00 (piu' 4 ore di viaggio) per discutere il corso
+ e farmi un'idea degli strumenti di sviluppo utilizzati;
+
+2. si è deciso di organizzare un corso molto su misura, con argomenti
+ specifici; inoltre si è deciso di preparare due questionari, uno di inizio
+ corso per verificare la preparazione generale (che ho già spedito a
+ Daniele Matteucci) ed uno di fine corso per verificare l'apprendimento
+ (che preparerò in seguito).
+
+Stimando il tempo occupato in queste attività in una giornata lavorativa
+(in effetti è un pò di più) mi pare il caso di aggiungere 400 Euro al
+preventivo. Ecco qui il sommario:
+
+ ============ ======= =======
+ Preparazione 400E
+ ------------ ------- -------
+ Compenso 400 x 5 2000E
+ ------------ ------- -------
+ Spese 120 x 5 600E
+ ------------ ------- -------
+ Viaggio 60E
+ ------------ ------- -------
+ Totale 3060E
+ ============ ======= =======
+
+A questo c'è da aggiungere l'IVA. In passato ho tenuto dei corsi per
+la provincia la quale pagava direttamente le spese di viaggio e vitto e
+alloggio. Come funziona in questo caso invece? Va aggiunta solo l'IVA
+al 20% sul compenso oppure va aggiunto anche qualcosa per l'albergo (mi pare
+il 10%) e per il viaggio?
+Infine, fevo ancora informarmi per quanto riguarda la copertura assicurativa,
+ma mi riservo di aggiungere qualcosina per coprire tali costi aggiuntivi.
+
+ Michele Simionato
diff --git a/pypers/marelli/mail/programma.txt b/pypers/marelli/mail/programma.txt
new file mode 100755
index 0000000..ec36352
--- /dev/null
+++ b/pypers/marelli/mail/programma.txt
@@ -0,0 +1,96 @@
+Corso Python Magneti Marelli
+======================================================
+
+Data: 19-23 Settembre
+Docente: Michele Simionato
+
+
+Programma
+---------------------------------------
+
+Si tratta di un corso di 20 ore suddiviso in 5 moduli di 4 ore ciascuno.
+
+Modulo 1: Strumenti di sviluppo, debugging e introspezione.
+
+In questo modulo discutero' gli strumenti da me utilizzati per sviluppare
+in Python sotto Windows. Parlero' di Cygwin come ambiente di lavoro,
+di Python e di IPython come interpreti interattivi, di Idle e di PythonWin
+come IDE, di pydoc e minidoc come tools di introspezione. Inoltre discutero'
+alcune utili librerie e frameworks per Python (Numeric, matplotlib, gnuplot,
+etc.). Se rimane del tempo e c'e' interesse accennero' anche
+a Revision Control Systems come Subversion e Darcs.
+
+Modulo 2: Programmazione di base in Python.
+
+In questo modulo si ripasseranno molto brevemente le basi di Python e
+si discuteranno le soluzioni al questionario di ammissione. Lo scopo
+piu' che altro e' quello di conoscersi e di chiarire il livello medio
+dei partecipanti e coprire eventuali buchi nella preparazione di base.
+
+Modulo 3. Tipici errori di programmazione e gestione delle eccezioni.
+
+Si discuteranno buoni e cattivi esempi di programmazione presi da software
+reale scritto alla Magneti Marelli. Si discuteranno alcune tecniche
+per interpretare i tracebacks di Python e per identificare l'origine dei
+problemi.
+
+Modulo 4. Sviluppo orientato ai test
+
+Come scrivere software con tecnologie agili, con lo scopo di ridurre e
+tenere sotto controllo i bugs. Discussione di doctest, py.test e unittest.
+Esempi di programmazione test driven.
+
+Modulo 5: Design, documentazione e manutenzione di librarie
+
+Pratiche di programmazione "in the large". Moduli, packages, strumenti di
+documentazione e di installazione. Applicazioni pratiche di principi generali
+quali disaccoppiamento, modularità, non duplicazione del codice.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Preventivo
+----------------------
+
+ ============ ======= =======
+ Preparazione 400E
+ ------------ ------- -------
+ Compenso 400 x 5 2000E
+ ------------ ------- -------
+ IVA 20% 240E
+ ------------ ------- -------
+ Spese 120 x 5 600E
+ ------------ ------- -------
+ Viaggio 60E
+ ------------ ------- -------
+ Totale 3300E
+ ============ ======= =======
+
+
+Coordinate bancarie per il pagamento
+-------------------------------------
+
+ Michele Simionato
+ Cassa di Risparmio di Venezia
+ Filiale di Pianiga
+ Via Roma 1 (ITALIA)
+ ABI: 06345 CAB: 36230
+ C/C: 0700075870H
+ Code swift/bic: CVCEIT2V
+ IBAN: IT47 C063 4536 2300 7400 0758 70H
diff --git a/pypers/marelli/materiale/README.txt b/pypers/marelli/materiale/README.txt
new file mode 100755
index 0000000..fcf7e29
--- /dev/null
+++ b/pypers/marelli/materiale/README.txt
@@ -0,0 +1,14 @@
+Questa directory contiene il materiale relativo al corso di Python avanzato
+tenuto presso la Magneti Marelli dal 19 al 23 settembre 2005.
+
+- corso.pdf (dispense in formato PDF)
+- corso.html (dispense in formato HTML)
+- corso.txt (dispense in formato RST)
+- *.py (alcuni scripts di esempio)
+
+Materiale integrativo:
+
+- doctest-talk (seminario da me tenuto su doctest)
+
+I curiosi possono anche guardare alle mie lezioni di Oxford
+(http://www.phyast.pitt.edu/~micheles/oxford-lectures.zip)
diff --git a/pypers/marelli/materiale/corso.html b/pypers/marelli/materiale/corso.html
new file mode 100755
index 0000000..8a0de82
--- /dev/null
+++ b/pypers/marelli/materiale/corso.html
@@ -0,0 +1,1850 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.3.7: http://docutils.sourceforge.net/" />
+<title>Corso Python Magneti Marelli</title>
+</head>
+<body>
+<div class="document" id="corso-python-magneti-marelli">
+<h1 class="title">Corso Python Magneti Marelli</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr class="field"><th class="docinfo-name">Tenuto:</th><td class="field-body">19-23 Settembre 2005</td>
+</tr>
+<tr class="field"><th class="docinfo-name">Autore:</th><td class="field-body">Michele Simionato</td>
+</tr>
+<tr class="field"><th class="docinfo-name">E-mail:</th><td class="field-body"><a class="reference" href="mailto:michele.simionato&#64;gmail.com">michele.simionato&#64;gmail.com</a></td>
+</tr>
+</tbody>
+</table>
+<p><em>Queste dispense sono un compendio informale e molto sintetico di quanto
+svolto durante il corso. Esse non si pongono in nessun modo come un testo
+sistematico di programmazione in Python. Il loro scopo principale è quello
+di tenere traccia, per quanto possibile, di quanto si è detto. Lo
+scopo secondario è quello di invogliare i partecipanti e tutti
+gli eventuali lettori ad affrontare gli argomenti qui trattati per forza
+di cose in maniera abbozzata, in maniera più sistematica andando a
+consultare le fonti più adatte alla bisogna, siano essi libri di testo,
+la documentazione ufficiale, newsgroups, siti Web dedicati e, in ultima
+instanza, il codice sorgente stesso, l'unico riferimento definitivo.</em></p>
+<div class="contents topic" id="contents">
+<p class="topic-title first"><a name="contents">Indice</a></p>
+<ul class="simple">
+<li><a class="reference" href="#i-messaggi-fondamentali-del-corso" id="id1" name="id1">I messaggi fondamentali del corso</a><ul>
+<li><a class="reference" href="#studiare-paga" id="id2" name="id2"><em>Studiare paga</em></a></li>
+<li><a class="reference" href="#disaccoppiamento-e-kiss" id="id3" name="id3"><em>Disaccoppiamento</em> e <em>KISS</em></a></li>
+<li><a class="reference" href="#non-nascondete-gli-errori-sotto-il-tappeto" id="id4" name="id4"><em>Non nascondete gli errori sotto il tappeto</em></a></li>
+</ul>
+</li>
+<li><a class="reference" href="#modulo-1-strumenti-di-introspezione-sviluppo-e-debugging" id="id5" name="id5">Modulo 1: Strumenti di introspezione, sviluppo e debugging</a><ul>
+<li><a class="reference" href="#strumenti-di-introspezione-e-come-ottenere-aiuto" id="id6" name="id6">Strumenti di introspezione e come ottenere aiuto</a></li>
+<li><a class="reference" href="#ambienti-di-sviluppo" id="id7" name="id7">Ambienti di sviluppo</a></li>
+<li><a class="reference" href="#strumenti-di-debugging" id="id8" name="id8">Strumenti di debugging</a></li>
+<li><a class="reference" href="#strumenti-utili-per-l-utenza-scientifica-ingegneristica" id="id9" name="id9">Strumenti utili per l'utenza scientifica/ingegneristica</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#modulo-2-programmazione-di-base-in-python" id="id10" name="id10">Modulo 2: Programmazione di base in Python</a><ul>
+<li><a class="reference" href="#encoding" id="id11" name="id11">Encoding</a></li>
+<li><a class="reference" href="#pathnames" id="id12" name="id12">Pathnames</a></li>
+<li><a class="reference" href="#insiemi" id="id13" name="id13">Insiemi</a></li>
+<li><a class="reference" href="#differenza-tra-mutabili-e-immutabili" id="id14" name="id14">Differenza tra mutabili e immutabili</a></li>
+<li><a class="reference" href="#getattr-e-setattr" id="id15" name="id15">getattr e setattr</a></li>
+<li><a class="reference" href="#gestione-dei-processi" id="id16" name="id16">Gestione dei processi</a></li>
+<li><a class="reference" href="#iteratori-e-generatori" id="id17" name="id17">Iteratori e generatori</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#modulo-3-tipici-errori-di-programmazione-e-gestione-delle-eccezioni" id="id18" name="id18">Modulo 3. Tipici errori di programmazione e gestione delle eccezioni</a><ul>
+<li><a class="reference" href="#l-errore-pi-tipico-con-le-eccezioni" id="id19" name="id19">L'errore più tipico con le eccezioni</a></li>
+<li><a class="reference" href="#il-try-finally-una-grande-idea" id="id20" name="id20">Il try .. finally è una grande idea</a></li>
+<li><a class="reference" href="#uso-di-assert" id="id21" name="id21">Uso di assert</a></li>
+<li><a class="reference" href="#non-usate-exec" id="id22" name="id22">Non usate exec</a></li>
+<li><a class="reference" href="#come-far-partire-pdb-automaticamente-in-caso-di-eccezioni-inaspettate" id="id23" name="id23">Come far partire pdb automaticamente in caso di eccezioni inaspettate</a></li>
+<li><a class="reference" href="#eccezioni-e-threads" id="id24" name="id24">Eccezioni e threads</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#modulo-4-sviluppo-orientato-ai-test" id="id25" name="id25">Modulo 4. Sviluppo orientato ai test</a><ul>
+<li><a class="reference" href="#consigli-di-carattere-generale" id="id26" name="id26">Consigli di carattere generale</a></li>
+<li><a class="reference" href="#usare-unittest" id="id27" name="id27">Usare unittest</a></li>
+<li><a class="reference" href="#usare-doctest" id="id28" name="id28">Usare doctest</a></li>
+<li><a class="reference" href="#un-esempio-di-programma-sviluppato-in-maniera-incrementale" id="id29" name="id29">Un esempio di programma sviluppato in maniera incrementale</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#modulo-5-design-documentazione-e-manutenzione-di-librarie" id="id30" name="id30">Modulo 5: Design, documentazione e manutenzione di librarie</a><ul>
+<li><a class="reference" href="#la-filosofia-del-python" id="id31" name="id31">La filosofia del Python</a></li>
+<li><a class="reference" href="#principio-del-disaccoppiamento" id="id32" name="id32">Principio del disaccoppiamento</a></li>
+<li><a class="reference" href="#principio-del-kiss" id="id33" name="id33">Principio del KISS</a></li>
+<li><a class="reference" href="#importanza-di-avere-un-prototipo" id="id34" name="id34">Importanza di avere un prototipo</a></li>
+<li><a class="reference" href="#moduli-e-packages" id="id35" name="id35">Moduli e packages</a></li>
+<li><a class="reference" href="#come-si-documenta-una-libreria-python" id="id36" name="id36">Come si documenta una libreria Python</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#modulo-6-domande-estemporanee" id="id37" name="id37">Modulo 6: Domande estemporanee</a><ul>
+<li><a class="reference" href="#come-funziona-import" id="id38" name="id38">Come funziona 'import'</a></li>
+<li><a class="reference" href="#come-funziona-del" id="id39" name="id39">Come funziona '__del__'</a></li>
+<li><a class="reference" href="#che-differenza-c-fra-variabili-di-classe-e-di-istanza" id="id40" name="id40">Che differenza c'è fra variabili di classe e di istanza</a></li>
+<li><a class="reference" href="#che-cosa-sono-i-metodi-che-iniziano-con" id="id41" name="id41">Che cosa sono i metodi che iniziano con &quot;__&quot;</a></li>
+</ul>
+</li>
+<li><a class="reference" href="#soluzioni-al-questionario-di-ammissione" id="id42" name="id42">Soluzioni al questionario di ammissione</a><ul>
+<li><a class="reference" href="#scrivere-un-programma-che-testa-se-una-stringa-rappresenta-un-numero" id="id43" name="id43">Scrivere un programma che testa se una stringa rappresenta un numero</a></li>
+<li><a class="reference" href="#scrivere-un-programma-che-lista-tutti-i-files-nella-directory-corrente" id="id44" name="id44">Scrivere un programma che lista tutti i files nella directory corrente</a></li>
+<li><a class="reference" href="#listare-tutti-i-files-nelle-sottodirectories-ricorsivamente" id="id45" name="id45">Listare tutti i files nelle sottodirectories ricorsivamente</a></li>
+<li><a class="reference" href="#calcolare-lo-spazio-occupato-da-tutti-i-files-di-tipo-txt-in-una-directory" id="id46" name="id46">Calcolare lo spazio occupato da tutti i files di tipo .txt in una directory</a></li>
+<li><a class="reference" href="#listare-i-files-a-seconda-delle-dimensioni" id="id47" name="id47">Listare i files a seconda delle dimensioni</a></li>
+<li><a class="reference" href="#scrivere-un-test-per-verificate-che-una-directory-sia-vuota" id="id48" name="id48">Scrivere un test per verificate che una directory sia vuota</a></li>
+<li><a class="reference" href="#aprire-una-finestrella-contenente-la-scritta-hello-world" id="id49" name="id49">Aprire una finestrella contenente la scritta &quot;hello, world!&quot;</a></li>
+<li><a class="reference" href="#scaricare-la-pagina-web-http-www-example-com-da-internet" id="id50" name="id50">Scaricare la pagina Web http://www.example.com da Internet</a></li>
+<li><a class="reference" href="#stampare-a-schermo-una-tavola-delle-moltiplicazioni" id="id51" name="id51">Stampare a schermo una tavola delle moltiplicazioni</a></li>
+<li><a class="reference" href="#trovare-tutte-le-immagini-jpg-nel-vostro-hard-disk-e-mostrarle-a-schermo-in-formato-ridotto" id="id52" name="id52">Trovare tutte le immagini .jpg nel vostro hard disk e mostrarle a schermo in formato ridotto</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="i-messaggi-fondamentali-del-corso">
+<h1><a class="toc-backref" href="#id1" name="i-messaggi-fondamentali-del-corso">I messaggi fondamentali del corso</a></h1>
+<div class="section" id="studiare-paga">
+<h2><a class="toc-backref" href="#id2" name="studiare-paga"><em>Studiare paga</em></a></h2>
+<p>Grazie alla sua macchina del tempo, Guido ha risolto i problemi
+che vi stanno affliggendo ora dieci anni fa, e sono già nel linguaggio
+e nella libreria standard. Per esempìo avete scoperto di avere a
+disposizione:</p>
+<ul class="simple">
+<li>le stringhe di documentazione per darvi la documentazione automatica
+del codice tramite strumenti quali pydoc ed altri;</li>
+<li>il try ... finally per garantirvi un &quot;gracefull exit&quot; del vostro
+programma, anche in presenza di eccezioni inaspettate;</li>
+<li>i metodi setUp e tearDown di unittest.TestCase, che vi permettono
+di inizializzare e di pulire propriamente l'ambiente per ogni test;</li>
+<li>sia unittest che doctest vi permetto di gestire le eccezioni (nel
+senso di gestire le eccezioni &quot;buone&quot;, quelle che vi aspettate);</li>
+<li>call e Popen in subprocess per aprire processi, kill per ucciderli
+(usando win32api.TerminateProcess);</li>
+<li>twisted vi gestisce la comunicazione tra processi e tutte le eccezioni
+senza problemi</li>
+</ul>
+<p>Una settimana di studio oggi può risparmiarvi mesi di frustrazioni
+domani. Sfruttare le risorse disponibili, quali tutorial, howto,
+libri, documentazione, siti Web (come il Python cookbook) e soprattutto
+i newsgroups. Ma prima di postare su di un newsgroup leggetevi &quot;How to
+ask smart questions&quot; e ricordatevi sempre che &quot;Google is you friend&quot;.</p>
+</div>
+<div class="section" id="disaccoppiamento-e-kiss">
+<h2><a class="toc-backref" href="#id3" name="disaccoppiamento-e-kiss"><em>Disaccoppiamento</em> e <em>KISS</em></a></h2>
+<p>Se potere, scomponete l'applicazione in componenti separati e testateli
+separatamente. Scegliete architetture che vi permettono di disaccoppiare
+i problemi. Se potere fare le cose semplici, fatele semplici.
+Abbiate un core minimale che faccia poco, ma che siate sicuri che
+funzioni. Non complicatevi la vita.</p>
+</div>
+<div class="section" id="non-nascondete-gli-errori-sotto-il-tappeto">
+<h2><a class="toc-backref" href="#id4" name="non-nascondete-gli-errori-sotto-il-tappeto"><em>Non nascondete gli errori sotto il tappeto</em></a></h2>
+<p>Non trappate l'inaspettato, è una ricetta sicura per avere rogne.
+Usate lo <em>sviluppo incrementale</em>, cioè verificate il funzionamento del
+programma SUBITO, e fissate l'errore SUBITO. Non debuggate mai
+a posteriori, se potete evitarlo, ma scrivete codice testato fin da subito.
+Abbiate una bella suite di test automatici di installazione, per accorgervi
+da subito se c'è un problema quando installate il software su di un'altra
+macchina.</p>
+</div>
+</div>
+<div class="section" id="modulo-1-strumenti-di-introspezione-sviluppo-e-debugging">
+<h1><a class="toc-backref" href="#id5" name="modulo-1-strumenti-di-introspezione-sviluppo-e-debugging">Modulo 1: Strumenti di introspezione, sviluppo e debugging</a></h1>
+<p><em>In questo modulo discuterò gli strumenti da me utilizzati per sviluppare
+in Python sotto Windows. Parlerò di Cygwin come ambiente di lavoro,
+di Python e di IPython come interpreti interattivi, di Idle e di PythonWin
+come IDE, di pydoc e minidoc come tools di introspezione. Inoltre discuterò
+alcune utili librerie e frameworks per Python (Numeric, matplotlib, gnuplot,
+etc.).</em></p>
+<div class="section" id="strumenti-di-introspezione-e-come-ottenere-aiuto">
+<h2><a class="toc-backref" href="#id6" name="strumenti-di-introspezione-e-come-ottenere-aiuto">Strumenti di introspezione e come ottenere aiuto</a></h2>
+<ul class="simple">
+<li><strong>Help in linea:</strong>
+Ottimo</li>
+<li><strong>Pydoc:</strong>
+Standard, può essere usato dalla riga di comando.
+<tt class="docutils literal"><span class="pre">pydoc</span> <span class="pre">-g</span></tt> oppure <tt class="docutils literal"><span class="pre">python</span> <span class="pre">-mpydoc</span> <span class="pre">-g</span></tt>
+vi dà la versione grafica, con funzionalità di search.</li>
+<li><strong>Help di ActiveState:</strong>
+Eccezionale, contiene anche libri di testo, FAQs e how-tos.</li>
+<li><strong>Google:</strong>
+Di tutto, di più.</li>
+<li><strong>Newsgroups:</strong>
+Risolvono i vostri problemi per voi, e gratis.</li>
+</ul>
+</div>
+<div class="section" id="ambienti-di-sviluppo">
+<h2><a class="toc-backref" href="#id7" name="ambienti-di-sviluppo">Ambienti di sviluppo</a></h2>
+<ul class="simple">
+<li><strong>Cygwin:</strong>
+Emulatore Unix sotto Windows. Vi permette di lavorare dalla riga di
+comando comodamente. Evitate di perdere tempo a cliccare a destra e
+a manca e avete una stabilità maggiore di quella di un ambiente
+grafico.</li>
+<li><strong>Idle:</strong>
+Ambiente di sviluppo per Python che viene con la distribuzione standard.
+Un pò povero, con qualche difetto, ma semplice e portabile ovunque.</li>
+<li><strong>PythonWin:</strong>
+Ambiente di sviluppo per Python che viene con la distribuzione ActiveState
+per Windows. Più sofisticato di Idle e più integrato con Windows. Ha dei
+pro e dei contro.</li>
+<li><strong>WingIDE, Eric/Qt Designer, Komodo, Boa Constructor:</strong>
+Ambienti di sviluppo di cui esiste una versione commerciale. In generale
+hanno un look più professionale e sono utili se uno deve dare interfacce
+grafiche. WingIDE ha il debugger migliore, a quanto ho sentito.</li>
+<li><strong>Emacs o Vi:</strong>
+Un Real Programmer (TM) vi dirà che al mondo esistono due soli editor:
+Emacs e Vi. Tutto il resto è spazzatura. Emacs e Vi girano bene sotto
+Windows, ma funzionano al meglio sotto Unix.</li>
+</ul>
+</div>
+<div class="section" id="strumenti-di-debugging">
+<h2><a class="toc-backref" href="#id8" name="strumenti-di-debugging">Strumenti di debugging</a></h2>
+<ul class="simple">
+<li><strong>print:</strong> è la soluzione usata dai migliori programmatori Python;</li>
+<li><strong>pdb:</strong> sembra il debugger dei poveri, ma è standard e funziona;</li>
+<li><strong>mille altri debuggers</strong>, compreso un nuovissimo winpdb dall'autore
+del pdb, da valutare;</li>
+<li><strong>programmazione test-driven:</strong> con questa metodologia la stragrande
+maggioranza dei bugs vengono individuati subito, non appena il
+codice viene scritto, e vi troverete ad usare il debuggere dieci
+volte di meno di quanto fate ora.</li>
+</ul>
+</div>
+<div class="section" id="strumenti-utili-per-l-utenza-scientifica-ingegneristica">
+<h2><a class="toc-backref" href="#id9" name="strumenti-utili-per-l-utenza-scientifica-ingegneristica">Strumenti utili per l'utenza scientifica/ingegneristica</a></h2>
+<ul class="simple">
+<li><strong>Numeric e/o Numarray:</strong>
+Tutto quello che serve per far conti con le matrici. Numarray è il
+successore di Numeric, con compatibilità al 99%.</li>
+<li><strong>matplotlib:</strong>
+Il meglio per plottare grafici 2D. Richiede Numeric/Numarray.</li>
+<li><strong>ipython:</strong>
+Il miglior interprete interattivo per Python. Eccezionali capacità
+di introspezione e di debugging (è integrato con il Python debugger
+pdb della libreria standard).</li>
+</ul>
+</div>
+</div>
+<div class="section" id="modulo-2-programmazione-di-base-in-python">
+<h1><a class="toc-backref" href="#id10" name="modulo-2-programmazione-di-base-in-python">Modulo 2: Programmazione di base in Python</a></h1>
+<p><em>In questo modulo si ripasseranno molto brevemente le basi di Python e
+si discuteranno le soluzioni al questionario di ammissione. Lo scopo
+più che altro è quello di conoscersi e di chiarire il livello medio
+dei partecipanti e coprire eventuali buchi nella preparazione di base.</em></p>
+<p>Le soluzioni agli esercizi sono riportate nell'ultimo capitolo. Durante le
+correzioni mi sono accordi di vari buchi nella programmazione
+di base in Python che si è cercato di riempire.</p>
+<div class="section" id="encoding">
+<h2><a class="toc-backref" href="#id11" name="encoding">Encoding</a></h2>
+<p>[Illustrato al corso 1] In versioni recenti di Python (dalla 2.3)
+se il vostro script contiene dei caratteri accentati (anche nei commenti)
+ottenete un warning tipo questo:</p>
+<pre class="literal-block">
+sys:1: DeprecationWarning: Non-ASCII character '\xe0' in file x.py
+on line 1, but no encoding declared; see
+http://www.python.org/peps/pep-0263.html for details
+</pre>
+<p>La soluzione e' aggiungere in testa al vostro programma una dichiarazione
+tipo questa:</p>
+<pre class="literal-block">
+#-*- encoding: latin-1 -*-
+</pre>
+<p>(usate latin-15 se il vostro programma contiene il simbolo dell'Euro).</p>
+</div>
+<div class="section" id="pathnames">
+<h2><a class="toc-backref" href="#id12" name="pathnames">Pathnames</a></h2>
+<p>Sfortunatamente Windows usa la backslash come separatore dei pathnames;
+la backslash e' anche il carattere di escaping, quindi ci sono
+problemi:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; print 'documenti\nonna' # \n interpretato come newline
+documenti
+onna
+</pre>
+<p>La soluzione e' usare raw strings:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; print r'documenti\nonna'
+documenti\nonna
+</pre>
+<p>Alternativamente, in versioni recenti di Windows, avreste potuto usare
+anche &quot;/&quot; come separatore:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; import os
+&gt;&gt;&gt; os.path.exists(r'C:\Python24\python.exe')
+True
+&gt;&gt;&gt; os.path.exists(r'C:/Python24/python.exe')
+True
+</pre>
+</div>
+<div class="section" id="insiemi">
+<h2><a class="toc-backref" href="#id13" name="insiemi">Insiemi</a></h2>
+<p>In Python 2.3 gli insiemi sono stati aggiunti come un nuovo tipo di dati
+nel modulo sets (by Alex Martelli); in Python 2.4 gli insiemi sono diventati
+un tipo builtin.</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; s = set('pippo')
+&gt;&gt;&gt; s
+set(['i', 'p', 'o'])
+&gt;&gt;&gt; 'i' in s
+True
+&gt;&gt;&gt; 'p' in s
+True
+&gt;&gt;&gt; 'o' in s
+True
+&gt;&gt;&gt; 'z' in s
+False
+</pre>
+<p>E' possibile calcolare l'unione e l'intersezione di insiemi:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; t = set('aglio')
+&gt;&gt;&gt; s | t
+set(['a', 'g', 'i', 'l', 'o', 'p'])
+&gt;&gt;&gt; s &amp; t
+set(['i', 'o'])
+</pre>
+<p>Il modo compatibile con il passato per usare i sets nello stesso modo nella
+2.3 e nella 2.4 è il seguente:</p>
+<pre class="literal-block">
+try:
+ set:
+except NameError:
+ from sets import Set as set
+</pre>
+<p>Guardare la documentazione standard per saperne di più.</p>
+</div>
+<div class="section" id="differenza-tra-mutabili-e-immutabili">
+<h2><a class="toc-backref" href="#id14" name="differenza-tra-mutabili-e-immutabili">Differenza tra mutabili e immutabili</a></h2>
+<p>Questa è una causa comune di confusione in Python:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; a = 1 # i numeri sono immutabili
+&gt;&gt;&gt; b = a
+&gt;&gt;&gt; a += 1
+&gt;&gt;&gt; a
+2
+&gt;&gt;&gt; b
+1
+</pre>
+<pre class="doctest-block">
+&gt;&gt;&gt; a = [1] # le liste sono mutabili
+&gt;&gt;&gt; b = a
+&gt;&gt;&gt; a += [1]
+&gt;&gt;&gt; a
+[1, 1]
+&gt;&gt;&gt; b
+[1, 1]
+</pre>
+</div>
+<div class="section" id="getattr-e-setattr">
+<h2><a class="toc-backref" href="#id15" name="getattr-e-setattr">getattr e setattr</a></h2>
+<p>[Svolto al corso 1] <tt class="docutils literal"><span class="pre">getattr</span></tt> e <tt class="docutils literal"><span class="pre">setattr</span></tt> servono per richiamare e
+settare metodi il cui nome viene determinato dinamicamente:</p>
+<pre class="literal-block">
+#&lt;getattr_ex.py&gt;
+
+class C(object):
+ def m1(self):
+ print &quot;chiamato m1&quot;
+ def m2(self):
+ print &quot;chiamato m2&quot;
+
+if __name__ == &quot;__main__&quot;:
+ c = C()
+ method = raw_input(&quot;Che metodo devo chiamare? [m1 o m2] &quot;)
+ getattr(c, method)()
+
+#&lt;/getattr_ex.py&gt;
+</pre>
+<p><em>Non usate exec quando getattr basterebbe!</em></p>
+<pre class="doctest-block">
+&gt;&gt;&gt; method = 'm1'
+&gt;&gt;&gt; exec 'c.%s()' % method # funziona ma è brutto
+chiamato m1
+&gt;&gt;&gt; getattr(c, method)() # il modo giusto
+chiamato m1
+</pre>
+<p>Per <tt class="docutils literal"><span class="pre">setattr</span></tt> vedere la documentazione.</p>
+</div>
+<div class="section" id="gestione-dei-processi">
+<h2><a class="toc-backref" href="#id16" name="gestione-dei-processi">Gestione dei processi</a></h2>
+<p>Come far partire un processo in parallelo:</p>
+<pre class="literal-block">
+import subprocess
+
+PLAYER =&quot;mplay32&quot;
+
+def play_song(song):
+ subprocess.Popen([PLAYER, &quot;/play&quot;, &quot;/close&quot;, song]) # NON BLOCCA!
+ print &quot;Partito&quot;
+
+
+if __name__ == &quot;__main__&quot;:
+ play_song(&quot;c:/Documents and Settings/micheles/Desktop/Music/1. &quot;
+ &quot;Theme from Harry's Game.mp3&quot;)
+</pre>
+<p><tt class="docutils literal"><span class="pre">subprocess.call</span></tt> fa partire il processo e blocca il programma fintanto
+che il processo non è terminato. Ho anche fatto vedere cosa succede
+se uno dei processi solleva qualche eccezione inaspettata ma viene chiuso
+correttamente grazie al try .. finally:</p>
+<pre class="literal-block">
+#&lt;main.py&gt;
+
+&quot;Chiama due processi proc1a.py e proc1b.py&quot;
+
+import subprocess
+
+CMD_a = [&quot;python&quot;, &quot;-c&quot;, &quot;import proc1a; proc1a.main()&quot;]
+CMD_b = [&quot;python&quot;, &quot;-c&quot;, &quot;import proc1b; proc1b.main()&quot;]
+
+if __name__ == &quot;__main__&quot;:
+ p_a = subprocess.Popen(CMD_a)
+ p_b = subprocess.Popen(CMD_b)
+
+#&lt;/main.py&gt;
+</pre>
+<p>Processo 1a:</p>
+<pre class="literal-block">
+#&lt;proc1a.py&gt;
+
+import time
+
+def main():
+ for i in range(10):
+ print &quot;hello&quot;
+ time.sleep(1)
+
+if __name__ == &quot;__main__&quot;:
+ main()
+
+#&lt;/proc1a.py&gt;
+</pre>
+<p>Processo 1b:</p>
+<pre class="literal-block">
+#&lt;proc1b.py&gt;
+
+#-*- encoding: latin-1 -*-
+import time, sys
+
+def main():
+ try:
+ f = file(&quot;proc1b.py&quot;)
+ for i in range(10):
+ print &quot;world&quot;
+ if i == 5:
+ raise RuntimeError(&quot;Ahia!&quot;)
+ time.sleep(1)
+ finally:
+ f.close()
+ print &quot;Il file è stato chiuso correttamente.&quot;
+
+if __name__ == &quot;__main__&quot;:
+ main()
+
+#&lt;/proc1b.py&gt;
+</pre>
+<p>Ho anche illustrato brevemente come si possono gestire i processi da
+Twisted:</p>
+<pre class="literal-block">
+#&lt;proc2a.py&gt;
+
+&quot;Un processo che genera numeri casuali e li salva nel file data.txt&quot;
+
+import random
+
+def main():
+ ro = random.Random()
+ out = file(&quot;data.txt&quot;, &quot;w&quot;)
+ for number in ro.sample(range(1000), 100):
+ print &gt;&gt; out, number
+ out.close()
+ print &quot;Dati salvati sul file 'data.txt'&quot;
+
+if __name__ == &quot;__main__&quot;:
+ main()
+
+#&lt;/proc2a.py&gt;
+
+#&lt;proc2b.py&gt;
+
+&quot;Un processo che genera l'istogramma histo.png dai dati in data.txt&quot;
+
+from pylab import hist, savefig
+
+def main():
+ hist([int(n) for n in file(&quot;dat.txt&quot;)], 10)
+ savefig(&quot;histo.png&quot;)
+ print &quot;Istogramma salvato sul file 'histo.png'&quot;
+
+if __name__ == &quot;__main__&quot;:
+ main()
+
+#&lt;/proc2b.py&gt;
+
+#&lt;twisted_main.py&gt;
+
+&quot;Il main che chiama proc2a.py e proc2b.py nell'ordine e gestisce gli errori&quot;
+
+import webbrowser, sys
+if sys.platform == &quot;win32&quot;:
+ from twisted.internet import win32eventreactor
+ win32eventreactor.install()
+
+from twisted.internet.utils import getProcessOutput
+from twisted.internet import reactor
+
+def scrivi_messaggio(err):
+ print err.getErrorMessage()
+ reactor.stop()
+ import pdb; pdb.set_trace() # fa partire il debugger in caso di errore
+
+def visualizza_histo(out_di_genera_histo):
+ print out_di_genera_histo
+ webbrowser.open(&quot;histo.png&quot;)
+
+def genera_histo(out_di_genera_dati):
+ print out_di_genera_dati
+ getProcessOutput(sys.executable, (r&quot;c:\corso\processi\proc2b.py&quot;,)) \
+ .addCallback(visualizza_histo) \
+ .addErrback(scrivi_messaggio)
+
+def genera_dati():
+ getProcessOutput(sys.executable, (r&quot;c:\corso\processi\proc2a.py&quot;,)) \
+ .addCallback(genera_histo) \
+ .addErrback(scrivi_messaggio)
+
+if __name__ == &quot;__main__&quot;:
+ reactor.callLater(0, genera_dati) # call &quot;genera_dati&quot; after 0 seconds
+ reactor.run()
+
+#&lt;/twisted_main.py&gt;
+</pre>
+<p>In questo esempio ho usato <tt class="docutils literal"><span class="pre">sys.executable</span></tt>, che contiene il nome
+completo dell'eseguibile Python (per esempio <tt class="docutils literal"><span class="pre">C:\Python24\python.exe</span></tt>)
+con cui il programma principale è stato lanciato. Questo assicura che
+i processi secondari vengano lanciati con quella versione di Python
+(utile se avete installato contemporaneamente piu' versioni di Python
+e ci possono essere dei dubbi, oppure se il path non e' settato
+correttamente e l'eseguibile Python non viene trovato).</p>
+<p>A volte, nonostante tutta la buona volontà, i processi vanno fuori
+controllo. E' possibile ammazzarli brutalmente, con una funzione
+<tt class="docutils literal"><span class="pre">kill</span></tt> come la seguente:</p>
+<pre class="literal-block">
+import os
+
+try: # we are on Windows
+ import win32api
+ def kill(pid, *unix_compatibility_dummy_args):
+ handle = win32api.OpenProcess(1, False, pid) # open handle to kill
+ win32api.TerminateProcess(handle, -1)
+ win32api.CloseHandle(handle)
+ os.kill = kill # fix os
+except ImportError: # we are on Unix
+ pass
+</pre>
+<p>In questo modo di fare, il modulo 'os' della libreria standard viene
+fissato automaticamente, aggiungendogli una funzione 'kill' che è
+mancante nell'ambiente Windows ma che può facilmente essere implementata
+usando le win32api (che non vengono con la distribuzione standard ma sono
+incluse con la distribuzione dell'ActiveState).</p>
+<p>Naturalmente cambiare moduli della libreria standard al volo NON È
+CONSIGLIATO, ma è sempre meglio che modificare a mano il codice
+sorgente e mantenere una propria versione modificata.</p>
+</div>
+<div class="section" id="iteratori-e-generatori">
+<h2><a class="toc-backref" href="#id17" name="iteratori-e-generatori">Iteratori e generatori</a></h2>
+<p>Un iterabile è un qualunque oggetto su cui si può iterare con un
+ciclo &quot;for&quot;; un iteratore è un oggetto con un metodo .next().
+Il modo più comune per definire iteratori è tramite un generatore,
+cioè una &quot;funzione&quot; con uno &quot;yield&quot;:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; def gen123():
+... yield 1
+... yield 2
+... yield 3
+...
+&gt;&gt;&gt; it = gen123()
+&gt;&gt;&gt; it.next()
+1
+&gt;&gt;&gt; it.next()
+2
+&gt;&gt;&gt; it.next()
+3
+&gt;&gt;&gt; it.next()
+Traceback (most recent call last):
+ File '&lt;stdin&gt;', line 1, in ?
+StopIteration
+</pre>
+<p>Un ciclo &quot;for&quot; internamente converte l'iterabile in un iteratore,
+chiama il metodo &quot;.next()&quot; successivamente e trappa l'eccezione StopIteration,
+uscendo dal loop quando non c'è più nulla su cui iterare:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; it = gen123()
+&gt;&gt;&gt; for i in it: print i
+...
+1
+2
+3
+</pre>
+</div>
+</div>
+<div class="section" id="modulo-3-tipici-errori-di-programmazione-e-gestione-delle-eccezioni">
+<h1><a class="toc-backref" href="#id18" name="modulo-3-tipici-errori-di-programmazione-e-gestione-delle-eccezioni">Modulo 3. Tipici errori di programmazione e gestione delle eccezioni</a></h1>
+<p><em>Si discuteranno buoni e cattivi esempi di programmazione presi da software
+reale scritto alla Magneti Marelli. Si discuteranno alcune tecniche
+per interpretare i tracebacks di Python e per identificare l'origine dei
+problemi.</em></p>
+<div class="section" id="l-errore-pi-tipico-con-le-eccezioni">
+<h2><a class="toc-backref" href="#id19" name="l-errore-pi-tipico-con-le-eccezioni">L'errore più tipico con le eccezioni</a></h2>
+<p>Bisogna assolutamente evitare codice come il seguente:</p>
+<pre class="literal-block">
+try:
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+except:
+ bla-bla
+</pre>
+<p>Nel blocco <tt class="docutils literal"><span class="pre">try</span></tt> dev'esserci la cosa più semplice possibile, per
+limitare i tipi di eccezione che possono nascere. Inoltre l'except nudo
+e' orribile perchè trappa qualunque cosa, anche quello che non vorreste.
+La cosa giusta da fare è del tipo:</p>
+<pre class="literal-block">
+try:
+ bla-bla
+except MyException, e: # sempre specificare l'eccezione aspettata
+ print e
+except OtherException,e:
+ print e
+...
+</pre>
+<p>Non trappate l'inaspettato, altrimenti non capirete mai qual è stata
+l'origine di un problema.</p>
+</div>
+<div class="section" id="il-try-finally-una-grande-idea">
+<h2><a class="toc-backref" href="#id20" name="il-try-finally-una-grande-idea">Il try .. finally è una grande idea</a></h2>
+<p>Molto spesso quello che volete non è tanto il try .. except, quanto il
+try .. finally: il vantaggio del try .. finally è che
+<em>non vi nasconde l'eccezione</em> e nello stesso tempo vi <em>garantisce che quello
+che deve essere chiuso correttamente venga chiuso correttamente</em> in ogni caso.
+C'è un eccezione a questa regola: se ammazzate un processo di brutto con un
+kill, il try .. finally non può salvarvi. Il try .. finally vi
+salva per tutte le eccezioni Python, compreso il CTRL-C (KeyboardInterrupt)
+e il sys.exit() (SystemExit).</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; try:
+... raise RuntimeError(&quot;Ahia&quot;)
+... finally:
+... print &quot;Io vengo eseguito SEMPRE, anche se c'è un'eccezione!&quot;
+...
+Io vengo eseguito SEMPRE, anche se c'e' un'eccezione!
+Traceback (most recent call last):
+ File '&lt;stdin&gt;', line 2, in ?
+RuntimeError: Ahia
+</pre>
+</div>
+<div class="section" id="uso-di-assert">
+<h2><a class="toc-backref" href="#id21" name="uso-di-assert">Uso di assert</a></h2>
+<p>Per asserire che una condizione è verificata con certezza:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; def div2(x):
+... assert isinstance(x, int), '%s non è un numero intero' % x
+... return x/2
+...
+&gt;&gt;&gt; div2(14)
+7
+&gt;&gt;&gt; div2(14.0)
+Traceback (most recent call last):
+ File '&lt;stdin&gt;', line 1, in ?
+ File '&lt;stdin&gt;', line 2, in div2
+AssertionError: 14.0 non è un numero intero
+</pre>
+<p>Tipicamente si usa in &quot;sanity checks&quot;, per essere sicuri che un parametro
+sia esattamente quello che ci si aspetta, in casi di eccezioni gravi; se
+l'assert non è rispettato, tutto il programma deve bloccarsi.</p>
+</div>
+<div class="section" id="non-usate-exec">
+<h2><a class="toc-backref" href="#id22" name="non-usate-exec">Non usate exec</a></h2>
+<p>'exec' è un costrutto pericolosissimo che va riservato solo a chi sa
+cosa sta facendo. Spesso e volentieri si usa soltanto per ignoranza
+dell'esistenza di una soluzione migliore.</p>
+<p>Esempio:</p>
+<pre class="literal-block">
+exec file(&quot;myscript.py&quot;).read()
+</pre>
+<p>è UN ERRORE GRAVE per vari motivi.</p>
+<p>In primo luogo, in caso di eccezioni sollevate in 'myscript.py'
+perdete informazione su dove si trova l'errore (cioè nel file &quot;myscript.py&quot;)
+e rendete impossibile la vita al debugger; in secondo luogo, sporcate il
+namespace del vostro programma in maniera potenzialmente pericolosa. La cosa
+giusta da fare è:</p>
+<pre class="literal-block">
+dic = {}
+execfile(&quot;myscript.py&quot;, dic)
+</pre>
+<p>che non perde informazioni e non sporca il namespace, perchè i nomi
+definiti in myscript.py verranno confinati nel dizionario. Leggetevi
+la documentazione di 'execfilè per saperne di più.</p>
+</div>
+<div class="section" id="come-far-partire-pdb-automaticamente-in-caso-di-eccezioni-inaspettate">
+<h2><a class="toc-backref" href="#id23" name="come-far-partire-pdb-automaticamente-in-caso-di-eccezioni-inaspettate">Come far partire pdb automaticamente in caso di eccezioni inaspettate</a></h2>
+<p>[Illustrato al corso 1]</p>
+<pre class="literal-block">
+#&lt;exc_debug.py&gt;
+
+# recipe in the Python cookbook first edition, chapter 14.5
+
+import sys
+
+def info(type, value, tb):
+ if hasattr(sys, 'ps1') or not sys.stderr.isatty() or \
+ type == SyntaxError:
+ # we are in interactive mode or we don't have a tty-like
+ # device, so we call the default hook
+ sys.__excepthook__(type, value, tb)
+ else:
+ import traceback, pdb
+ # we are NOT in interactive mode, print the exception...
+ traceback.print_exception(type, value, tb)
+ print
+ # ...then start the debugger in post-mortem mode.
+ pdb.pm()
+
+sys.excepthook = info
+
+#&lt;/exc_debug.py&gt;
+</pre>
+<p>Se un programma importa <tt class="docutils literal"><span class="pre">exc_debug</span></tt>, il Python debugger partirà
+automaticamente in caso di eccezioni non trappate. Per esempio eseguire</p>
+<pre class="literal-block">
+#&lt;example.py&gt;
+import exc_debug
+a = 1
+b = 0
+a/b
+#&lt;/example.py&gt;
+</pre>
+<p>fa partire il debugger:</p>
+<pre class="literal-block">
+$ python example.py
+Traceback (most recent call last):
+ File &quot;example.py&quot;, line 4, in ?
+ a/b
+ZeroDivisionError: integer division or modulo by zero
+
+&gt; /mnt/hda2/cygwin/home/micheles/md/pypers/marelli/materiale/example.py(4)?()
+-&gt; a/b
+(Pdb) print a
+1
+(Pdb) print b
+0
+Pdb) !b = 1 # cambia il valore di b
+(Pdb) print a/b
+1
+</pre>
+<p>Date <tt class="docutils literal"><span class="pre">help</span> <span class="pre">pdb</span></tt> dall'interno del debugger per avere informazioni sul suo
+funzionamento.</p>
+</div>
+<div class="section" id="eccezioni-e-threads">
+<h2><a class="toc-backref" href="#id24" name="eccezioni-e-threads">Eccezioni e threads</a></h2>
+<p>Un'eccezione non trappata blocca soltanto il thread in cui si è verificata,
+NON tutto il programma:</p>
+<pre class="literal-block">
+#&lt;esempio1.py&gt;
+
+import threading, time, sys
+
+def print_hello():
+ for i in range(10):
+ print &quot;hello&quot;
+ if i == 5:
+ raise RuntimeError(&quot;Problema a runtime&quot;)
+ time.sleep(1)
+
+def print_world():
+ for i in range(10):
+ print &quot;world&quot;
+ time.sleep(1)
+
+threading.Thread(target=print_hello).start()
+threading.Thread(target=print_world).start()
+
+#&lt;/esempio1.py&gt;
+</pre>
+<p>dà come output:</p>
+<pre class="literal-block">
+$ python esempio1.py
+hello
+world
+hello
+world
+hello
+world
+hello
+world
+hello
+world
+hello
+world
+Exception in thread Thread-1:
+Traceback (most recent call last):
+ File &quot;/usr/lib/python2.4/threading.py&quot;, line 442, in __bootstrap
+ self.run()
+ File &quot;/usr/lib/python2.4/threading.py&quot;, line 422, in run
+ self.__target(*self.__args, **self.__kwargs)
+ File &quot;esempio1.py&quot;, line 7, in print_hello
+ raise RuntimeError(&quot;Problema a runtime&quot;)
+RuntimeError: Problema a runtime
+
+world
+world
+world
+world
+</pre>
+<p>Quindi uno è costretto a implementare un meccanismo di controllo, tipo
+il seguente:</p>
+<pre class="literal-block">
+import threading, time, sys
+
+END = False
+
+def print_hello():
+ global END
+ i = 0
+ while not END:
+ i += 1
+ print &quot;hello&quot;
+ if i == 5:
+ try:
+ raise RuntimeError(&quot;Problema a runtime&quot;)
+ except RuntimeError, e:
+ END = True
+ time.sleep(1)
+
+def print_world():
+ i = 0
+ while not END:
+ print &quot;world&quot;
+ time.sleep(1)
+
+threading.Thread(target=print_hello).start()
+threading.Thread(target=print_world).start()
+</pre>
+<p>Questa è una soluzione artigianale, che usa una variabile globale, sfruttando
+il fatto che le variabili globali sono condivise fra tutti i thread (questo
+può anche causare danni, se non si sta attenti).</p>
+<p>La strada consigliata per comunicare fra threads è quella di usare una coda
+[esempio svolto al corso 1]:</p>
+<pre class="literal-block">
+&quot;Esempio di due threads comunicanti tramite una queue.&quot;
+
+import time, threading, Tkinter, Queue
+
+queue = Queue.Queue()
+
+def print_hello():
+ for i in range(10):
+ try:
+ messaggio = queue.get_nowait()
+ except Queue.Empty:
+ pass
+ else:
+ if messaggio == &quot;terminate&quot;: break
+ print &quot;%s, hello&quot; % i
+ time.sleep(1)
+
+def print_world():
+ for i in range(10):
+ print &quot;%s, world&quot; % i
+ if i == 5:
+ queue.put(&quot;terminate&quot;) # manda il messaggio di terminazione
+ root.quit()
+ raise RuntimeError(&quot;Errore nel thread print_world!&quot;)
+ time.sleep(1)
+
+root = Tkinter.Tk()
+
+for func in print_hello, print_world:
+ th = threading.Thread(target=func)
+ th.start()
+
+root.mainloop()
+</pre>
+<p>Questo esempio fa anche vedere che chiudere la finestrella grafica NON
+uccide i threads che stanno girando.</p>
+<p>I meccanismi di controllo per bloccare i thread sono notoriamente fragili
+e piccoli errori possono farvi grossi danni.</p>
+<p>Debuggare i threads è notoriamente un macello.</p>
+<p>L'unica soluzione vera è evitare i threads quando è possibile.</p>
+</div>
+</div>
+<div class="section" id="modulo-4-sviluppo-orientato-ai-test">
+<h1><a class="toc-backref" href="#id25" name="modulo-4-sviluppo-orientato-ai-test">Modulo 4. Sviluppo orientato ai test</a></h1>
+<p><em>Come scrivere software con tecnologie agili, con lo scopo di ridurre e
+tenere sotto controllo i bugs. Discussione di doctest, py.test e unittest.
+Esempi di programmazione test driven.</em></p>
+<div class="section" id="consigli-di-carattere-generale">
+<h2><a class="toc-backref" href="#id26" name="consigli-di-carattere-generale">Consigli di carattere generale</a></h2>
+<ul class="simple">
+<li>testate SUBITO, non debuggate dopo (ad ogni una riga di codice che si
+scrive, si testa che funzioni e che non distrugga quello che funzionava
+prima).</li>
+<li>scrivete software in maniera che sia testabile (per esempio create
+sempre anche una versione non-grafica di un programma grafico, perchè
+la versione testuale si testa <strong>molto</strong> più facilmente).</li>
+<li>non abbiate paura a scrivervi un vostro ambiente di test personalizzato.</li>
+<li>tenete conto che unittest e doctest esistono e possono aiutarvi infinitamente
+nel gestire i vostri test.</li>
+</ul>
+</div>
+<div class="section" id="usare-unittest">
+<h2><a class="toc-backref" href="#id27" name="usare-unittest">Usare unittest</a></h2>
+<p>Tipicamente con unittest si divide la libreria da testare:</p>
+<pre class="literal-block">
+#&lt;isnumber.py&gt;
+
+def is_number(arg):
+ &quot;Verifica se la stringa arg è un numero valido&quot;
+ try:
+ float(arg)
+ except ValueError:
+ return False
+ else:
+ return True
+
+#&lt;/isnumber.py&gt;
+</pre>
+<p>dal file di test, che convenzionalmente ha un nome che inizia per &quot;test&quot;:</p>
+<pre class="literal-block">
+#&lt;test_isnumber.py&gt;
+
+import unittest
+
+from isnumber import is_number
+
+class TestIsNumber(unittest.TestCase):
+
+ def setUp(self):
+ print &quot;sto inizializzando&quot;
+
+ # test positivi
+ def test_1(self):
+ &quot;Testa che '1' è un numero buono.&quot;
+ self.assertTrue(is_number(&quot;1&quot;))
+ def test_2(self):
+ &quot;Testa che '1.3' è un numero buono.&quot;
+ self.assertTrue(is_number(&quot;1.3&quot;))
+ def test_3(self):
+ &quot;Testa che '+1.3' è un numero buono.&quot;
+ self.assertTrue(is_number(&quot;+1.3&quot;))
+ def test_4(self):
+ &quot;Testa che '-1.3' è un numero buono.&quot;
+ self.assertTrue(is_number(&quot;-1.3&quot;))
+
+ # test negativi
+ def test_5(self):
+ &quot;Testa che '1-.3' non è un numero buono.&quot;
+ self.assertFalse(is_number(&quot;1-.3&quot;))
+ def test_6(self):
+ &quot;Testa che 'à non è un numero buono.&quot;
+ self.assertFalse(is_number(&quot;a&quot;))
+ def test_7(self):
+ &quot;Testa che '42' è un numero buono.&quot;
+ self.assertTrue(is_number(&quot;42&quot;))
+
+ def tearDown(self):
+ print &quot;Sto chiudendo quello che c'è da chiudere&quot;
+
+if __name__ == &quot;__main__&quot;:
+ unittest.main()
+
+#&lt;/test_isnumber.py&gt;
+</pre>
+<p>Eseguire i tests con l'opzione verbose da:</p>
+<pre class="literal-block">
+$ python test_isnumber.py -v
+Testa che '1' è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+Testa che '1.3' è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+Testa che '+1.3' è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+Testa che '-1.3' è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+Testa che '1-.3' non è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+Testa che 'à non è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+Testa che '42' è un numero buono. ... sto inizializzando
+Sto chiudendo quello che c'è da chiudere
+ok
+
+----------------------------------------------------------------------
+Ran 7 tests in 0.001s
+
+OK
+</pre>
+<p>Questo mostra che i metodi <tt class="docutils literal"><span class="pre">setUp</span></tt> e <tt class="docutils literal"><span class="pre">tearDown</span></tt> vengono chiamati
+<em>per ogni test</em>, quindi tutti i test si svolgono in un ambiente pulito.</p>
+<p>E' normale avere un file di test più lungo della libreria da testare.</p>
+<p>E' possibile specificare le eccezioni aspettate:</p>
+<pre class="literal-block">
+#&lt;test_exc.py&gt;
+
+import unittest
+
+def divide(a, b):
+ return a/b
+
+class TestIsNumber(unittest.TestCase):
+ def test_1(self):
+ &quot;Divide 4/2&quot;
+ self.assertEqual(divide(4,2), 2)
+ def test_2(self):
+ &quot;Divide 4/0&quot;
+ self.assertRaises(ZeroDivisionError, divide, 4, 0)
+
+
+if __name__ == &quot;__main__&quot;:
+ unittest.main()
+
+#&lt;/test_exc.py&gt;
+
+$ python test_exc.py -v
+Divide 4/2 ... ok
+Divide 4/0 ... ok
+
+----------------------------------------------------------------------
+Ran 2 tests in 0.001s
+
+OK
+</pre>
+</div>
+<div class="section" id="usare-doctest">
+<h2><a class="toc-backref" href="#id28" name="usare-doctest">Usare doctest</a></h2>
+<p>L'uso più semplice, eseguire i doctest che si trovano nelle stringhe
+di documentazione di un modulo:</p>
+<pre class="literal-block">
+#&lt;esempio_banale.py&gt;
+
+def sum12():
+ &quot;&quot;&quot;Questa funzione ritorna la somma di 1 + 2::
+ &gt;&gt;&gt; sum12()
+ 3&quot;&quot;&quot;
+ return 1+2
+
+if __name__ == &quot;__main__&quot;:
+ import doctest; doctest.testmod()
+
+#&lt;/esempio_banale.py&gt;
+</pre>
+<p>Ecco come eseguire i tests con l'opzione verbose:</p>
+<pre class="literal-block">
+$ python esempio_banale.py -v
+Trying:
+ sum12()
+Expecting:
+ 3
+ok
+1 items had no tests:
+ __main__
+1 items passed all tests:
+ 1 tests in __main__.sum12
+1 tests in 2 items.
+1 passed and 0 failed.
+Test passed.
+</pre>
+<p>Eseguire i doctest che si trovano in un file di testo separato (nuova
+funzionalità di Python 2.4):</p>
+<pre class="literal-block">
+#&lt;doctest_runner.py&gt;
+
+import doctest
+
+if __name__== &quot;__main__&quot;:
+ doctest.testfile(&quot;test_isnumber.txt&quot;)
+
+#&lt;/doctest_runner.py&gt;
+</pre>
+<p>Contenuto di 'test_isnumber.txt':</p>
+<pre class="literal-block">
+Questa è la documentazione della funzione isnumber
+====================================================
+
+Esempi di uso:
+
+&gt;&gt;&gt; from isnumber import is_number
+&gt;&gt;&gt; is_number(&quot;1&quot;)
+True
+&gt;&gt;&gt; is_number(&quot;1.3&quot;)
+True
+&gt;&gt;&gt; is_number(&quot;+1.3&quot;)
+True
+&gt;&gt;&gt; is_number(&quot;-1.3&quot;)
+True
+&gt;&gt;&gt; is_number(&quot;1-.3&quot;)
+False
+&gt;&gt;&gt; is_number(&quot;a&quot;)
+False
+&gt;&gt;&gt; is_number(&quot;42&quot;)
+True
+&gt;&gt;&gt; 1/0
+Traceback (most recent call last):
+ kkkkdjjfkf
+ZeroDivisionError: integer division or modulo by zero
+</pre>
+<p>Eseguire i tests:</p>
+<pre class="literal-block">
+$ python doctest_runner.py -v
+Trying:
+ from isnumber import is_number
+Expecting nothing
+ok
+Trying:
+ is_number(&quot;1&quot;)
+Expecting:
+ True
+ok
+Trying:
+ is_number(&quot;1.3&quot;)
+Expecting:
+ True
+ok
+Trying:
+ is_number(&quot;+1.3&quot;)
+Expecting:
+ True
+ok
+Trying:
+ is_number(&quot;-1.3&quot;)
+Expecting:
+ True
+ok
+Trying:
+ is_number(&quot;1-.3&quot;)
+Expecting:
+ False
+ok
+Trying:
+ is_number(&quot;a&quot;)
+Expecting:
+ False
+ok
+Trying:
+ is_number(&quot;42&quot;)
+Expecting:
+ True
+ok
+Trying:
+ 1/0
+Expecting:
+ Traceback (most recent call last):
+ kkkkdjjfkf
+ ZeroDivisionError: integer division or modulo by zero
+ok
+1 items passed all tests:
+ 9 tests in test_isnumber.txt
+9 tests in 1 items.
+9 passed and 0 failed.
+Test passed.
+</pre>
+<p>Confrontare la leggibilità di <tt class="docutils literal"><span class="pre">test_isnumber.txt</span></tt> con la leggibilità
+di <tt class="docutils literal"><span class="pre">test_isnumber.py</span></tt>, basato su unittest. Leggetevi il mio seminario su
+doctest (in allegato) per convincervi che doctest è il migliore. Anche perchè
+i doctest possono essere convertiti in unittest automaticamente, a partire
+da Python 2.4</p>
+<p>Per convertire i test contenuti in 'mymodulè da doctest a unittest:</p>
+<pre class="literal-block">
+import doctest, unittest, mymodule
+
+if __name__== &quot;__main__&quot;:
+ suite = doctest.DocTestSuite(mymodule)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+</pre>
+<p>E' anche possibile contenere i tests contenuti in un file di
+tipo testo da doctest a unittest, vedere la documentazione.</p>
+<p>Correntemente, doctest non ha un meccanismo predefinito corrispondente
+ai metodi <tt class="docutils literal"><span class="pre">setUp</span></tt> e <tt class="docutils literal"><span class="pre">tearDown</span></tt> di unittest, ma potete impostarlo a mano.</p>
+</div>
+<div class="section" id="un-esempio-di-programma-sviluppato-in-maniera-incrementale">
+<h2><a class="toc-backref" href="#id29" name="un-esempio-di-programma-sviluppato-in-maniera-incrementale">Un esempio di programma sviluppato in maniera incrementale</a></h2>
+<p>Il seguente esempio svolto al corso intendeva dimostrare:</p>
+<ol class="arabic simple">
+<li>Come si sviluppa un programma in maniera incrementale (ad ogni nuova riga di
+codice si fa una verifica immediata del funzionamento dell'insieme);</li>
+<li>Come si fanno scelte architetturali in maniera tale da assicurare la
+testabilità del prodotto finale in maniera semplice ed automatica;</li>
+<li>Come sfruttare la libreria standard di Python al meglio, usando il
+modulo cmd;</li>
+<li>Come dividere il codice in metodi pubblici, metodi di utilità e
+metodi di debugging;</li>
+<li>Come assicurarsi che il programma venga chiuso propriamente, anche
+nel caso di eccezioni impreviste e imprevedibili;</li>
+</ol>
+<pre class="literal-block">
+# -*- encoding: latin-1 -*-
+import os, cmd, subprocess, lib, time # lib fissa os.kill
+from pywintypes import error as WindowsProcessDidNotStartCorrectly
+
+MUSICDIR = &quot;C:/Documents and Settings/micheles/Desktop/Music&quot;
+
+def play_song(name):
+ po = subprocess.Popen([&quot;mplay32&quot;, &quot;/play&quot;, &quot;/close&quot;, name])
+ return po.pid
+
+class InterpreteDiComandi(cmd.Cmd):
+ cwd = MUSICDIR
+ prompt = &quot;Player&gt; &quot;
+ def preloop(self):
+ self.process_list = []
+ os.chdir(MUSICDIR)
+
+ def do_play(self, arg):
+ &quot;Suona una canzone&quot;
+ if not arg:
+ print &quot;Per favore scrivi il nome di una canzone!&quot;
+ else:
+ self.process_list.append(play_song(arg))
+
+ def do_quit(self, dummy):
+ &quot;Esce dall'interprete.&quot;
+ return True
+
+ def safe_kill(self, pid):
+ try:
+ os.kill(pid)
+ except WindowsProcessDidNotStartCorrectly, e:
+ print e
+
+ def do_kill(self, arg):
+ &quot;Uccide il player&quot;
+ try:
+ pid = self.process_list.pop()
+ except IndexError:
+ print &quot;Hai già ucciso tutti i processi!&quot;
+ else:
+ self.safe_kill(pid)
+
+ def postloop(self):
+ for pid in self.process_list:
+ self.safe_kill(pid)
+ print &quot;Ho ucciso tutto!&quot;
+ os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+ # metodi che possono essere utili per il debugging
+ def do_print_dir(self, arg):
+ &quot;Comando utile per il debugging&quot;
+ print self.cwd
+
+ def do_raise_exc(self, dummy):
+ raise RuntimeError(&quot;Tanto per vedere che succede&quot;)
+
+ def do_sleep(self, arg):
+ &quot;utile per vedere quello che i test automatici stanno facendo&quot;
+ time.sleep(int(arg))
+
+i = InterpreteDiComandi()
+
+try:
+ i.cmdloop()
+finally: # assicura la chiusura anche in caso di eccezione
+ i.postloop()
+</pre>
+<p>Nel caso regolare (senza eccezioni impreviste) .postloop è chiamato 2 volte,
+ma questo non fa danno.</p>
+<p>Questo potrebbe essere il codice corrispondente ad un test automatico:</p>
+<pre class="literal-block">
+$ more test_player.cmd
+play
+sleep 2
+play 2. Croi Croga.mp
+sleep 2
+play 2. Croi Croga.mp3
+sleep 2
+kill
+sleep 2
+quit
+</pre>
+<p>(la prima canzone non esiste, in modo da poter vedere come viene segnalato
+l'errore) che verrebbe eseguito così:</p>
+<pre class="literal-block">
+$ python player.py &lt; test_player.cmd
+</pre>
+</div>
+</div>
+<div class="section" id="modulo-5-design-documentazione-e-manutenzione-di-librarie">
+<h1><a class="toc-backref" href="#id30" name="modulo-5-design-documentazione-e-manutenzione-di-librarie">Modulo 5: Design, documentazione e manutenzione di librarie</a></h1>
+<p><em>Pratiche di programmazione &quot;in the large&quot;. Moduli, packages, strumenti di
+documentazione e di installazione. Applicazioni pratiche di principi generali
+quali disaccoppiamento, modularità, non duplicazione del codice.</em></p>
+<div class="section" id="la-filosofia-del-python">
+<h2><a class="toc-backref" href="#id31" name="la-filosofia-del-python">La filosofia del Python</a></h2>
+<pre class="doctest-block">
+&gt;&gt;&gt; import this
+The Zen of Python, by Tim Peters
+Beautiful is better than ugly.
+Explicit is better than implicit.
+Simple is better than complex.
+Complex is better than complicated.
+Flat is better than nested.
+Sparse is better than dense.
+Readability counts.
+Special cases aren't special enough to break the rules.
+Although practicality beats purity.
+Errors should never pass silently.
+Unless explicitly silenced.
+In the face of ambiguity, refuse the temptation to guess.
+There should be one-- and preferably only one --obvious way to do it.
+Although that way may not be obvious at first unless you are Dutch.
+Now is better than never.
+Although never is often better than *right* now.
+If the implementation is hard to explain, it's a bad idea.
+If the implementation is easy to explain, it may be a good idea.
+Namespaces are one honking great idea -- let's do more of those!
+</pre>
+</div>
+<div class="section" id="principio-del-disaccoppiamento">
+<h2><a class="toc-backref" href="#id32" name="principio-del-disaccoppiamento">Principio del disaccoppiamento</a></h2>
+<p>Questo è il principio guida di tutta la programmazione e non solo, tutto
+il resto nasce di conseguenza.</p>
+<p>Il principio dice: <strong>cercate di disaccoppiare il più possibile
+le componenti del vostro sistema</strong>.</p>
+<p><em>Un componente si dice disaccoppiato se
+può essere rimosso o sostituito senza danneggiare il resto del sistema.</em></p>
+<p>Per esempio:</p>
+<ul class="simple">
+<li>disaccoppiare l'ambiente di sviluppo dall'ambiente di esecuzione (è più
+sicuro lanciare un programma dalla riga di comando che dall' IDE; un
+debugger disaccoppiato come pdb è più sicuro di un debugger integrato
+come quello di PythoWin, un editor vero è più sicuro dell'editor dell'
+IDE, etc.)</li>
+<li>disaccoppiare l'interfaccia grafica: il programma deve poter funzionare
+senza di essa, o sostituendo il GUI toolkit con un altro.</li>
+<li>i threads vi accoppiano tutto, se uno va male può bloccare tutti gli
+altri: evitateli se potete.</li>
+<li>l'ereditarietà vi accoppia il parente al figlio (per sapere quello che
+fa il figlio bisogna andare a vedere quello che fanno il padre, il nonno,
+il bisnonno, il trisavolo, etc.). Evitatela se potete.</li>
+<li>la modularità è un modo concreto per applicare il principio del
+disaccoppiamento al codice: funzioni che logicamente vanno insieme,
+vanno messe in un modulo comune, funzioni separate vanno separate.
+Se c'è un problema nel modulo X, questo non deve interferire con
+il modulo Y (almeno in un mondo ideale). La modularità rende anche
+più semplice rimpiazzare un modulo sbagliato o vecchio con uno
+corretto o più recente.</li>
+<li>la non-duplicazione del codice è una conseguenza della modularità:
+avendo raggruppato le funzioni di uso generale in un modulo comune,
+si acquista in concisione, semplicità, leggibilità, debuggabilità,
+si evita di correggere lo stesso errore più volte, e in generale tutto
+diviene più facile da mantenere.</li>
+</ul>
+</div>
+<div class="section" id="principio-del-kiss">
+<h2><a class="toc-backref" href="#id33" name="principio-del-kiss">Principio del KISS</a></h2>
+<p><em>Keep it simple, stupid</em>. In Italiano: <em>non facciamoci del male</em>.</p>
+<p>Se potete fare le cose in maniera semplice, fatele in maniera semplice.</p>
+<p>Chiedetevi sempre se una cosa vi serve veramente oppure no.</p>
+</div>
+<div class="section" id="importanza-di-avere-un-prototipo">
+<h2><a class="toc-backref" href="#id34" name="importanza-di-avere-un-prototipo">Importanza di avere un prototipo</a></h2>
+<p>Non c'è nulla di più sbagliato che partire scrivendosi l'architettura di
+un progetto complesso sulla carta. Si parte sempre scrivendo un prototipo,
+<em>testato sul campo di battaglia</em>, che magari ha l'1% delle funzionalità
+che vi interessano, ma che <em>funziona</em>. A quel punto è possibile decidere
+l'architettura e il prototipo diventerà il core e la parte più testata
+e sicura della vostra applicazione.</p>
+<p>Il prototipo/core deve <em>rimuovere tutto l'inessenziale</em>. Più povero è,
+meglio è.</p>
+</div>
+<div class="section" id="moduli-e-packages">
+<h2><a class="toc-backref" href="#id35" name="moduli-e-packages">Moduli e packages</a></h2>
+<p>Qualunque file Python può essere visto come un modulo. Un package invece,
+è una directory contente un file <tt class="docutils literal"><span class="pre">__init__.py</span></tt> che contiene il codice di
+inizializzazione (<tt class="docutils literal"><span class="pre">__init__.py</span></tt> può benissimo essere vuoto, oppure può
+consistere solo di 'import' dei moduli di quel package).</p>
+<p>Importare un package non importa automaticamente tutti i suoi moduli,
+a meno che questo non sia detto esplicitamente nell' <tt class="docutils literal"><span class="pre">__init__.py</span></tt>.</p>
+<p>I package possono essere nidificati senza limite.</p>
+<p>Le variabili globali di un modulo sono locali a quel modulo, quindi
+non c'è mai il rischio di fare danni (a meno che un modulo non importi
+esplicitamente una variabile corrispondente ad un oggetto mutabile e
+la cambi esplicitamente).</p>
+<p>E' possibile mettere un package nel Python path automaticamente per
+tutti gli utenti listando il nome del package in un file <tt class="docutils literal"><span class="pre">.pth</span></tt> nella
+directory site-packages (vedere la documentazione di distutils).</p>
+</div>
+<div class="section" id="come-si-documenta-una-libreria-python">
+<h2><a class="toc-backref" href="#id36" name="come-si-documenta-una-libreria-python">Come si documenta una libreria Python</a></h2>
+<p>Python è un linguaggio &quot;self-documenting&quot; grazie alle doctrings.
+Usatele. In più guardate come è documentato un progetto Python
+tipico (io suggerisco di guardare a <em>docutils</em>) e copiate le convenzioni
+usate lì. Ci sono dei file standard come il README.txt, l'HISTORY.txt,
+il BUGS.txt, una directory docs, una directory test, un file setup.py,
+etc.</p>
+<p>Tenete presente che grazie a <em>doctest</em> potete inserire dei test automatici
+all'interno della vostra documentazione.</p>
+</div>
+</div>
+<div class="section" id="modulo-6-domande-estemporanee">
+<h1><a class="toc-backref" href="#id37" name="modulo-6-domande-estemporanee">Modulo 6: Domande estemporanee</a></h1>
+<p><em>Risponderò alle domande dell'audience, anche al di fuori dal programma,
+se di interesse generale</em>.</p>
+<div class="section" id="come-funziona-import">
+<h2><a class="toc-backref" href="#id38" name="come-funziona-import">Come funziona 'import'</a></h2>
+<p>Se un modulo è già stato importato e chiamate 'import' una seconda
+volta, il modulo NON viene importato due volte. Questo può essere
+un problema nell'interprete interattivo. Se importate un modulo,
+poi lo modificate e lo importate di nuovo, vi resterà in memoria
+la copia <em>vecchia</em>, quella non modificata. La soluzione è usare
+'reload', che vi importerà veramente la nuova versione.</p>
+</div>
+<div class="section" id="come-funziona-del">
+<h2><a class="toc-backref" href="#id39" name="come-funziona-del">Come funziona '__del__'</a></h2>
+<pre class="doctest-block">
+&gt;&gt;&gt; a = 1
+&gt;&gt;&gt; del a
+</pre>
+<p>vi cancella il nome dal namespace:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; a
+Traceback (most recent call last):
+ File &quot;&lt;stdin&gt;&quot;, line 1, in ?
+NameError: name 'a' is not defined
+</pre>
+<p>Tuttavia l'oggetto cui si riferisce <em>non viene cancellato immediatamente</em>.
+Verrà cancellato dal garbage collector <em>quando serve</em>, ma soltanto
+<em>se non vi sono altre referenze</em> all'oggetto da qualche altra parte.
+Inoltre per oggetti C, dovrete definirvi un metodo <tt class="docutils literal"><span class="pre">__del__</span></tt> custom
+che ha accesso all'oggetto a livello C. Tenete anche conto che tipicamente
+il debugger tiene referenze agli oggetti aggiuntive, quindi in modalità
+di debugger i problemi con oggetti non cancellati peggiorano.</p>
+<p>Ecco un esempio di un metodo <tt class="docutils literal"><span class="pre">__del__</span></tt> custom piuttosto banale:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; class C(object):
+... def __del__(self):
+... print 'Hai usato del'
+...
+&gt;&gt;&gt; c = C()
+&gt;&gt;&gt; del c
+Hai usato del
+</pre>
+<p>Il metodo <tt class="docutils literal"><span class="pre">__del__</span></tt> viene chiamato automaticamente all'uscita
+dall'interprete:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; class C(object):
+... def __del__(self):
+... print 'Hai usato del'
+...
+&gt;&gt;&gt; c = C()
+&gt;&gt;&gt; &lt;CTRL-Z&gt; per uscire dall'interprete
+Hai usato del
+</pre>
+<p>In principio, all'uscita del programma Python
+<em>dovrebbe chiamare ``__del__`` automaticamente anche se vi sono eccezioni</em>:</p>
+<pre class="literal-block">
+#&lt;del_with_exc.py&gt;
+
+class C(object):
+ def __del__(self):
+ print &quot;Hai chiamato del&quot;
+
+c = C()
+raise RuntimeError(&quot;Ahi ahi!&quot;)
+
+#&lt;/del_with_exc.py&gt;
+
+$ python del_with_exc.py
+Traceback (most recent call last):
+ File &quot;del_with_exc.py&quot;, line 6, in ?
+ raise RuntimeError(&quot;Ahi ahi!&quot;)
+RuntimeError: Ahi ahi!
+Hai chiamato del
+</pre>
+<p>Tuttavia per oggetti <tt class="docutils literal"><span class="pre">C</span></tt> ed eccezioni le cose possono essere delicate ed
+è sempre meglio chiamare <tt class="docutils literal"><span class="pre">del</span></tt> <em>esplicitamente</em>, magari in un
+<tt class="docutils literal"><span class="pre">try</span> <span class="pre">..</span> <span class="pre">finally</span></tt>.</p>
+</div>
+<div class="section" id="che-differenza-c-fra-variabili-di-classe-e-di-istanza">
+<h2><a class="toc-backref" href="#id40" name="che-differenza-c-fra-variabili-di-classe-e-di-istanza">Che differenza c'è fra variabili di classe e di istanza</a></h2>
+<p>Questo esempio dovrebbe chiarire la differenza:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; class C(object):
+... pippo = 'sono una variabile di classe'
+... def __init__(self):
+... self.poppi = 'sono una variabile di istanza'
+...
+</pre>
+<p>Le variabili di classe sono le stesse per tutte le istanze:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; c1 = C()
+&gt;&gt;&gt; c2 = C()
+&gt;&gt;&gt; c1.pippo
+'sono una variabile di classe'
+&gt;&gt;&gt; c2.pippo
+'sono una variabile di classe'
+</pre>
+<p>Se cambio una variabile di classe, cambia per tutte le istanze, anche
+per quelle che sono state create <em>prima</em> del cambiamento:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; C.pippo = 'adesso la cambio'
+&gt;&gt;&gt; c1.pippo
+'adesso la cambio'
+&gt;&gt;&gt; c2.pippo
+'adesso la cambio'
+</pre>
+<p>Lo stesso vale per i metodi, che non sono altro che variabili di classe.</p>
+<p>Le variabili di istanza invece sono indipendenti:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; c1.poppi
+'sono una variabile di instanza'
+&gt;&gt;&gt; c2.poppi
+'sono una variabile di instanza'
+&gt;&gt;&gt; c1.poppi = 'cambio la variabile dell'istanza c1'
+&gt;&gt;&gt; c1.poppi
+'cambio la variabile dell'istanza c1'
+&gt;&gt;&gt; c2.poppi # questa rimane quella che era prima
+'sono una variabile di instanza'
+</pre>
+</div>
+<div class="section" id="che-cosa-sono-i-metodi-che-iniziano-con">
+<h2><a class="toc-backref" href="#id41" name="che-cosa-sono-i-metodi-che-iniziano-con">Che cosa sono i metodi che iniziano con &quot;__&quot;</a></h2>
+<p>Sono metodi protetti. Sono utili per evitare rogne con l'ereditarietà.
+Per capire il problema dò un esempio semplice qui di seguito.</p>
+<p>Normalmente l'ereditarietà accoppia il padre con il figlio, nel senso che
+il figlio può sovrascrivere i metodi del padre, e i metodi del padre andranno
+automaticamente a chiamare i metodi del figlio:</p>
+<pre class="literal-block">
+class B(object): # padre
+ def __init__(self):
+ self.hello()
+ def hello(self):
+ print &quot;hello!&quot;
+
+class C(B): # figlio
+ def hello(self):
+ print &quot;cucu!&quot;
+
+b = B() # stampa 'hello!'
+c = C() # stampa 'cucu!'
+</pre>
+<p>In questo esempio l'__init__ del padre chiama l'hello del figlio. Tuttavia,
+a volte uno vuole essere sicuro che l'__init__ del padre chiami l'hello
+del padre, e non quello del figlio (sempre per via del principio del
+disaccoppiamento). Per questo ci sono i <em>metodi protetti</em>:</p>
+<pre class="literal-block">
+class B(object):
+ def __init__(self): # call the '__hello' method in THIS class
+ self.__hello()
+ def __hello(self):
+ print &quot;hello!&quot;
+
+class C(B):
+ def __hello(self): # won't be called by B.__init__
+ print &quot;cucu!&quot;
+
+b = B() # stampa 'hello!'
+c = C() # stampe 'hello!'
+</pre>
+<p>I metodi protetti di tipo <tt class="docutils literal"><span class="pre">__&lt;nome</span> <span class="pre">metodo&gt;</span></tt> non vanno confusi con i metodi
+privati di tipo <tt class="docutils literal"><span class="pre">_&lt;nome</span> <span class="pre">metodo&gt;</span></tt> (un solo underscore):</p>
+<ol class="arabic">
+<li><p class="first">i metodi privati non andrebbero chiamati mai, se non sapendo al 100% quello
+che si sta facendo, e solo in caso di errori nel design della libreria che
+si sta utilizzando;</p>
+</li>
+<li><p class="first">i metodi protetti possono essere chiamati con tranquillità. Proprio
+perchè sono protetti, c'è la garanzia che sovrascrivendoli nella
+sottoclasse non si va ad alterare il comportamento ereditato dal padre
+(nel nostro esempio l'<tt class="docutils literal"><span class="pre">__init__</span></tt> del padre continuerà a chiamare il
+proprio <tt class="docutils literal"><span class="pre">__hello</span></tt>, non l'<tt class="docutils literal"><span class="pre">__hello</span></tt> del figlio). D'altra parte i
+metodi definiti nel figlio vedranno solo l'<tt class="docutils literal"><span class="pre">__hello</span></tt> del figlio e
+non quello del padre.</p>
+</li>
+<li><p class="first">i metodi protetti non possono essere chiamati accidentalmente, perchè
+per esempio <tt class="docutils literal"><span class="pre">c.__hello()</span></tt> non funziona. Tuttavia è possibile chiamarli,
+quindi non sono veramente privati: nel nostro esempio è possibile
+chiamare</p>
+<p><tt class="docutils literal"><span class="pre">c._B__hello</span></tt> (<tt class="docutils literal"><span class="pre">__hello</span></tt> del padre) oppure
+<tt class="docutils literal"><span class="pre">c._C__hello</span></tt> (<tt class="docutils literal"><span class="pre">__hello</span></tt> del figlio)</p>
+<p>Siccome bisogna specificare il nome della classe dove il metodo è definito
+non c'è il rischio di sbagliarsi (a meno di non essere masochisti e di
+non dare lo stesso nome al padre e al figlio).</p>
+</li>
+</ol>
+<p>I metodi protetti vengono usati raramente. Vedere &quot;Python in a Nutshell&quot;
+per maggiori informazioni sul loro uso.</p>
+</div>
+</div>
+<div class="section" id="soluzioni-al-questionario-di-ammissione">
+<h1><a class="toc-backref" href="#id42" name="soluzioni-al-questionario-di-ammissione">Soluzioni al questionario di ammissione</a></h1>
+<div class="section" id="scrivere-un-programma-che-testa-se-una-stringa-rappresenta-un-numero">
+<h2><a class="toc-backref" href="#id43" name="scrivere-un-programma-che-testa-se-una-stringa-rappresenta-un-numero">Scrivere un programma che testa se una stringa rappresenta un numero</a></h2>
+<p>Soluzione standard (vedere anche il tutorial di Python):</p>
+<pre class="literal-block">
+try:
+ int(x)
+except ValueError:
+ print &quot;This is not a number!&quot;
+</pre>
+<p>Soluzione usando tkSimpleDialog:</p>
+<pre class="literal-block">
+from tkSimpleDialog import askfloat
+askfloat(&quot;Enter a number&quot;, &quot;Number:&quot;)
+</pre>
+</div>
+<div class="section" id="scrivere-un-programma-che-lista-tutti-i-files-nella-directory-corrente">
+<h2><a class="toc-backref" href="#id44" name="scrivere-un-programma-che-lista-tutti-i-files-nella-directory-corrente">Scrivere un programma che lista tutti i files nella directory corrente</a></h2>
+<pre class="literal-block">
+for f in os.listdir(&quot;.&quot;):
+ print f
+</pre>
+</div>
+<div class="section" id="listare-tutti-i-files-nelle-sottodirectories-ricorsivamente">
+<h2><a class="toc-backref" href="#id45" name="listare-tutti-i-files-nelle-sottodirectories-ricorsivamente">Listare tutti i files nelle sottodirectories ricorsivamente</a></h2>
+<pre class="literal-block">
+for cwd, dirs, files in os.walk(&quot;.&quot;):
+ for f in files:
+ print f
+</pre>
+</div>
+<div class="section" id="calcolare-lo-spazio-occupato-da-tutti-i-files-di-tipo-txt-in-una-directory">
+<h2><a class="toc-backref" href="#id46" name="calcolare-lo-spazio-occupato-da-tutti-i-files-di-tipo-txt-in-una-directory">Calcolare lo spazio occupato da tutti i files di tipo .txt in una directory</a></h2>
+<p>[Soluzione svolta al corso 1]</p>
+<pre class="literal-block">
+import os
+
+def get_text_files(d):
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ if f.lower().endswith(&quot;.txt&quot;):
+ fullname = os.path.join(cwd, f)
+ size = os.path.getsize(fullname)
+ yield fullname, size
+
+from operator import itemgetter
+print sum(map(itemgetter(1), get_text_files(&quot;.&quot;)))
+</pre>
+</div>
+<div class="section" id="listare-i-files-a-seconda-delle-dimensioni">
+<h2><a class="toc-backref" href="#id47" name="listare-i-files-a-seconda-delle-dimensioni">Listare i files a seconda delle dimensioni</a></h2>
+<pre class="literal-block">
+print sorted(get_text_files(&quot;.&quot;), key=itemgetter(1))
+</pre>
+</div>
+<div class="section" id="scrivere-un-test-per-verificate-che-una-directory-sia-vuota">
+<h2><a class="toc-backref" href="#id48" name="scrivere-un-test-per-verificate-che-una-directory-sia-vuota">Scrivere un test per verificate che una directory sia vuota</a></h2>
+<pre class="literal-block">
+def is_empty(d):
+ if os.listdir(d): return False
+ else: return True
+</pre>
+<p>Sarebbe ridondante scrivere</p>
+<pre class="literal-block">
+if os.listdir(d) != []:
+</pre>
+<p>perchè la lista vuota ha già di per sè un valore booleano &quot;False&quot;.</p>
+</div>
+<div class="section" id="aprire-una-finestrella-contenente-la-scritta-hello-world">
+<h2><a class="toc-backref" href="#id49" name="aprire-una-finestrella-contenente-la-scritta-hello-world">Aprire una finestrella contenente la scritta &quot;hello, world!&quot;</a></h2>
+<p>[In maniera portabile]</p>
+<p>Soluzione più semplice:</p>
+<pre class="literal-block">
+# hellotk.pyw
+from tkMessageBox import showinfo
+showinfo(message=&quot;hello&quot;)
+</pre>
+<p>Soluzione alternativa:</p>
+<pre class="literal-block">
+# hellotk.pyw
+import Tkinter as t
+root = t.Tk()
+l = t.Label(text=&quot;hello&quot;)
+l.pack()
+root.mainloop()
+</pre>
+<p>Guardatevi sull'help di ActiveState la differenza tra l'estensione <tt class="docutils literal"><span class="pre">.py</span></tt>
+e l'estensione <tt class="docutils literal"><span class="pre">.pyw</span></tt> (dovrebbe essere nelle FAQ).</p>
+</div>
+<div class="section" id="scaricare-la-pagina-web-http-www-example-com-da-internet">
+<h2><a class="toc-backref" href="#id50" name="scaricare-la-pagina-web-http-www-example-com-da-internet">Scaricare la pagina Web <a class="reference" href="http://www.example.com">http://www.example.com</a> da Internet</a></h2>
+<pre class="doctest-block">
+&gt;&gt;&gt; from urllib2 import urlopen
+&gt;&gt;&gt; print urlopen('http://www.example.com').read()
+</pre>
+</div>
+<div class="section" id="stampare-a-schermo-una-tavola-delle-moltiplicazioni">
+<h2><a class="toc-backref" href="#id51" name="stampare-a-schermo-una-tavola-delle-moltiplicazioni">Stampare a schermo una tavola delle moltiplicazioni</a></h2>
+<p>Soluzione senza generatori:</p>
+<pre class="literal-block">
+#&lt;maketable.py&gt;
+
+# non graphic
+N = 10
+for i in range(1, N+1):
+ for j in range(1, N+1):
+ print &quot;%4d&quot; % (i*j),
+ print
+
+# HTML
+def maketable(iterable, N):
+ iterable = iter(iterable)
+ print &quot;&lt;table border='1'&gt;&quot;
+ stop = False
+ while not stop:
+ print &quot;&lt;tr&gt;&quot;
+ for j in range(1, N+1):
+ try:
+ print &quot;&lt;td&gt;%s&lt;/td&gt;&quot; % iterable.next(),
+ except StopIteration:
+ print &quot;&lt;td&gt;&lt;/td&gt;&quot;
+ stop = True
+ print &quot;&lt;/tr&gt;&quot;
+ print &quot;&lt;/table&gt;&quot;
+
+import tempfile, webbrowser, os, sys
+
+def showtable(iterable, N):
+ stdout = sys.stdout # shows how to redirect stdout correctly
+ fd, name = tempfile.mkstemp(suffix=&quot;.html&quot;)
+ sys.stdout = os.fdopen(fd, &quot;w&quot;)
+ maketable(iterable, N)
+ webbrowser.open(name)
+ sys.stdout = stdout
+
+showtable((i*j for j in range(1, N+1) for i in range(1, N+1)), N)
+
+#&lt;/maketable.py&gt;
+</pre>
+<p>Soluzione usando i generatori, non HTML:</p>
+<pre class="literal-block">
+#&lt;gentable.py&gt;
+
+def gentable(N):
+ for i in range(1, N+1):
+ for j in range(1, N+1):
+ yield i*j
+
+def printtable(lst, N):
+ for i, el in enumerate(lst):
+ print &quot;%4d&quot; % el,
+ if (i+1) % 10 == 0:
+ print
+
+if __name__ == &quot;__main__&quot;:
+ printtable(gentable(10), 10)
+
+#&lt;/gentable.py&gt;
+</pre>
+</div>
+<div class="section" id="trovare-tutte-le-immagini-jpg-nel-vostro-hard-disk-e-mostrarle-a-schermo-in-formato-ridotto">
+<h2><a class="toc-backref" href="#id52" name="trovare-tutte-le-immagini-jpg-nel-vostro-hard-disk-e-mostrarle-a-schermo-in-formato-ridotto">Trovare tutte le immagini .jpg nel vostro hard disk e mostrarle a schermo in formato ridotto</a></h2>
+<p>Soluzione svolta al corso 1:</p>
+<pre class="literal-block">
+import os, webbrowser
+
+def gentableHTML(iterable, N):
+ iterator = iter(iterable)
+ yield &quot;&lt;HTML&gt;&quot;
+ yield &quot;&lt;BODY&gt;&quot;
+ yield &quot;&lt;TABLE border='1'&gt;&quot;
+ for i in range(N):
+ yield &quot;&lt;TR&gt;&quot;
+ for j in range(N):
+ yield '&lt;TD&gt;&lt;img src=&quot;%s&quot; width=&quot;50&quot;, height=&quot;50&quot;&gt;&lt;/TD&gt;\n' % \
+ iterator.next()
+ yield &quot;&lt;/TR&gt;\n&quot;
+ yield &quot;&lt;/TABLE&gt;&quot;
+ yield &quot;&lt;/BODY&gt;&quot;
+ yield &quot;&lt;/HTML&gt;&quot;
+
+# generatore di file names
+def get_files_with_ext(ext_set, d):
+ &quot;&quot;&quot;
+ ext_set is a set of valid extensions.
+ &quot;&quot;&quot;
+ assert isinstance(ext_set, set), &quot;%r is not a set!&quot; % ext_set
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ fullname = os.path.join(cwd, f)
+ if ext.lower() in ext_set and os.path.getsize(fullname):
+ yield fullname
+
+if __name__ == &quot;__main__&quot;:
+ # genera il file e lo mostra
+ images = file(&quot;images.html&quot;, &quot;w&quot;)
+ for el in gentableHTML(get_files_with_ext(set([&quot;.png&quot;]),
+ &quot;C:\\Documents and Settings&quot;), 15):
+ print &gt;&gt; images, el,
+ images.close()
+ webbrowser.open(&quot;images.html&quot;)
+</pre>
+<p>Soluzione più sofisticata, per darvi qualcosa su cui pensare:</p>
+<pre class="literal-block">
+#&lt;maketable.py&gt;
+
+def get_files_with_ext(ext, d):
+ &quot;&quot;&quot;
+ ext can be a string or a set of strings; for instance
+ get_files_with_ext(&quot;.png&quot;) or get_files_with_ext(set(&quot;.png&quot;, &quot;.gif&quot;))
+ &quot;&quot;&quot;
+ if not isinstance(ext, set):
+ ext_set = set([ext])
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ if ext.lower() in ext_set:
+ yield os.path.join(cwd, f)
+
+class Picture(object):
+ &quot;&quot;&quot;An example of the utility of __str__&quot;&quot;&quot;
+ def __init__(self, pathname):
+ self.pathname = pathname
+ self.name = os.path.basename(pathname)
+ def __str__(self):
+ return &quot;&lt;img src=%r width=100&gt;&quot; % self.pathname
+
+if sys.platform == 'win32':
+ drive = &quot;C:\\&quot;
+else:
+ drive = &quot;/&quot;
+showtable(map(Picture, get_files_with_ext(&quot;.jpg&quot;, drive)), N)
+
+#&lt;/maketable.py&gt;
+</pre>
+</div>
+</div>
+</div>
+</body>
+</html>
+
diff --git a/pypers/marelli/materiale/corso.txt b/pypers/marelli/materiale/corso.txt
new file mode 100755
index 0000000..e8c07dd
--- /dev/null
+++ b/pypers/marelli/materiale/corso.txt
@@ -0,0 +1,1851 @@
+Corso Python Magneti Marelli
+===================================
+
+:Tenuto: 19-23 Settembre 2005
+
+:Autore: Michele Simionato
+
+:E-mail: michele.simionato@gmail.com
+
+*Queste dispense sono un compendio informale e molto sintetico di quanto
+svolto durante il corso. Esse non si pongono in nessun modo come un testo
+sistematico di programmazione in Python. Il loro scopo principale è quello
+di tenere traccia, per quanto possibile, di quanto si è detto. Lo
+scopo secondario è quello di invogliare i partecipanti e tutti
+gli eventuali lettori ad affrontare gli argomenti qui trattati per forza
+di cose in maniera abbozzata, in maniera più sistematica andando a
+consultare le fonti più adatte alla bisogna, siano essi libri di testo,
+la documentazione ufficiale, newsgroups, siti Web dedicati e, in ultima
+instanza, il codice sorgente stesso, l'unico riferimento definitivo.*
+
+.. contents::
+
+I messaggi fondamentali del corso
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Studiare paga*
+---------------
+
+Grazie alla sua macchina del tempo, Guido ha risolto i problemi
+che vi stanno affliggendo ora dieci anni fa, e sono già nel linguaggio
+e nella libreria standard. Per esempìo avete scoperto di avere a
+disposizione:
+
+- le stringhe di documentazione per darvi la documentazione automatica
+ del codice tramite strumenti quali pydoc ed altri;
+- il try ... finally per garantirvi un "gracefull exit" del vostro
+ programma, anche in presenza di eccezioni inaspettate;
+- i metodi setUp e tearDown di unittest.TestCase, che vi permettono
+ di inizializzare e di pulire propriamente l'ambiente per ogni test;
+- sia unittest che doctest vi permetto di gestire le eccezioni (nel
+ senso di gestire le eccezioni "buone", quelle che vi aspettate);
+- call e Popen in subprocess per aprire processi, kill per ucciderli
+ (usando win32api.TerminateProcess);
+- twisted vi gestisce la comunicazione tra processi e tutte le eccezioni
+ senza problemi
+
+Una settimana di studio oggi può risparmiarvi mesi di frustrazioni
+domani. Sfruttare le risorse disponibili, quali tutorial, howto,
+libri, documentazione, siti Web (come il Python cookbook) e soprattutto
+i newsgroups. Ma prima di postare su di un newsgroup leggetevi "How to
+ask smart questions" e ricordatevi sempre che "Google is you friend".
+
+*Disaccoppiamento* e *KISS*
+----------------------------
+
+Se potere, scomponete l'applicazione in componenti separati e testateli
+separatamente. Scegliete architetture che vi permettono di disaccoppiare
+i problemi. Se potere fare le cose semplici, fatele semplici.
+Abbiate un core minimale che faccia poco, ma che siate sicuri che
+funzioni. Non complicatevi la vita.
+
+*Non nascondete gli errori sotto il tappeto*
+--------------------------------------------
+
+Non trappate l'inaspettato, è una ricetta sicura per avere rogne.
+Usate lo *sviluppo incrementale*, cioè verificate il funzionamento del
+programma SUBITO, e fissate l'errore SUBITO. Non debuggate mai
+a posteriori, se potete evitarlo, ma scrivete codice testato fin da subito.
+Abbiate una bella suite di test automatici di installazione, per accorgervi
+da subito se c'è un problema quando installate il software su di un'altra
+macchina.
+
+
+Modulo 1: Strumenti di introspezione, sviluppo e debugging
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*In questo modulo discuterò gli strumenti da me utilizzati per sviluppare
+in Python sotto Windows. Parlerò di Cygwin come ambiente di lavoro,
+di Python e di IPython come interpreti interattivi, di Idle e di PythonWin
+come IDE, di pydoc e minidoc come tools di introspezione. Inoltre discuterò
+alcune utili librerie e frameworks per Python (Numeric, matplotlib, gnuplot,
+etc.).*
+
+Strumenti di introspezione e come ottenere aiuto
+-------------------------------------------------
+
++ **Help in linea:**
+ Ottimo
+
++ **Pydoc:**
+ Standard, può essere usato dalla riga di comando.
+ ``pydoc -g`` oppure ``python -mpydoc -g``
+ vi dà la versione grafica, con funzionalità di search.
+
++ **Help di ActiveState:**
+ Eccezionale, contiene anche libri di testo, FAQs e how-tos.
+
++ **Google:**
+ Di tutto, di più.
+
++ **Newsgroups:**
+ Risolvono i vostri problemi per voi, e gratis.
+
+Ambienti di sviluppo
+--------------------
+
++ **Cygwin:**
+ Emulatore Unix sotto Windows. Vi permette di lavorare dalla riga di
+ comando comodamente. Evitate di perdere tempo a cliccare a destra e
+ a manca e avete una stabilità maggiore di quella di un ambiente
+ grafico.
+
++ **Idle:**
+ Ambiente di sviluppo per Python che viene con la distribuzione standard.
+ Un pò povero, con qualche difetto, ma semplice e portabile ovunque.
+
++ **PythonWin:**
+ Ambiente di sviluppo per Python che viene con la distribuzione ActiveState
+ per Windows. Più sofisticato di Idle e più integrato con Windows. Ha dei
+ pro e dei contro.
+
++ **WingIDE, Eric/Qt Designer, Komodo, Boa Constructor:**
+ Ambienti di sviluppo di cui esiste una versione commerciale. In generale
+ hanno un look più professionale e sono utili se uno deve dare interfacce
+ grafiche. WingIDE ha il debugger migliore, a quanto ho sentito.
+
++ **Emacs o Vi:**
+ Un Real Programmer (TM) vi dirà che al mondo esistono due soli editor:
+ Emacs e Vi. Tutto il resto è spazzatura. Emacs e Vi girano bene sotto
+ Windows, ma funzionano al meglio sotto Unix.
+
+Strumenti di debugging
+------------------------------------------------
+
+- **print:** è la soluzione usata dai migliori programmatori Python;
+- **pdb:** sembra il debugger dei poveri, ma è standard e funziona;
+- **mille altri debuggers**, compreso un nuovissimo winpdb dall'autore
+ del pdb, da valutare;
+- **programmazione test-driven:** con questa metodologia la stragrande
+ maggioranza dei bugs vengono individuati subito, non appena il
+ codice viene scritto, e vi troverete ad usare il debuggere dieci
+ volte di meno di quanto fate ora.
+
+Strumenti utili per l'utenza scientifica/ingegneristica
+------------------------------------------------------------------
+
+- **Numeric e/o Numarray:**
+ Tutto quello che serve per far conti con le matrici. Numarray è il
+ successore di Numeric, con compatibilità al 99%.
+
+- **matplotlib:**
+ Il meglio per plottare grafici 2D. Richiede Numeric/Numarray.
+
+- **ipython:**
+ Il miglior interprete interattivo per Python. Eccezionali capacità
+ di introspezione e di debugging (è integrato con il Python debugger
+ pdb della libreria standard).
+
+Modulo 2: Programmazione di base in Python
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*In questo modulo si ripasseranno molto brevemente le basi di Python e
+si discuteranno le soluzioni al questionario di ammissione. Lo scopo
+più che altro è quello di conoscersi e di chiarire il livello medio
+dei partecipanti e coprire eventuali buchi nella preparazione di base.*
+
+Le soluzioni agli esercizi sono riportate nell'ultimo capitolo. Durante le
+correzioni mi sono accordi di vari buchi nella programmazione
+di base in Python che si è cercato di riempire.
+
+Encoding
+----------------------------------
+
+[Illustrato al corso 1] In versioni recenti di Python (dalla 2.3)
+se il vostro script contiene dei caratteri accentati (anche nei commenti)
+ottenete un warning tipo questo::
+
+ sys:1: DeprecationWarning: Non-ASCII character '\xe0' in file x.py
+ on line 1, but no encoding declared; see
+ http://www.python.org/peps/pep-0263.html for details
+
+La soluzione e' aggiungere in testa al vostro programma una dichiarazione
+tipo questa::
+
+ #-*- encoding: latin-1 -*-
+
+(usate latin-15 se il vostro programma contiene il simbolo dell'Euro).
+
+
+Pathnames
+-----------------------------
+
+Sfortunatamente Windows usa la backslash come separatore dei pathnames;
+la backslash e' anche il carattere di escaping, quindi ci sono
+problemi:
+
+>>> print 'documenti\nonna' # \n interpretato come newline
+documenti
+onna
+
+La soluzione e' usare raw strings:
+
+>>> print r'documenti\nonna'
+documenti\nonna
+
+Alternativamente, in versioni recenti di Windows, avreste potuto usare
+anche "/" come separatore:
+
+>>> import os
+>>> os.path.exists(r'C:\Python24\python.exe')
+True
+>>> os.path.exists(r'C:/Python24/python.exe')
+True
+
+Insiemi
+-----------------------------------------
+
+In Python 2.3 gli insiemi sono stati aggiunti come un nuovo tipo di dati
+nel modulo sets (by Alex Martelli); in Python 2.4 gli insiemi sono diventati
+un tipo builtin.
+
+>>> s = set('pippo')
+>>> s
+set(['i', 'p', 'o'])
+>>> 'i' in s
+True
+>>> 'p' in s
+True
+>>> 'o' in s
+True
+>>> 'z' in s
+False
+
+E' possibile calcolare l'unione e l'intersezione di insiemi:
+
+>>> t = set('aglio')
+>>> s | t
+set(['a', 'g', 'i', 'l', 'o', 'p'])
+>>> s & t
+set(['i', 'o'])
+
+Il modo compatibile con il passato per usare i sets nello stesso modo nella
+2.3 e nella 2.4 è il seguente::
+
+ try:
+ set:
+ except NameError:
+ from sets import Set as set
+
+Guardare la documentazione standard per saperne di più.
+
+Differenza tra mutabili e immutabili
+---------------------------------------
+
+Questa è una causa comune di confusione in Python:
+
+>>> a = 1 # i numeri sono immutabili
+>>> b = a
+>>> a += 1
+>>> a
+2
+>>> b
+1
+
+>>> a = [1] # le liste sono mutabili
+>>> b = a
+>>> a += [1]
+>>> a
+[1, 1]
+>>> b
+[1, 1]
+
+getattr e setattr
+-------------------------------------------
+
+[Svolto al corso 1] ``getattr`` e ``setattr`` servono per richiamare e
+settare metodi il cui nome viene determinato dinamicamente::
+
+ #<getattr_ex.py>
+
+ class C(object):
+ def m1(self):
+ print "chiamato m1"
+ def m2(self):
+ print "chiamato m2"
+
+ if __name__ == "__main__":
+ c = C()
+ method = raw_input("Che metodo devo chiamare? [m1 o m2] ")
+ getattr(c, method)()
+
+ #</getattr_ex.py>
+
+*Non usate exec quando getattr basterebbe!*
+
+>>> method = 'm1'
+>>> exec 'c.%s()' % method # funziona ma è brutto
+chiamato m1
+>>> getattr(c, method)() # il modo giusto
+chiamato m1
+
+Per ``setattr`` vedere la documentazione.
+
+Gestione dei processi
+-----------------------
+
+Come far partire un processo in parallelo::
+
+ import subprocess
+
+ PLAYER ="mplay32"
+
+ def play_song(song):
+ subprocess.Popen([PLAYER, "/play", "/close", song]) # NON BLOCCA!
+ print "Partito"
+
+
+ if __name__ == "__main__":
+ play_song("c:/Documents and Settings/micheles/Desktop/Music/1. "
+ "Theme from Harry's Game.mp3")
+
+
+``subprocess.call`` fa partire il processo e blocca il programma fintanto
+che il processo non è terminato. Ho anche fatto vedere cosa succede
+se uno dei processi solleva qualche eccezione inaspettata ma viene chiuso
+correttamente grazie al try .. finally::
+
+ #<main.py>
+
+ "Chiama due processi proc1a.py e proc1b.py"
+
+ import subprocess
+
+ CMD_a = ["python", "-c", "import proc1a; proc1a.main()"]
+ CMD_b = ["python", "-c", "import proc1b; proc1b.main()"]
+
+ if __name__ == "__main__":
+ p_a = subprocess.Popen(CMD_a)
+ p_b = subprocess.Popen(CMD_b)
+
+ #</main.py>
+
+Processo 1a::
+
+ #<proc1a.py>
+
+ import time
+
+ def main():
+ for i in range(10):
+ print "hello"
+ time.sleep(1)
+
+ if __name__ == "__main__":
+ main()
+
+ #</proc1a.py>
+
+Processo 1b::
+
+ #<proc1b.py>
+
+ #-*- encoding: latin-1 -*-
+ import time, sys
+
+ def main():
+ try:
+ f = file("proc1b.py")
+ for i in range(10):
+ print "world"
+ if i == 5:
+ raise RuntimeError("Ahia!")
+ time.sleep(1)
+ finally:
+ f.close()
+ print "Il file è stato chiuso correttamente."
+
+ if __name__ == "__main__":
+ main()
+
+ #</proc1b.py>
+
+Ho anche illustrato brevemente come si possono gestire i processi da
+Twisted::
+
+ #<proc2a.py>
+
+ "Un processo che genera numeri casuali e li salva nel file data.txt"
+
+ import random
+
+ def main():
+ ro = random.Random()
+ out = file("data.txt", "w")
+ for number in ro.sample(range(1000), 100):
+ print >> out, number
+ out.close()
+ print "Dati salvati sul file 'data.txt'"
+
+ if __name__ == "__main__":
+ main()
+
+ #</proc2a.py>
+
+ #<proc2b.py>
+
+ "Un processo che genera l'istogramma histo.png dai dati in data.txt"
+
+ from pylab import hist, savefig
+
+ def main():
+ hist([int(n) for n in file("dat.txt")], 10)
+ savefig("histo.png")
+ print "Istogramma salvato sul file 'histo.png'"
+
+ if __name__ == "__main__":
+ main()
+
+ #</proc2b.py>
+
+ #<twisted_main.py>
+
+ "Il main che chiama proc2a.py e proc2b.py nell'ordine e gestisce gli errori"
+
+ import webbrowser, sys
+ if sys.platform == "win32":
+ from twisted.internet import win32eventreactor
+ win32eventreactor.install()
+
+ from twisted.internet.utils import getProcessOutput
+ from twisted.internet import reactor
+
+ def scrivi_messaggio(err):
+ print err.getErrorMessage()
+ reactor.stop()
+ import pdb; pdb.set_trace() # fa partire il debugger in caso di errore
+
+ def visualizza_histo(out_di_genera_histo):
+ print out_di_genera_histo
+ webbrowser.open("histo.png")
+
+ def genera_histo(out_di_genera_dati):
+ print out_di_genera_dati
+ getProcessOutput(sys.executable, (r"c:\corso\processi\proc2b.py",)) \
+ .addCallback(visualizza_histo) \
+ .addErrback(scrivi_messaggio)
+
+ def genera_dati():
+ getProcessOutput(sys.executable, (r"c:\corso\processi\proc2a.py",)) \
+ .addCallback(genera_histo) \
+ .addErrback(scrivi_messaggio)
+
+ if __name__ == "__main__":
+ reactor.callLater(0, genera_dati) # call "genera_dati" after 0 seconds
+ reactor.run()
+
+ #</twisted_main.py>
+
+In questo esempio ho usato ``sys.executable``, che contiene il nome
+completo dell'eseguibile Python (per esempio ``C:\Python24\python.exe``)
+con cui il programma principale è stato lanciato. Questo assicura che
+i processi secondari vengano lanciati con quella versione di Python
+(utile se avete installato contemporaneamente piu' versioni di Python
+e ci possono essere dei dubbi, oppure se il path non e' settato
+correttamente e l'eseguibile Python non viene trovato).
+
+A volte, nonostante tutta la buona volontà, i processi vanno fuori
+controllo. E' possibile ammazzarli brutalmente, con una funzione
+``kill`` come la seguente::
+
+ import os
+
+ try: # we are on Windows
+ import win32api
+ def kill(pid, *unix_compatibility_dummy_args):
+ handle = win32api.OpenProcess(1, False, pid) # open handle to kill
+ win32api.TerminateProcess(handle, -1)
+ win32api.CloseHandle(handle)
+ os.kill = kill # fix os
+ except ImportError: # we are on Unix
+ pass
+
+In questo modo di fare, il modulo 'os' della libreria standard viene
+fissato automaticamente, aggiungendogli una funzione 'kill' che è
+mancante nell'ambiente Windows ma che può facilmente essere implementata
+usando le win32api (che non vengono con la distribuzione standard ma sono
+incluse con la distribuzione dell'ActiveState).
+
+Naturalmente cambiare moduli della libreria standard al volo NON È
+CONSIGLIATO, ma è sempre meglio che modificare a mano il codice
+sorgente e mantenere una propria versione modificata.
+
+Iteratori e generatori
+----------------------------
+
+Un iterabile è un qualunque oggetto su cui si può iterare con un
+ciclo "for"; un iteratore è un oggetto con un metodo .next().
+Il modo più comune per definire iteratori è tramite un generatore,
+cioè una "funzione" con uno "yield":
+
+>>> def gen123():
+... yield 1
+... yield 2
+... yield 3
+...
+>>> it = gen123()
+>>> it.next()
+1
+>>> it.next()
+2
+>>> it.next()
+3
+>>> it.next()
+Traceback (most recent call last):
+ File '<stdin>', line 1, in ?
+StopIteration
+
+Un ciclo "for" internamente converte l'iterabile in un iteratore,
+chiama il metodo ".next()" successivamente e trappa l'eccezione StopIteration,
+uscendo dal loop quando non c'è più nulla su cui iterare:
+
+>>> it = gen123()
+>>> for i in it: print i
+...
+1
+2
+3
+
+Modulo 3. Tipici errori di programmazione e gestione delle eccezioni
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Si discuteranno buoni e cattivi esempi di programmazione presi da software
+reale scritto alla Magneti Marelli. Si discuteranno alcune tecniche
+per interpretare i tracebacks di Python e per identificare l'origine dei
+problemi.*
+
+L'errore più tipico con le eccezioni
+--------------------------------------
+
+Bisogna assolutamente evitare codice come il seguente::
+
+ try:
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ bla-bla
+ except:
+ bla-bla
+
+Nel blocco ``try`` dev'esserci la cosa più semplice possibile, per
+limitare i tipi di eccezione che possono nascere. Inoltre l'except nudo
+e' orribile perchè trappa qualunque cosa, anche quello che non vorreste.
+La cosa giusta da fare è del tipo::
+
+ try:
+ bla-bla
+ except MyException, e: # sempre specificare l'eccezione aspettata
+ print e
+ except OtherException,e:
+ print e
+ ...
+
+Non trappate l'inaspettato, altrimenti non capirete mai qual è stata
+l'origine di un problema.
+
+Il try .. finally è una grande idea
+----------------------------------------------------------------
+
+Molto spesso quello che volete non è tanto il try .. except, quanto il
+try .. finally: il vantaggio del try .. finally è che
+*non vi nasconde l'eccezione* e nello stesso tempo vi *garantisce che quello
+che deve essere chiuso correttamente venga chiuso correttamente* in ogni caso.
+C'è un eccezione a questa regola: se ammazzate un processo di brutto con un
+kill, il try .. finally non può salvarvi. Il try .. finally vi
+salva per tutte le eccezioni Python, compreso il CTRL-C (KeyboardInterrupt)
+e il sys.exit() (SystemExit).
+
+>>> try:
+... raise RuntimeError("Ahia")
+... finally:
+... print "Io vengo eseguito SEMPRE, anche se c'è un'eccezione!"
+...
+Io vengo eseguito SEMPRE, anche se c'e' un'eccezione!
+Traceback (most recent call last):
+ File '<stdin>', line 2, in ?
+RuntimeError: Ahia
+
+Uso di assert
+--------------
+
+Per asserire che una condizione è verificata con certezza:
+
+>>> def div2(x):
+... assert isinstance(x, int), '%s non è un numero intero' % x
+... return x/2
+...
+>>> div2(14)
+7
+>>> div2(14.0)
+Traceback (most recent call last):
+ File '<stdin>', line 1, in ?
+ File '<stdin>', line 2, in div2
+AssertionError: 14.0 non è un numero intero
+
+Tipicamente si usa in "sanity checks", per essere sicuri che un parametro
+sia esattamente quello che ci si aspetta, in casi di eccezioni gravi; se
+l'assert non è rispettato, tutto il programma deve bloccarsi.
+
+Non usate exec
+----------------------------
+
+'exec' è un costrutto pericolosissimo che va riservato solo a chi sa
+cosa sta facendo. Spesso e volentieri si usa soltanto per ignoranza
+dell'esistenza di una soluzione migliore.
+
+Esempio::
+
+ exec file("myscript.py").read()
+
+è UN ERRORE GRAVE per vari motivi.
+
+In primo luogo, in caso di eccezioni sollevate in 'myscript.py'
+perdete informazione su dove si trova l'errore (cioè nel file "myscript.py")
+e rendete impossibile la vita al debugger; in secondo luogo, sporcate il
+namespace del vostro programma in maniera potenzialmente pericolosa. La cosa
+giusta da fare è::
+
+ dic = {}
+ execfile("myscript.py", dic)
+
+che non perde informazioni e non sporca il namespace, perchè i nomi
+definiti in myscript.py verranno confinati nel dizionario. Leggetevi
+la documentazione di 'execfilè per saperne di più.
+
+Come far partire pdb automaticamente in caso di eccezioni inaspettate
+-----------------------------------------------------------------------
+
+[Illustrato al corso 1]
+
+::
+
+ #<exc_debug.py>
+
+ # recipe in the Python cookbook first edition, chapter 14.5
+
+ import sys
+
+ def info(type, value, tb):
+ if hasattr(sys, 'ps1') or not sys.stderr.isatty() or \
+ type == SyntaxError:
+ # we are in interactive mode or we don't have a tty-like
+ # device, so we call the default hook
+ sys.__excepthook__(type, value, tb)
+ else:
+ import traceback, pdb
+ # we are NOT in interactive mode, print the exception...
+ traceback.print_exception(type, value, tb)
+ print
+ # ...then start the debugger in post-mortem mode.
+ pdb.pm()
+
+ sys.excepthook = info
+
+ #</exc_debug.py>
+
+Se un programma importa ``exc_debug``, il Python debugger partirà
+automaticamente in caso di eccezioni non trappate. Per esempio eseguire
+
+::
+
+ #<example.py>
+ import exc_debug
+ a = 1
+ b = 0
+ a/b
+ #</example.py>
+
+fa partire il debugger::
+
+ $ python example.py
+ Traceback (most recent call last):
+ File "example.py", line 4, in ?
+ a/b
+ ZeroDivisionError: integer division or modulo by zero
+
+ > /mnt/hda2/cygwin/home/micheles/md/pypers/marelli/materiale/example.py(4)?()
+ -> a/b
+ (Pdb) print a
+ 1
+ (Pdb) print b
+ 0
+ Pdb) !b = 1 # cambia il valore di b
+ (Pdb) print a/b
+ 1
+
+Date ``help pdb`` dall'interno del debugger per avere informazioni sul suo
+funzionamento.
+
+Eccezioni e threads
+-------------------------
+
+Un'eccezione non trappata blocca soltanto il thread in cui si è verificata,
+NON tutto il programma::
+
+ #<esempio1.py>
+
+ import threading, time, sys
+
+ def print_hello():
+ for i in range(10):
+ print "hello"
+ if i == 5:
+ raise RuntimeError("Problema a runtime")
+ time.sleep(1)
+
+ def print_world():
+ for i in range(10):
+ print "world"
+ time.sleep(1)
+
+ threading.Thread(target=print_hello).start()
+ threading.Thread(target=print_world).start()
+
+ #</esempio1.py>
+
+dà come output::
+
+ $ python esempio1.py
+ hello
+ world
+ hello
+ world
+ hello
+ world
+ hello
+ world
+ hello
+ world
+ hello
+ world
+ Exception in thread Thread-1:
+ Traceback (most recent call last):
+ File "/usr/lib/python2.4/threading.py", line 442, in __bootstrap
+ self.run()
+ File "/usr/lib/python2.4/threading.py", line 422, in run
+ self.__target(*self.__args, **self.__kwargs)
+ File "esempio1.py", line 7, in print_hello
+ raise RuntimeError("Problema a runtime")
+ RuntimeError: Problema a runtime
+
+ world
+ world
+ world
+ world
+
+Quindi uno è costretto a implementare un meccanismo di controllo, tipo
+il seguente::
+
+ import threading, time, sys
+
+ END = False
+
+ def print_hello():
+ global END
+ i = 0
+ while not END:
+ i += 1
+ print "hello"
+ if i == 5:
+ try:
+ raise RuntimeError("Problema a runtime")
+ except RuntimeError, e:
+ END = True
+ time.sleep(1)
+
+ def print_world():
+ i = 0
+ while not END:
+ print "world"
+ time.sleep(1)
+
+ threading.Thread(target=print_hello).start()
+ threading.Thread(target=print_world).start()
+
+Questa è una soluzione artigianale, che usa una variabile globale, sfruttando
+il fatto che le variabili globali sono condivise fra tutti i thread (questo
+può anche causare danni, se non si sta attenti).
+
+La strada consigliata per comunicare fra threads è quella di usare una coda
+[esempio svolto al corso 1]::
+
+ "Esempio di due threads comunicanti tramite una queue."
+
+ import time, threading, Tkinter, Queue
+
+ queue = Queue.Queue()
+
+ def print_hello():
+ for i in range(10):
+ try:
+ messaggio = queue.get_nowait()
+ except Queue.Empty:
+ pass
+ else:
+ if messaggio == "terminate": break
+ print "%s, hello" % i
+ time.sleep(1)
+
+ def print_world():
+ for i in range(10):
+ print "%s, world" % i
+ if i == 5:
+ queue.put("terminate") # manda il messaggio di terminazione
+ root.quit()
+ raise RuntimeError("Errore nel thread print_world!")
+ time.sleep(1)
+
+ root = Tkinter.Tk()
+
+ for func in print_hello, print_world:
+ th = threading.Thread(target=func)
+ th.start()
+
+ root.mainloop()
+
+Questo esempio fa anche vedere che chiudere la finestrella grafica NON
+uccide i threads che stanno girando.
+
+I meccanismi di controllo per bloccare i thread sono notoriamente fragili
+e piccoli errori possono farvi grossi danni.
+
+Debuggare i threads è notoriamente un macello.
+
+L'unica soluzione vera è evitare i threads quando è possibile.
+
+Modulo 4. Sviluppo orientato ai test
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Come scrivere software con tecnologie agili, con lo scopo di ridurre e
+tenere sotto controllo i bugs. Discussione di doctest, py.test e unittest.
+Esempi di programmazione test driven.*
+
+Consigli di carattere generale
+-------------------------------
+
+- testate SUBITO, non debuggate dopo (ad ogni una riga di codice che si
+ scrive, si testa che funzioni e che non distrugga quello che funzionava
+ prima).
+
+- scrivete software in maniera che sia testabile (per esempio create
+ sempre anche una versione non-grafica di un programma grafico, perchè
+ la versione testuale si testa **molto** più facilmente).
+
+- non abbiate paura a scrivervi un vostro ambiente di test personalizzato.
+
+- tenete conto che unittest e doctest esistono e possono aiutarvi infinitamente
+ nel gestire i vostri test.
+
+Usare unittest
+------------------------------------------------------
+
+Tipicamente con unittest si divide la libreria da testare::
+
+ #<isnumber.py>
+
+ def is_number(arg):
+ "Verifica se la stringa arg è un numero valido"
+ try:
+ float(arg)
+ except ValueError:
+ return False
+ else:
+ return True
+
+ #</isnumber.py>
+
+dal file di test, che convenzionalmente ha un nome che inizia per "test"::
+
+ #<test_isnumber.py>
+
+ import unittest
+
+ from isnumber import is_number
+
+ class TestIsNumber(unittest.TestCase):
+
+ def setUp(self):
+ print "sto inizializzando"
+
+ # test positivi
+ def test_1(self):
+ "Testa che '1' è un numero buono."
+ self.assertTrue(is_number("1"))
+ def test_2(self):
+ "Testa che '1.3' è un numero buono."
+ self.assertTrue(is_number("1.3"))
+ def test_3(self):
+ "Testa che '+1.3' è un numero buono."
+ self.assertTrue(is_number("+1.3"))
+ def test_4(self):
+ "Testa che '-1.3' è un numero buono."
+ self.assertTrue(is_number("-1.3"))
+
+ # test negativi
+ def test_5(self):
+ "Testa che '1-.3' non è un numero buono."
+ self.assertFalse(is_number("1-.3"))
+ def test_6(self):
+ "Testa che 'à non è un numero buono."
+ self.assertFalse(is_number("a"))
+ def test_7(self):
+ "Testa che '42' è un numero buono."
+ self.assertTrue(is_number("42"))
+
+ def tearDown(self):
+ print "Sto chiudendo quello che c'è da chiudere"
+
+ if __name__ == "__main__":
+ unittest.main()
+
+ #</test_isnumber.py>
+
+Eseguire i tests con l'opzione verbose da::
+
+ $ python test_isnumber.py -v
+ Testa che '1' è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+ Testa che '1.3' è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+ Testa che '+1.3' è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+ Testa che '-1.3' è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+ Testa che '1-.3' non è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+ Testa che 'à non è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+ Testa che '42' è un numero buono. ... sto inizializzando
+ Sto chiudendo quello che c'è da chiudere
+ ok
+
+ ----------------------------------------------------------------------
+ Ran 7 tests in 0.001s
+
+ OK
+
+Questo mostra che i metodi ``setUp`` e ``tearDown`` vengono chiamati
+*per ogni test*, quindi tutti i test si svolgono in un ambiente pulito.
+
+E' normale avere un file di test più lungo della libreria da testare.
+
+E' possibile specificare le eccezioni aspettate::
+
+ #<test_exc.py>
+
+ import unittest
+
+ def divide(a, b):
+ return a/b
+
+ class TestIsNumber(unittest.TestCase):
+ def test_1(self):
+ "Divide 4/2"
+ self.assertEqual(divide(4,2), 2)
+ def test_2(self):
+ "Divide 4/0"
+ self.assertRaises(ZeroDivisionError, divide, 4, 0)
+
+
+ if __name__ == "__main__":
+ unittest.main()
+
+ #</test_exc.py>
+
+ $ python test_exc.py -v
+ Divide 4/2 ... ok
+ Divide 4/0 ... ok
+
+ ----------------------------------------------------------------------
+ Ran 2 tests in 0.001s
+
+ OK
+
+Usare doctest
+-----------------------------------
+
+L'uso più semplice, eseguire i doctest che si trovano nelle stringhe
+di documentazione di un modulo::
+
+ #<esempio_banale.py>
+
+ def sum12():
+ """Questa funzione ritorna la somma di 1 + 2::
+ >>> sum12()
+ 3"""
+ return 1+2
+
+ if __name__ == "__main__":
+ import doctest; doctest.testmod()
+
+ #</esempio_banale.py>
+
+Ecco come eseguire i tests con l'opzione verbose::
+
+ $ python esempio_banale.py -v
+ Trying:
+ sum12()
+ Expecting:
+ 3
+ ok
+ 1 items had no tests:
+ __main__
+ 1 items passed all tests:
+ 1 tests in __main__.sum12
+ 1 tests in 2 items.
+ 1 passed and 0 failed.
+ Test passed.
+
+Eseguire i doctest che si trovano in un file di testo separato (nuova
+funzionalità di Python 2.4)::
+
+ #<doctest_runner.py>
+
+ import doctest
+
+ if __name__== "__main__":
+ doctest.testfile("test_isnumber.txt")
+
+ #</doctest_runner.py>
+
+
+Contenuto di 'test_isnumber.txt'::
+
+ Questa è la documentazione della funzione isnumber
+ ====================================================
+
+ Esempi di uso:
+
+ >>> from isnumber import is_number
+ >>> is_number("1")
+ True
+ >>> is_number("1.3")
+ True
+ >>> is_number("+1.3")
+ True
+ >>> is_number("-1.3")
+ True
+ >>> is_number("1-.3")
+ False
+ >>> is_number("a")
+ False
+ >>> is_number("42")
+ True
+ >>> 1/0
+ Traceback (most recent call last):
+ kkkkdjjfkf
+ ZeroDivisionError: integer division or modulo by zero
+
+Eseguire i tests::
+
+ $ python doctest_runner.py -v
+ Trying:
+ from isnumber import is_number
+ Expecting nothing
+ ok
+ Trying:
+ is_number("1")
+ Expecting:
+ True
+ ok
+ Trying:
+ is_number("1.3")
+ Expecting:
+ True
+ ok
+ Trying:
+ is_number("+1.3")
+ Expecting:
+ True
+ ok
+ Trying:
+ is_number("-1.3")
+ Expecting:
+ True
+ ok
+ Trying:
+ is_number("1-.3")
+ Expecting:
+ False
+ ok
+ Trying:
+ is_number("a")
+ Expecting:
+ False
+ ok
+ Trying:
+ is_number("42")
+ Expecting:
+ True
+ ok
+ Trying:
+ 1/0
+ Expecting:
+ Traceback (most recent call last):
+ kkkkdjjfkf
+ ZeroDivisionError: integer division or modulo by zero
+ ok
+ 1 items passed all tests:
+ 9 tests in test_isnumber.txt
+ 9 tests in 1 items.
+ 9 passed and 0 failed.
+ Test passed.
+
+Confrontare la leggibilità di ``test_isnumber.txt`` con la leggibilità
+di ``test_isnumber.py``, basato su unittest. Leggetevi il mio seminario su
+doctest (in allegato) per convincervi che doctest è il migliore. Anche perchè
+i doctest possono essere convertiti in unittest automaticamente, a partire
+da Python 2.4
+
+Per convertire i test contenuti in 'mymodulè da doctest a unittest::
+
+ import doctest, unittest, mymodule
+
+ if __name__== "__main__":
+ suite = doctest.DocTestSuite(mymodule)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+E' anche possibile contenere i tests contenuti in un file di
+tipo testo da doctest a unittest, vedere la documentazione.
+
+Correntemente, doctest non ha un meccanismo predefinito corrispondente
+ai metodi ``setUp`` e ``tearDown`` di unittest, ma potete impostarlo a mano.
+
+
+Un esempio di programma sviluppato in maniera incrementale
+----------------------------------------------------------
+
+Il seguente esempio svolto al corso intendeva dimostrare:
+
+1. Come si sviluppa un programma in maniera incrementale (ad ogni nuova riga di
+ codice si fa una verifica immediata del funzionamento dell'insieme);
+2. Come si fanno scelte architetturali in maniera tale da assicurare la
+ testabilità del prodotto finale in maniera semplice ed automatica;
+3. Come sfruttare la libreria standard di Python al meglio, usando il
+ modulo cmd;
+4. Come dividere il codice in metodi pubblici, metodi di utilità e
+ metodi di debugging;
+5. Come assicurarsi che il programma venga chiuso propriamente, anche
+ nel caso di eccezioni impreviste e imprevedibili;
+
+::
+
+ # -*- encoding: latin-1 -*-
+ import os, cmd, subprocess, lib, time # lib fissa os.kill
+ from pywintypes import error as WindowsProcessDidNotStartCorrectly
+
+ MUSICDIR = "C:/Documents and Settings/micheles/Desktop/Music"
+
+ def play_song(name):
+ po = subprocess.Popen(["mplay32", "/play", "/close", name])
+ return po.pid
+
+ class InterpreteDiComandi(cmd.Cmd):
+ cwd = MUSICDIR
+ prompt = "Player> "
+ def preloop(self):
+ self.process_list = []
+ os.chdir(MUSICDIR)
+
+ def do_play(self, arg):
+ "Suona una canzone"
+ if not arg:
+ print "Per favore scrivi il nome di una canzone!"
+ else:
+ self.process_list.append(play_song(arg))
+
+ def do_quit(self, dummy):
+ "Esce dall'interprete."
+ return True
+
+ def safe_kill(self, pid):
+ try:
+ os.kill(pid)
+ except WindowsProcessDidNotStartCorrectly, e:
+ print e
+
+ def do_kill(self, arg):
+ "Uccide il player"
+ try:
+ pid = self.process_list.pop()
+ except IndexError:
+ print "Hai già ucciso tutti i processi!"
+ else:
+ self.safe_kill(pid)
+
+ def postloop(self):
+ for pid in self.process_list:
+ self.safe_kill(pid)
+ print "Ho ucciso tutto!"
+ os.chdir(os.path.dirname(os.path.abspath(__file__)))
+
+ # metodi che possono essere utili per il debugging
+ def do_print_dir(self, arg):
+ "Comando utile per il debugging"
+ print self.cwd
+
+ def do_raise_exc(self, dummy):
+ raise RuntimeError("Tanto per vedere che succede")
+
+ def do_sleep(self, arg):
+ "utile per vedere quello che i test automatici stanno facendo"
+ time.sleep(int(arg))
+
+ i = InterpreteDiComandi()
+
+ try:
+ i.cmdloop()
+ finally: # assicura la chiusura anche in caso di eccezione
+ i.postloop()
+
+Nel caso regolare (senza eccezioni impreviste) .postloop è chiamato 2 volte,
+ma questo non fa danno.
+
+Questo potrebbe essere il codice corrispondente ad un test automatico::
+
+ $ more test_player.cmd
+ play
+ sleep 2
+ play 2. Croi Croga.mp
+ sleep 2
+ play 2. Croi Croga.mp3
+ sleep 2
+ kill
+ sleep 2
+ quit
+
+(la prima canzone non esiste, in modo da poter vedere come viene segnalato
+l'errore) che verrebbe eseguito così::
+
+ $ python player.py < test_player.cmd
+
+Modulo 5: Design, documentazione e manutenzione di librarie
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Pratiche di programmazione "in the large". Moduli, packages, strumenti di
+documentazione e di installazione. Applicazioni pratiche di principi generali
+quali disaccoppiamento, modularità, non duplicazione del codice.*
+
+La filosofia del Python
+---------------------------------------
+
+>>> import this
+The Zen of Python, by Tim Peters
+Beautiful is better than ugly.
+Explicit is better than implicit.
+Simple is better than complex.
+Complex is better than complicated.
+Flat is better than nested.
+Sparse is better than dense.
+Readability counts.
+Special cases aren't special enough to break the rules.
+Although practicality beats purity.
+Errors should never pass silently.
+Unless explicitly silenced.
+In the face of ambiguity, refuse the temptation to guess.
+There should be one-- and preferably only one --obvious way to do it.
+Although that way may not be obvious at first unless you are Dutch.
+Now is better than never.
+Although never is often better than *right* now.
+If the implementation is hard to explain, it's a bad idea.
+If the implementation is easy to explain, it may be a good idea.
+Namespaces are one honking great idea -- let's do more of those!
+
+Principio del disaccoppiamento
+-------------------------------------
+
+Questo è il principio guida di tutta la programmazione e non solo, tutto
+il resto nasce di conseguenza.
+
+Il principio dice: **cercate di disaccoppiare il più possibile
+le componenti del vostro sistema**.
+
+*Un componente si dice disaccoppiato se
+può essere rimosso o sostituito senza danneggiare il resto del sistema.*
+
+Per esempio:
+
+- disaccoppiare l'ambiente di sviluppo dall'ambiente di esecuzione (è più
+ sicuro lanciare un programma dalla riga di comando che dall' IDE; un
+ debugger disaccoppiato come pdb è più sicuro di un debugger integrato
+ come quello di PythoWin, un editor vero è più sicuro dell'editor dell'
+ IDE, etc.)
+
+- disaccoppiare l'interfaccia grafica: il programma deve poter funzionare
+ senza di essa, o sostituendo il GUI toolkit con un altro.
+
+- i threads vi accoppiano tutto, se uno va male può bloccare tutti gli
+ altri: evitateli se potete.
+
+- l'ereditarietà vi accoppia il parente al figlio (per sapere quello che
+ fa il figlio bisogna andare a vedere quello che fanno il padre, il nonno,
+ il bisnonno, il trisavolo, etc.). Evitatela se potete.
+
+- la modularità è un modo concreto per applicare il principio del
+ disaccoppiamento al codice: funzioni che logicamente vanno insieme,
+ vanno messe in un modulo comune, funzioni separate vanno separate.
+ Se c'è un problema nel modulo X, questo non deve interferire con
+ il modulo Y (almeno in un mondo ideale). La modularità rende anche
+ più semplice rimpiazzare un modulo sbagliato o vecchio con uno
+ corretto o più recente.
+
+- la non-duplicazione del codice è una conseguenza della modularità:
+ avendo raggruppato le funzioni di uso generale in un modulo comune,
+ si acquista in concisione, semplicità, leggibilità, debuggabilità,
+ si evita di correggere lo stesso errore più volte, e in generale tutto
+ diviene più facile da mantenere.
+
+Principio del KISS
+--------------------------------------
+
+*Keep it simple, stupid*. In Italiano: *non facciamoci del male*.
+
+Se potete fare le cose in maniera semplice, fatele in maniera semplice.
+
+Chiedetevi sempre se una cosa vi serve veramente oppure no.
+
+Importanza di avere un prototipo
+------------------------------------------
+
+Non c'è nulla di più sbagliato che partire scrivendosi l'architettura di
+un progetto complesso sulla carta. Si parte sempre scrivendo un prototipo,
+*testato sul campo di battaglia*, che magari ha l'1% delle funzionalità
+che vi interessano, ma che *funziona*. A quel punto è possibile decidere
+l'architettura e il prototipo diventerà il core e la parte più testata
+e sicura della vostra applicazione.
+
+Il prototipo/core deve *rimuovere tutto l'inessenziale*. Più povero è,
+meglio è.
+
+
+Moduli e packages
+-------------------------------------------
+
+Qualunque file Python può essere visto come un modulo. Un package invece,
+è una directory contente un file ``__init__.py`` che contiene il codice di
+inizializzazione (``__init__.py`` può benissimo essere vuoto, oppure può
+consistere solo di 'import' dei moduli di quel package).
+
+Importare un package non importa automaticamente tutti i suoi moduli,
+a meno che questo non sia detto esplicitamente nell' ``__init__.py``.
+
+I package possono essere nidificati senza limite.
+
+Le variabili globali di un modulo sono locali a quel modulo, quindi
+non c'è mai il rischio di fare danni (a meno che un modulo non importi
+esplicitamente una variabile corrispondente ad un oggetto mutabile e
+la cambi esplicitamente).
+
+E' possibile mettere un package nel Python path automaticamente per
+tutti gli utenti listando il nome del package in un file ``.pth`` nella
+directory site-packages (vedere la documentazione di distutils).
+
+
+Come si documenta una libreria Python
+-------------------------------------------------
+
+Python è un linguaggio "self-documenting" grazie alle doctrings.
+Usatele. In più guardate come è documentato un progetto Python
+tipico (io suggerisco di guardare a *docutils*) e copiate le convenzioni
+usate lì. Ci sono dei file standard come il README.txt, l'HISTORY.txt,
+il BUGS.txt, una directory docs, una directory test, un file setup.py,
+etc.
+
+Tenete presente che grazie a *doctest* potete inserire dei test automatici
+all'interno della vostra documentazione.
+
+Modulo 6: Domande estemporanee
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Risponderò alle domande dell'audience, anche al di fuori dal programma,
+se di interesse generale*.
+
+Come funziona 'import'
+---------------------------------
+
+Se un modulo è già stato importato e chiamate 'import' una seconda
+volta, il modulo NON viene importato due volte. Questo può essere
+un problema nell'interprete interattivo. Se importate un modulo,
+poi lo modificate e lo importate di nuovo, vi resterà in memoria
+la copia *vecchia*, quella non modificata. La soluzione è usare
+'reload', che vi importerà veramente la nuova versione.
+
+Come funziona '__del__'
+---------------------------------------------
+
+>>> a = 1
+>>> del a
+
+vi cancella il nome dal namespace:
+
+>>> a
+Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+NameError: name 'a' is not defined
+
+Tuttavia l'oggetto cui si riferisce *non viene cancellato immediatamente*.
+Verrà cancellato dal garbage collector *quando serve*, ma soltanto
+*se non vi sono altre referenze* all'oggetto da qualche altra parte.
+Inoltre per oggetti C, dovrete definirvi un metodo ``__del__`` custom
+che ha accesso all'oggetto a livello C. Tenete anche conto che tipicamente
+il debugger tiene referenze agli oggetti aggiuntive, quindi in modalità
+di debugger i problemi con oggetti non cancellati peggiorano.
+
+Ecco un esempio di un metodo ``__del__`` custom piuttosto banale:
+
+>>> class C(object):
+... def __del__(self):
+... print 'Hai usato del'
+...
+>>> c = C()
+>>> del c
+Hai usato del
+
+Il metodo ``__del__`` viene chiamato automaticamente all'uscita
+dall'interprete:
+
+>>> class C(object):
+... def __del__(self):
+... print 'Hai usato del'
+...
+>>> c = C()
+>>> <CTRL-Z> per uscire dall'interprete
+Hai usato del
+
+In principio, all'uscita del programma Python
+*dovrebbe chiamare ``__del__`` automaticamente anche se vi sono eccezioni*::
+
+ #<del_with_exc.py>
+
+ class C(object):
+ def __del__(self):
+ print "Hai chiamato del"
+
+ c = C()
+ raise RuntimeError("Ahi ahi!")
+
+ #</del_with_exc.py>
+
+ $ python del_with_exc.py
+ Traceback (most recent call last):
+ File "del_with_exc.py", line 6, in ?
+ raise RuntimeError("Ahi ahi!")
+ RuntimeError: Ahi ahi!
+ Hai chiamato del
+
+Tuttavia per oggetti ``C`` ed eccezioni le cose possono essere delicate ed
+è sempre meglio chiamare ``del`` *esplicitamente*, magari in un
+``try .. finally``.
+
+Che differenza c'è fra variabili di classe e di istanza
+---------------------------------------------------------
+
+Questo esempio dovrebbe chiarire la differenza:
+
+>>> class C(object):
+... pippo = 'sono una variabile di classe'
+... def __init__(self):
+... self.poppi = 'sono una variabile di istanza'
+...
+
+Le variabili di classe sono le stesse per tutte le istanze:
+
+>>> c1 = C()
+>>> c2 = C()
+>>> c1.pippo
+'sono una variabile di classe'
+>>> c2.pippo
+'sono una variabile di classe'
+
+Se cambio una variabile di classe, cambia per tutte le istanze, anche
+per quelle che sono state create *prima* del cambiamento:
+
+>>> C.pippo = 'adesso la cambio'
+>>> c1.pippo
+'adesso la cambio'
+>>> c2.pippo
+'adesso la cambio'
+
+Lo stesso vale per i metodi, che non sono altro che variabili di classe.
+
+Le variabili di istanza invece sono indipendenti:
+
+>>> c1.poppi
+'sono una variabile di instanza'
+>>> c2.poppi
+'sono una variabile di instanza'
+>>> c1.poppi = 'cambio la variabile dell'istanza c1'
+>>> c1.poppi
+'cambio la variabile dell'istanza c1'
+>>> c2.poppi # questa rimane quella che era prima
+'sono una variabile di instanza'
+
+Che cosa sono i metodi che iniziano con "__"
+------------------------------------------------
+
+Sono metodi protetti. Sono utili per evitare rogne con l'ereditarietà.
+Per capire il problema dò un esempio semplice qui di seguito.
+
+Normalmente l'ereditarietà accoppia il padre con il figlio, nel senso che
+il figlio può sovrascrivere i metodi del padre, e i metodi del padre andranno
+automaticamente a chiamare i metodi del figlio::
+
+ class B(object): # padre
+ def __init__(self):
+ self.hello()
+ def hello(self):
+ print "hello!"
+
+ class C(B): # figlio
+ def hello(self):
+ print "cucu!"
+
+ b = B() # stampa 'hello!'
+ c = C() # stampa 'cucu!'
+
+In questo esempio l'__init__ del padre chiama l'hello del figlio. Tuttavia,
+a volte uno vuole essere sicuro che l'__init__ del padre chiami l'hello
+del padre, e non quello del figlio (sempre per via del principio del
+disaccoppiamento). Per questo ci sono i *metodi protetti*::
+
+ class B(object):
+ def __init__(self): # call the '__hello' method in THIS class
+ self.__hello()
+ def __hello(self):
+ print "hello!"
+
+ class C(B):
+ def __hello(self): # won't be called by B.__init__
+ print "cucu!"
+
+ b = B() # stampa 'hello!'
+ c = C() # stampe 'hello!'
+
+
+I metodi protetti di tipo ``__<nome metodo>`` non vanno confusi con i metodi
+privati di tipo ``_<nome metodo>`` (un solo underscore):
+
+1. i metodi privati non andrebbero chiamati mai, se non sapendo al 100% quello
+ che si sta facendo, e solo in caso di errori nel design della libreria che
+ si sta utilizzando;
+
+2. i metodi protetti possono essere chiamati con tranquillità. Proprio
+ perchè sono protetti, c'è la garanzia che sovrascrivendoli nella
+ sottoclasse non si va ad alterare il comportamento ereditato dal padre
+ (nel nostro esempio l'``__init__`` del padre continuerà a chiamare il
+ proprio ``__hello``, non l'``__hello`` del figlio). D'altra parte i
+ metodi definiti nel figlio vedranno solo l'``__hello`` del figlio e
+ non quello del padre.
+
+3. i metodi protetti non possono essere chiamati accidentalmente, perchè
+ per esempio ``c.__hello()`` non funziona. Tuttavia è possibile chiamarli,
+ quindi non sono veramente privati: nel nostro esempio è possibile
+ chiamare
+
+ ``c._B__hello`` (``__hello`` del padre) oppure
+ ``c._C__hello`` (``__hello`` del figlio)
+
+ Siccome bisogna specificare il nome della classe dove il metodo è definito
+ non c'è il rischio di sbagliarsi (a meno di non essere masochisti e di
+ non dare lo stesso nome al padre e al figlio).
+
+I metodi protetti vengono usati raramente. Vedere "Python in a Nutshell"
+per maggiori informazioni sul loro uso.
+
+Soluzioni al questionario di ammissione
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Scrivere un programma che testa se una stringa rappresenta un numero
+---------------------------------------------------------------------
+
+Soluzione standard (vedere anche il tutorial di Python)::
+
+ try:
+ int(x)
+ except ValueError:
+ print "This is not a number!"
+
+Soluzione usando tkSimpleDialog::
+
+ from tkSimpleDialog import askfloat
+ askfloat("Enter a number", "Number:")
+
+Scrivere un programma che lista tutti i files nella directory corrente
+------------------------------------------------------------------------
+
+::
+
+ for f in os.listdir("."):
+ print f
+
+Listare tutti i files nelle sottodirectories ricorsivamente
+-------------------------------------------------------------
+
+::
+
+ for cwd, dirs, files in os.walk("."):
+ for f in files:
+ print f
+
+Calcolare lo spazio occupato da tutti i files di tipo .txt in una directory
+----------------------------------------------------------------------------
+
+[Soluzione svolta al corso 1]
+
+::
+
+ import os
+
+ def get_text_files(d):
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ if f.lower().endswith(".txt"):
+ fullname = os.path.join(cwd, f)
+ size = os.path.getsize(fullname)
+ yield fullname, size
+
+ from operator import itemgetter
+ print sum(map(itemgetter(1), get_text_files(".")))
+
+Listare i files a seconda delle dimensioni
+-------------------------------------------
+
+::
+
+ print sorted(get_text_files("."), key=itemgetter(1))
+
+Scrivere un test per verificate che una directory sia vuota
+--------------------------------------------------------------
+
+::
+
+ def is_empty(d):
+ if os.listdir(d): return False
+ else: return True
+
+Sarebbe ridondante scrivere
+
+::
+
+ if os.listdir(d) != []:
+
+
+perchè la lista vuota ha già di per sè un valore booleano "False".
+
+Aprire una finestrella contenente la scritta "hello, world!"
+-------------------------------------------------------------
+
+[In maniera portabile]
+
+Soluzione più semplice::
+
+ # hellotk.pyw
+ from tkMessageBox import showinfo
+ showinfo(message="hello")
+
+Soluzione alternativa::
+
+ # hellotk.pyw
+ import Tkinter as t
+ root = t.Tk()
+ l = t.Label(text="hello")
+ l.pack()
+ root.mainloop()
+
+Guardatevi sull'help di ActiveState la differenza tra l'estensione ``.py``
+e l'estensione ``.pyw`` (dovrebbe essere nelle FAQ).
+
+Scaricare la pagina Web http://www.example.com da Internet
+----------------------------------------------------------------
+
+>>> from urllib2 import urlopen
+>>> print urlopen('http://www.example.com').read()
+
+Stampare a schermo una tavola delle moltiplicazioni
+---------------------------------------------------------
+
+Soluzione senza generatori::
+
+ #<maketable.py>
+
+ # non graphic
+ N = 10
+ for i in range(1, N+1):
+ for j in range(1, N+1):
+ print "%4d" % (i*j),
+ print
+
+ # HTML
+ def maketable(iterable, N):
+ iterable = iter(iterable)
+ print "<table border='1'>"
+ stop = False
+ while not stop:
+ print "<tr>"
+ for j in range(1, N+1):
+ try:
+ print "<td>%s</td>" % iterable.next(),
+ except StopIteration:
+ print "<td></td>"
+ stop = True
+ print "</tr>"
+ print "</table>"
+
+ import tempfile, webbrowser, os, sys
+
+ def showtable(iterable, N):
+ stdout = sys.stdout # shows how to redirect stdout correctly
+ fd, name = tempfile.mkstemp(suffix=".html")
+ sys.stdout = os.fdopen(fd, "w")
+ maketable(iterable, N)
+ webbrowser.open(name)
+ sys.stdout = stdout
+
+ showtable((i*j for j in range(1, N+1) for i in range(1, N+1)), N)
+
+ #</maketable.py>
+
+Soluzione usando i generatori, non HTML::
+
+ #<gentable.py>
+
+ def gentable(N):
+ for i in range(1, N+1):
+ for j in range(1, N+1):
+ yield i*j
+
+ def printtable(lst, N):
+ for i, el in enumerate(lst):
+ print "%4d" % el,
+ if (i+1) % 10 == 0:
+ print
+
+ if __name__ == "__main__":
+ printtable(gentable(10), 10)
+
+ #</gentable.py>
+
+Trovare tutte le immagini .jpg nel vostro hard disk e mostrarle a schermo in formato ridotto
+--------------------------------------------------------------------------------------------
+
+Soluzione svolta al corso 1::
+
+ import os, webbrowser
+
+ def gentableHTML(iterable, N):
+ iterator = iter(iterable)
+ yield "<HTML>"
+ yield "<BODY>"
+ yield "<TABLE border='1'>"
+ for i in range(N):
+ yield "<TR>"
+ for j in range(N):
+ yield '<TD><img src="%s" width="50", height="50"></TD>\n' % \
+ iterator.next()
+ yield "</TR>\n"
+ yield "</TABLE>"
+ yield "</BODY>"
+ yield "</HTML>"
+
+ # generatore di file names
+ def get_files_with_ext(ext_set, d):
+ """
+ ext_set is a set of valid extensions.
+ """
+ assert isinstance(ext_set, set), "%r is not a set!" % ext_set
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ fullname = os.path.join(cwd, f)
+ if ext.lower() in ext_set and os.path.getsize(fullname):
+ yield fullname
+
+ if __name__ == "__main__":
+ # genera il file e lo mostra
+ images = file("images.html", "w")
+ for el in gentableHTML(get_files_with_ext(set([".png"]),
+ "C:\\Documents and Settings"), 15):
+ print >> images, el,
+ images.close()
+ webbrowser.open("images.html")
+
+Soluzione più sofisticata, per darvi qualcosa su cui pensare::
+
+ #<maketable.py>
+
+ def get_files_with_ext(ext, d):
+ """
+ ext can be a string or a set of strings; for instance
+ get_files_with_ext(".png") or get_files_with_ext(set(".png", ".gif"))
+ """
+ if not isinstance(ext, set):
+ ext_set = set([ext])
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ if ext.lower() in ext_set:
+ yield os.path.join(cwd, f)
+
+ class Picture(object):
+ """An example of the utility of __str__"""
+ def __init__(self, pathname):
+ self.pathname = pathname
+ self.name = os.path.basename(pathname)
+ def __str__(self):
+ return "<img src=%r width=100>" % self.pathname
+
+ if sys.platform == 'win32':
+ drive = "C:\\"
+ else:
+ drive = "/"
+ showtable(map(Picture, get_files_with_ext(".jpg", drive)), N)
+
+ #</maketable.py>
+
diff --git a/pypers/marelli/materiale/del_with_exc.py b/pypers/marelli/materiale/del_with_exc.py
new file mode 100755
index 0000000..ee09bf1
--- /dev/null
+++ b/pypers/marelli/materiale/del_with_exc.py
@@ -0,0 +1,10 @@
+# del_with_exc.py
+
+class C(object):
+ def __del__(self):
+ print "Hai chiamato del"
+
+c = C()
+raise RuntimeError("Ahi ahi!")
+
+
diff --git a/pypers/marelli/materiale/doctest_runner.py b/pypers/marelli/materiale/doctest_runner.py
new file mode 100755
index 0000000..cd528c9
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_runner.py
@@ -0,0 +1,8 @@
+# doctest_runner.py
+
+import doctest
+
+if __name__== "__main__":
+ doctest.testfile("test_isnumber.txt")
+
+
diff --git a/pypers/marelli/materiale/doctest_talk/Makefile b/pypers/marelli/materiale/doctest_talk/Makefile
new file mode 100755
index 0000000..77a6cc0
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/Makefile
@@ -0,0 +1,5 @@
+talk: talk.txt
+ python2.4 maketalk.py talk.txt
+test: P01.html
+ tidy P01.html > /dev/null 2> x.txt; less x.txt
+
diff --git a/pypers/marelli/materiale/doctest_talk/P01.html b/pypers/marelli/materiale/doctest_talk/P01.html
new file mode 100755
index 0000000..a3a9e4d
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P01.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P01</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P02.html'>Next</a></td> <td bgcolor="lightblue"><a href='P25.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P01</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Automatic testing in Python: wonderful doctest!</h1><br/>
+
+<center>
+
+ ACCU Conference 2005 <br/> <br/>
+
+ 22 Apr 2005 <br/> <br/>
+
+ Michele Simionato <br/> <br/>
+
+ michele.simionato@gmail.com <br/> <br/>
+
+</center></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P02.html b/pypers/marelli/materiale/doctest_talk/P02.html
new file mode 100755
index 0000000..b187e50
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P02.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P02</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>Next</a></td> <td bgcolor="lightblue"><a href='P01.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P02</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Summary</h1><br/>
+
+<ul>
+ <li> What is automatic testing? </li>
+ <li> Why automatic testing is better? </li>
+ <li> Which kind of automatic testing? </li>
+ <li> How does it work, in practice? </li>
+ <li> What's the message?</li>
+<ul></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P03.html b/pypers/marelli/materiale/doctest_talk/P03.html
new file mode 100755
index 0000000..dbfc5f8
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P03.html
@@ -0,0 +1,102 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P03</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P04.html'>Next</a></td> <td bgcolor="lightblue"><a href='P02.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P03</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>What is automatic testing</h1><br/>
+
+Any methodology that allows you to test
+your application mechanically, repeatedly
+and in a <em>controlled reproducible</em> way.</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P04.html b/pypers/marelli/materiale/doctest_talk/P04.html
new file mode 100755
index 0000000..b05ff1a
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P04.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P04</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>Next</a></td> <td bgcolor="lightblue"><a href='P03.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P04</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Automatic testing is better (1)</h1><br/>
+
+When doing manual testing typically you spend
+
+<center><h2>
+
+ 1 hour of coding + 10 hours of testing/debugging
+
+</center></h2>
+
+on the other hand ...</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P05.html b/pypers/marelli/materiale/doctest_talk/P05.html
new file mode 100755
index 0000000..62b628a
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P05.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P05</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P06.html'>Next</a></td> <td bgcolor="lightblue"><a href='P04.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P05</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Automatic testing is better (2)</h1><br/>
+
+... when doing automatic testing typically you spend
+
+<br/> <br/>
+<center><h2>
+
+ 1 hour of coding + 10 hours of testing/debugging !
+
+</center></h2></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P06.html b/pypers/marelli/materiale/doctest_talk/P06.html
new file mode 100755
index 0000000..f4a18cb
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P06.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P06</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>Next</a></td> <td bgcolor="lightblue"><a href='P05.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P06</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>However ...</h1><br/>
+
+Think about six month later!
+ <br/><br/>
+<center><em>
+
+ there is a difference</em>
+
+ <h2><u>Refactoring!</u><h2>
+
+</center></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P07.html b/pypers/marelli/materiale/doctest_talk/P07.html
new file mode 100755
index 0000000..b6c31ae
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P07.html
@@ -0,0 +1,107 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P07</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P08.html'>Next</a></td> <td bgcolor="lightblue"><a href='P06.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P07</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Automatic testing in Python</h1><br/>
+
+There are two standard testing frameworks in Python:
+
+<ol>
+ <li> unittest </li>
+ <li> doctest </li>
+</ol>
+
+Which one should I use?</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P08.html b/pypers/marelli/materiale/doctest_talk/P08.html
new file mode 100755
index 0000000..6c6c43e
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P08.html
@@ -0,0 +1,102 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P08</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>Next</a></td> <td bgcolor="lightblue"><a href='P07.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P08</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Well,</h1><br/>
+
+since my talk has <em>doctest</em> in the title ...
+
+ ;-)</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P09.html b/pypers/marelli/materiale/doctest_talk/P09.html
new file mode 100755
index 0000000..0e92531
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P09.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P09</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P10.html'>Next</a></td> <td bgcolor="lightblue"><a href='P08.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P09</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>More seriously ...</h1><br/>
+
+Use different testing frameworks; each one has advantages
+and disadvantages; use combinations of them; invent your
+own testing procedure.
+
+I use combinations of
+
+<ul>
+ <li> unittest </li>
+ <li> doctest </li>
+ <li> custom tests </li>
+ <li> Makefile driven tests </li>
+ <li> et al. </li>
+</ul>
+
+doctest emphasis is on <em>documentation</em></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P10.html b/pypers/marelli/materiale/doctest_talk/P10.html
new file mode 100755
index 0000000..19c6e36
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P10.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P10</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>Next</a></td> <td bgcolor="lightblue"><a href='P09.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P10</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>What is doctest?</h1><br/>
+
+In its simplest form (which I do not use that much) doctest allows
+you to include tests in the docstrings of your application.</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P11.html b/pypers/marelli/materiale/doctest_talk/P11.html
new file mode 100755
index 0000000..e838716
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P11.html
@@ -0,0 +1,114 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P11</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P12.html'>Next</a></td> <td bgcolor="lightblue"><a href='P10.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P11</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Example</h1><br/>
+<pre># split.py
+import re
+SEP = re.compile(r"\s*[,;]\s*")
+
+def split(text):
+ """Split a string taking as separators "," ";".
+ Example:
+ >>> from split import split
+ >>> split("hello, world!; welcome to PyUK!")
+ ['hello', 'world!', 'welcome to PyUK!']
+ """
+ return SEP.split(text)
+
+if __name__ == "__main__":
+ import doctest; doctest.testmod()
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P12.html b/pypers/marelli/materiale/doctest_talk/P12.html
new file mode 100755
index 0000000..230eb27
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P12.html
@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P12</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>Next</a></td> <td bgcolor="lightblue"><a href='P11.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P12</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Running doctest in verbose mode</h1><br/>
+
+<pre>
+$ python split.py -v
+Running __main__.__doc__
+0 of 0 examples failed in __main__.__doc__
+Running __main__.split.__doc__
+Trying: from split import split
+Expecting: nothing
+ok
+Trying: split("hello, world!; welcome to Oxford!")
+Expecting: ['hello', 'world!', 'welcome to Oxford!']
+ok
+0 of 2 examples failed in __main__.split.__doc__
+1 items had no tests:
+ __main__
+1 items passed all tests:
+ 2 tests in __main__.split
+2 tests in 2 items.
+2 passed and 0 failed.
+Test passed.
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P13.html b/pypers/marelli/materiale/doctest_talk/P13.html
new file mode 100755
index 0000000..b2fe415
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P13.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P13</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P14.html'>Next</a></td> <td bgcolor="lightblue"><a href='P12.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P13</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Why I do not use the docstring approach</h1><br/>
+
+<ul>
+<li> It makes you end up with very large docstrings</li>
+
+<li> It abuses the original purpose of docstrings</li>
+
+<li> It conflates two different aspects (code and tests on the code)</li>
+
+<li> It is much easier to write the documentation in a separate
+ text file </li>
+
+<li> Testing should be done by an external tool anyway </li>
+</ul></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P14.html b/pypers/marelli/materiale/doctest_talk/P14.html
new file mode 100755
index 0000000..5c16abf
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P14.html
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P14</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>Next</a></td> <td bgcolor="lightblue"><a href='P13.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P14</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>How I use doctest</h1><br/>
+
+I hacked inside doctest and wrote a custom utility
+to extract doctests from documentation files since
+
+<ul>
+ <li>I like keeping the documentation on a separate rst file</li>
+
+ <li>there is no sync problem since you run the tests all the time</li>
+
+ <li>it is useful for writing articles ...</li>
+
+ <li> ... but also documentation for internal usage in the company</li>
+</ul>
+
+http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/410052
+
+<pre>
+$ python -m doctester < split.txt
+doctest: run 4 tests, failed 0
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P15.html b/pypers/marelli/materiale/doctest_talk/P15.html
new file mode 100755
index 0000000..a6843e3
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P15.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P15</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P16.html'>Next</a></td> <td bgcolor="lightblue"><a href='P14.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P15</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Testing the doctester frontend</h1><br/>
+
+<pre>
+>>> from ms.webtester import start_server, stop_server
+>>> from ms.http_utils import urlopen
+>>> baseurl = "http://localhost:7080/"
+>>> home = "/home/micheles/md/python/quixote/"
+
+>>> start_server(home + "doctester_frontend.py")
+>>> import time; time.sleep(2) # wait a bit
+
+Making a POST:
+
+>>> res = urlopen(baseurl, dict(txt=">>> 1 + 1\n2")).read()
+>>> assert "tests" in res
+>>> stop_server()
+
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P16.html b/pypers/marelli/materiale/doctest_talk/P16.html
new file mode 100755
index 0000000..d5b4541
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P16.html
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P16</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>Next</a></td> <td bgcolor="lightblue"><a href='P15.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P16</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Managing exceptions</h1><br/>
+
+It is possible to test that your program raises the exception you
+expect:
+
+<pre>
+
+$ echo "# split cannot work on a list
+>>> from split import split
+>>> split([])
+Traceback (most recent call last):
+ ...
+TypeError: expected string or buffer
+" > x.txt
+
+$ doct x.txt
+x.txt: 2 tests passed in 0.01 seconds
+
+</pre>
+
+(notice however that relying on exception messages may be risky)</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P17.html b/pypers/marelli/materiale/doctest_talk/P17.html
new file mode 100755
index 0000000..da93de5
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P17.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P17</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P18.html'>Next</a></td> <td bgcolor="lightblue"><a href='P16.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P17</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>When tests fail</h1><br/>
+
+<pre>
+
+$ cat split-failure.txt
+An example of failed text:
+
+>>> from split import split
+>>> split("hello, world")
+['hello', ' world']
+
+$ doct split-failure.txt
+*****************************************************************
+Failure in example: split("hello, world")
+from line #5 of split-failure.txt
+Expected: ['hello', ' world']
+Got: ['hello', 'world']
+
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P18.html b/pypers/marelli/materiale/doctest_talk/P18.html
new file mode 100755
index 0000000..0acc512
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P18.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P18</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>Next</a></td> <td bgcolor="lightblue"><a href='P17.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P18</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Converting doctests to unittests</h1><br/>
+
+<pre>
+ import unittest
+ import doctest
+ import my_module_with_doctests
+
+ suite = doctest.DocTestSuite(my_module_with_doctests)
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
+</pre>
+
+<h2>For Python 2.3+<h2></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P19.html b/pypers/marelli/materiale/doctest_talk/P19.html
new file mode 100755
index 0000000..744a43b
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P19.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P19</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P20.html'>Next</a></td> <td bgcolor="lightblue"><a href='P18.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P19</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>doctest is becoming even better</h1><br/>
+
+With Python 2.4 you can run doctests on external text files:
+
+<pre>
+ import doctest, unittest
+ doctest.testfile(my_documentation_file, package=mypackage)
+</pre>
+
+you can also convert these doctests into unittests:
+
+<pre>
+ import doctest, unittest
+ suite = doctest.DocFileSuite(my_documentation_file, package=mypackage)
+ unittest.TextTestRunner().run(suite)
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P20.html b/pypers/marelli/materiale/doctest_talk/P20.html
new file mode 100755
index 0000000..8aea60d
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P20.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P20</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>Next</a></td> <td bgcolor="lightblue"><a href='P19.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P20</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Python 2.4 recognizes blank lines</h1><br/>
+
+Blank lines can be marked with &lt;BLANKLINE&gt; :
+<pre>
+>>> print 'foo\n\nbar\n'
+foo
+&lt;BLANKLINE&gt;
+bar
+&lt;BLANKLINE&gt;
+
+</pre></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P21.html b/pypers/marelli/materiale/doctest_talk/P21.html
new file mode 100755
index 0000000..34a3aa5
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P21.html
@@ -0,0 +1,117 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P21</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P22.html'>Next</a></td> <td bgcolor="lightblue"><a href='P20.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P21</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Python 2.4 recognizes flags!</h1><br/>
+
+<ul>
+<li> If the ellipsis flag is used, then '...' can be used to
+ elide substrings in the desired output: <pre>
+>>> print range(1000) #doctest: +ELLIPSIS
+[0, 1, 2, ..., 999]
+
+</pre></li>
+
+<li>
+ If the whitespace normalization flag is used, then
+ differences in whitespace are ignored.<pre>
+>>> print range(20) #doctest: +NORMALIZE_WHITESPACE
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+12, 13, 14, 15, 16, 17, 18, 19]
+
+</pre></li>
+
+</ul></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P22.html b/pypers/marelli/materiale/doctest_talk/P22.html
new file mode 100755
index 0000000..929bbb5
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P22.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P22</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>Next</a></td> <td bgcolor="lightblue"><a href='P21.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P22</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Zope experience</h1><br/>
+
+Literal quote from the PyCON doctest talk:
+
+<ul>
+<li> ~ 5600 tests (~3500 in Zope 3, ~1300 in ZODB, ~800 in Zope 2)</li>
+<li> we wrote lots of tests before we knew what we were doing</li>
+<li> debugging failed tests is really hard when intent is unclear</li>
+<li> often refactor or reimplement tests to make them clearer</li>
+<li> most new tests are doctest based</li>
+</ul></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P23.html b/pypers/marelli/materiale/doctest_talk/P23.html
new file mode 100755
index 0000000..4ab3427
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P23.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P23</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P24.html'>Next</a></td> <td bgcolor="lightblue"><a href='P22.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P23</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Conclusion (1): good reasons to use doctest</h1><br/>
+
+<quote>
+"Test coverage is important, but test readability is much more important"
+</quote>
+
+<em>-- Tim Peters and Jim Fulton</em> <br/> <br/>
+
+doctest is good since:
+
+<ol>
+ <li> it is easy to understand, to explain and to use </li>
+
+ <li> it makes you improve the quality of your documentation </li>
+
+ <li> it can be converted to unittest anyway </li>
+
+</ol></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P24.html b/pypers/marelli/materiale/doctest_talk/P24.html
new file mode 100755
index 0000000..276299f
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P24.html
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P24</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Next</a></td> <td bgcolor="lightblue"><a href='P23.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P24</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>Conclusion (2): the message of this talk</h1><br/>
+
+Automatic testing is good for tons of practical reasons, but also
+because:
+
+<ol>
+
+<li>It teaches you <em>discipline</em> </li>
+
+<li>It makes you
+ <em>think differently</em> </li>
+
+<li>It is more <em>fun!</em> </li>
+
+</ol></td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P25.html b/pypers/marelli/materiale/doctest_talk/P25.html
new file mode 100755
index 0000000..daae306
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P25.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P25</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>Next</a></td> <td bgcolor="lightblue"><a href='P24.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P25</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>References</h1><br/>
+
+<ul>
+
+<li>The standard library documentation
+http://docs.python.org/lib/module-doctest.html </li>
+
+<li> The doctest talk by Tim Peters and Jim Fulton
+http://www.python.org/pycon/dc2004/papers/4/</li>
+
+<li> doctest.py <em>(use the source, Luke!)</em></li>
+</ul>
+</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/P26.html b/pypers/marelli/materiale/doctest_talk/P26.html
new file mode 100755
index 0000000..cb376d4
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/P26.html
@@ -0,0 +1,113 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>P26</title>
+
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+
+ </head>
+<body bgcolor="lightblue">
+
+
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><small>
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><img src = "accu2005.png" alt = "logo"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>Next</a></td> <td bgcolor="lightblue"><a href='P25.html'>Prev</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P26.html'>Last</a></td> <td bgcolor="lightblue"><a href='P01.html'>First</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">Current</td> <td bgcolor="lightblue">P26</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+<tr>
+ <td bgcolor="lightblue">
+<table border=0 summary='a table'>
+<tr>
+ <td bgcolor="lightblue"><a href='P01.html'>P01</a></td> <td bgcolor="lightblue"><a href='P02.html'>P02</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P03.html'>P03</a></td> <td bgcolor="lightblue"><a href='P04.html'>P04</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P05.html'>P05</a></td> <td bgcolor="lightblue"><a href='P06.html'>P06</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P07.html'>P07</a></td> <td bgcolor="lightblue"><a href='P08.html'>P08</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P09.html'>P09</a></td> <td bgcolor="lightblue"><a href='P10.html'>P10</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P11.html'>P11</a></td> <td bgcolor="lightblue"><a href='P12.html'>P12</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P13.html'>P13</a></td> <td bgcolor="lightblue"><a href='P14.html'>P14</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P15.html'>P15</a></td> <td bgcolor="lightblue"><a href='P16.html'>P16</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P17.html'>P17</a></td> <td bgcolor="lightblue"><a href='P18.html'>P18</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P19.html'>P19</a></td> <td bgcolor="lightblue"><a href='P20.html'>P20</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P21.html'>P21</a></td> <td bgcolor="lightblue"><a href='P22.html'>P22</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P23.html'>P23</a></td> <td bgcolor="lightblue"><a href='P24.html'>P24</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"><a href='P25.html'>P25</a></td> <td bgcolor="lightblue"><a href='P26.html'>P26</a></td>
+</tr>
+<tr>
+ <td bgcolor="lightblue"></td> <td bgcolor="lightblue"></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</small></td> <td bgcolor="lightblue"><h1>References</h1><br/>
+
+<ul>
+
+<li>The standard library documentation
+http://docs.python.org/lib/module-doctest.html </li>
+
+<li> The doctest talk by Tim Peters and Jim Fulton
+http://www.python.org/pycon/dc2004/papers/4/</li>
+
+<li> doctest.py <em>(use the source, Luke!)</em></li>
+</ul>
+</td>
+</tr>
+</table>
+
+ </body>
+
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/abstract.txt b/pypers/marelli/materiale/doctest_talk/abstract.txt
new file mode 100755
index 0000000..e671aae
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/abstract.txt
@@ -0,0 +1,11 @@
+Automatic testing proved extremely effective in
+helping code design, improving code reliability,
+and enabling code refactoring.
+Therefore, most modern languages provide a
+standard testing framework.
+Python is no exception and provide a powerful
+Smalltalk/Java-inspired unittest framework.
+However, Python also provides a *second*, less known
+but arguably *better*, testing framework called doctest..
+In this talk I will show to the audience the wonders of
+doctest, explaining why it is so cool and deserving attention.
diff --git a/pypers/marelli/materiale/doctest_talk/doct_pkg.py b/pypers/marelli/materiale/doctest_talk/doct_pkg.py
new file mode 100755
index 0000000..331fcca
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/doct_pkg.py
@@ -0,0 +1,22 @@
+import test_pkg, doctest, os
+
+import sys
+from ms.file_utils import ifiles
+
+pkg = __import__("test_pkg")
+
+pkg_name = pkg.__name__
+csd = os.path.dirname(test_pkg.__path__[0]) # current search directory
+os.chdir(csd)
+
+print "Testing package", pkg_name
+
+total_fail, total_ok = 0, 0
+for f in ifiles(pkg_name, lambda f: f.endswith(".py"), abs_path=True):
+ f = f[:-3].replace("/", ".")
+ fail, ok = doctest.testmod(__import__(f, globals(), locals(), [f]))
+ total_fail += fail
+ total_ok += ok
+print "Failed %s, passed %s" % (total_fail, total_ok)
+# doctest.testmod(test_pkg) # only tests __init__
+# doctest.run_docstring_examples(test_pkg, globals()) # idem
diff --git a/pypers/marelli/materiale/doctest_talk/doctester_frontend.py b/pypers/marelli/materiale/doctest_talk/doctester_frontend.py
new file mode 100755
index 0000000..0a1acc7
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/doctester_frontend.py
@@ -0,0 +1,44 @@
+from ms.quixote_utils_exp import Website, htmlpage, FormPage
+from doctester import runtests
+from StringIO import StringIO
+import sys
+
+class DoctestPage(FormPage):
+ form_config = """\
+ [text]
+ name: txt
+ title: Doctester input
+
+ [checkbox]
+ name: verbose
+ title: Verbose
+
+ [submit]
+ name: test
+ value: test!"""
+
+ @htmlpage()
+ def exitpage(self):
+ if self.form["verbose"]:
+ yield "<pre>%s</pre>" % self.out.getvalue()
+ else:
+ yield "%(tests)s tests, %(fail)s failed" % vars(self)
+
+ @htmlpage()
+ def errorpage(self):
+ yield self.form.get_widget('txt').error
+ yield "<pre>%s</pre>" % self.out.getvalue()
+
+ def checker(self):
+ sys.stdout_orig = sys.stdout
+ sys.stdout = self.out = StringIO()
+ txt, verbose = self.form["txt"] or "", self.form["verbose"]
+ self.fail, self.tests = runtests(txt, verbose=verbose)
+ sys.stdout = sys.stdout_orig
+ if self.fail:
+ self.form.set_error("txt", "Doctester error")
+
+publisher = Website(_q_index=DoctestPage("doctester")).publisher()
+
+if __name__ == "__main__":
+ publisher.run_show(port=7080)
diff --git a/pypers/marelli/materiale/doctest_talk/doctester_frontend.txt b/pypers/marelli/materiale/doctest_talk/doctester_frontend.txt
new file mode 100755
index 0000000..72233d4
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/doctester_frontend.txt
@@ -0,0 +1,23 @@
+A simple example of how to doctest a Web application
+--------------------------------------------------------
+
+A few imports and settings:
+
+>>> from ms.webtester import start_server, stop_server
+>>> from ms.http_utils import urlopen
+>>> baseurl = "http://localhost:7080/"
+>>> server = "/home/micheles/md/python/quixote/doctester_frontend.py"
+
+Starting the server:
+
+>>> start_server(server)
+>>> import time; time.sleep(2) # wait a bit
+
+Making a POST:
+
+>>> res = urlopen(baseurl, dict(txt=">>> 1 + 1\n2")).read()
+>>> assert "tests" in res
+
+We are done:
+
+>>> stop_server()
diff --git a/pypers/marelli/materiale/doctest_talk/ex24.py b/pypers/marelli/materiale/doctest_talk/ex24.py
new file mode 100755
index 0000000..ce45cf8
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/ex24.py
@@ -0,0 +1,17 @@
+"""
+>>> print "Hello, World!"
+Hello, World!
+
+>>> print "Hello World! 2" #doctest: +ELLIPSIS
+Hello ... 2
+>>> print range(1000) #doctest: +ELLIPSIS
+[0, 1, 2, ..., 999]
+
+>>> print "ciao come va nina?" #doctest: +ELLIPSIS
+ciao ... nina?
+
+"""
+
+if __name__ == "__main__":
+ import doctest, __main__
+ doctest.testmod(__main__)
diff --git a/pypers/marelli/materiale/doctest_talk/ex_inner.py b/pypers/marelli/materiale/doctest_talk/ex_inner.py
new file mode 100755
index 0000000..b59dc3d
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/ex_inner.py
@@ -0,0 +1,16 @@
+# split.py
+import re
+
+def outer():
+ def split(text, sep = re.compile(r"\s*[,;]\s*")):
+ """Split a string taking as separators "," ";".
+ Example:
+ >>> from split import split
+ >>> split("hello, world!; welcome to the Italian Code Jam!")
+ ['hello', 'world!', 'welcome to the Italian Code Jam!']
+ """
+ return sep.split(text)
+
+if __name__ == "__main__":
+ import __main__, doctest
+ doctest.testmod(__main__)
diff --git a/pypers/marelli/materiale/doctest_talk/index.html b/pypers/marelli/materiale/doctest_talk/index.html
new file mode 100755
index 0000000..870e229
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/index.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.3.4: http://docutils.sourceforge.net/" />
+<title>Partecs Training: Internal Documentation</title>
+<link rel="stylesheet" href="default.css" type="text/css" />
+</head>
+<body>
+<h1 class="title">Partecs Training: Internal Documentation</h1>
+<div class="document" id="partecs-training-internal-documentation">
+<p><a class="reference" href="http://wiki.partecs.com/Developers/PartecsTraining/P01.html">Michele's slides for the Italian Code Jam conference</a></p>
+</div>
+</body>
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/index.txt b/pypers/marelli/materiale/doctest_talk/index.txt
new file mode 100755
index 0000000..8988e3e
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/index.txt
@@ -0,0 +1,6 @@
+Partecs Training: Internal Documentation
+=========================================
+
+`Michele's slides for the Italian Code Jam conference`__
+
+__ http://wiki.partecs.com/Developers/PartecsTraining/P01.html
diff --git a/pypers/marelli/materiale/doctest_talk/maketalk.py b/pypers/marelli/materiale/doctest_talk/maketalk.py
new file mode 100755
index 0000000..abd3394
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/maketalk.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+import exc_debugger, webbrowser
+from ms.html_utils import makelink, TableList, tidy
+import os, sys, re
+INCLUDE = re.compile(r"\n.. include::\s+([\w\./]+)")
+
+BGCOLOR = "lightblue"
+CSS = """
+<STYLE TYPE="text/css">
+ body { font-size: 160%; }
+</STYLE>
+"""
+
+class HTMLDocument(list):
+ def __init__(self, ls = []):
+ super(HTMLDocument, self).__init__(ls)
+ self.reorder()
+ def reorder(self):
+ """Generates circular 'prev' and 'next' tabs."""
+ self.npages = len(self)
+ self.pageindex = []
+ for i, page in enumerate(self):
+ page.prev = self[i-1].namext
+ if i == self.npages-1: i = -1
+ page.next = self[i+1].namext
+ page.first = self[0].namext
+ page.last = self[-1].namext
+ page.document = self
+ self.pageindex.append(page)
+
+class HTMLPage(object):
+ def __init__(self, id_txt):
+ self.BGCOLOR = BGCOLOR
+ id, txt = id_txt
+ if isinstance(id, int):
+ self.name = "P%02d" % (id + 1)
+ else:
+ self.name = id
+ self.namext = self.name + ".html"
+ lines = txt.splitlines()
+ if lines: # empty page
+ self.title = lines[0]
+ self.txt = "\n".join(lines[2:])
+ else:
+ self.title = ""
+ self.txt = ""
+ self.txt = "<h1>%s</h1><br/>\n" % self.title + \
+ INCLUDE.sub(lambda m: "<pre>%s</pre>" %
+ file(m.group(1)).read(), self.txt)
+ self.head = """
+ <head>
+ <meta name="generator" content="Generated by Python">
+ <title>%s</title>
+ %s
+ </head>""" % (self.name, CSS)
+ def html(self):
+ self.body = """\n<body bgcolor="%(BGCOLOR)s">\n
+ %(txt)s
+ </body>
+ """ % vars(self)
+ return """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+ <html>%s\n</html>""" % (self.head + self.body)
+ def __str__(self):
+ box = TableList.make(
+ makelink(self.next, "Next"),
+ makelink(self.prev, "Prev"),
+ makelink(self.last, "Last"),
+ makelink(self.first, "First"),
+ "Current",
+ self.name,
+ border = 0,
+ color = BGCOLOR)
+ logo = TableList.col(
+ '<img src = "accu2005.png" alt = "logo">',
+ border = 0,
+ color = BGCOLOR)
+ links = [makelink(page.namext, page.name)
+ for page in self.document.pageindex]
+ opts = dict(border = 0, color = BGCOLOR, ncols=2)
+ index = TableList.make(*links, **opts)
+ self.txt = str(
+ TableList.row("<small>%s</small>" % TableList.col(box, index, logo,
+ border = 0, color = BGCOLOR),
+ self.txt, border = 0, color = BGCOLOR))
+ return self.html()
+ #return tidy(self.html(), "-i")[0]
+
+def main(fname):
+ BLANK = re.compile(r"\n\n\n\s*")
+ chunks = BLANK.split(file(fname).read())
+ pages = HTMLDocument(map(HTMLPage, enumerate(chunks)))
+ for page in pages:
+ print >> file(page.namext, "w"), page
+ #os.system("xterm -e elinks P01.html&")
+ webbrowser.open("file:%s/P01.html" % os.getcwd())
+
+if __name__ == "__main__":
+ main(sys.argv[1])
diff --git a/pypers/marelli/materiale/doctest_talk/more.txt b/pypers/marelli/materiale/doctest_talk/more.txt
new file mode 100755
index 0000000..0e0b7fc
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/more.txt
@@ -0,0 +1,33 @@
+
+Doctest and exceptions
+--------------------------------------
+
+<pre>
+
+>>> from partecs_voting import vote_validator
+>>> from partecs_voting.util import TheVoteIsClosedError
+>>> validate = vote_validator(
+... choices = ["A", "B", "C"],
+... OpeningDate = "Sun Aug 29 06:00:00 2004",
+... ClosingDate = "Sun Aug 30 22:00:00 2004")
+>>> try: # assuming you run this after Aug 29 2004
+... validate("A")
+... except TheVoteIsClosedError:
+... print "The vote is closed!"
+The vote is closed!
+
+</pre>
+
+Real example
+----------------------------------------------------------
+
+<pre>
+
+>>> from partecs_voting import make_ballot
+>>> ballot=make_ballot(["A", "B"], [["A"], ["A"], ["B"]], "BordaBallot")
+>>> print ballot.getresults()
+ALL RESULTS:
+A 2
+B 1
+
+</pre>
diff --git a/pypers/marelli/materiale/doctest_talk/refresh.txt b/pypers/marelli/materiale/doctest_talk/refresh.txt
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/refresh.txt
diff --git a/pypers/marelli/materiale/doctest_talk/split-failure.txt b/pypers/marelli/materiale/doctest_talk/split-failure.txt
new file mode 100755
index 0000000..0bce3e2
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/split-failure.txt
@@ -0,0 +1,5 @@
+An example of failed text:
+
+>>> from split import split
+>>> split("hello, world")
+['hello', ' world']
diff --git a/pypers/marelli/materiale/doctest_talk/split-failure_txt.py b/pypers/marelli/materiale/doctest_talk/split-failure_txt.py
new file mode 100755
index 0000000..6819fb5
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/split-failure_txt.py
@@ -0,0 +1,8 @@
+"""
+An example of failed text:
+
+>>> from split import split
+>>> split("hello, world")
+['hello', ' world']
+
+"""
diff --git a/pypers/marelli/materiale/doctest_talk/split.html b/pypers/marelli/materiale/doctest_talk/split.html
new file mode 100755
index 0000000..3cc867a
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/split.html
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.3.4: http://docutils.sourceforge.net/" />
+<title>Documentation for the 'split' module</title>
+<link rel="stylesheet" href="default.css" type="text/css" />
+</head>
+<body>
+<h1 class="title">Documentation for the 'split' module</h1>
+<div class="document" id="documentation-for-the-split-module">
+<p>The module contains a 'split' function, which
+splits a string taking as separators &quot;,&quot; and &quot;;&quot;.
+This is an example of usage:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; from split import split
+&gt;&gt;&gt; split(&quot;hello, world!; welcome to the Italian Code Jam!&quot;)
+['hello', 'world!', 'welcome to the Italian Code Jam!']
+</pre>
+<p>Notice that 'split' eats whitespaces:</p>
+<pre class="doctest-block">
+&gt;&gt;&gt; split(&quot;hello , world&quot;)
+['hello', 'world']
+</pre>
+<pre class="doctest-block">
+&gt;&gt;&gt; split(&quot;hello , ; world&quot;)
+['hello', '', 'world']
+</pre>
+</div>
+</body>
+</html>
diff --git a/pypers/marelli/materiale/doctest_talk/split.py b/pypers/marelli/materiale/doctest_talk/split.py
new file mode 100755
index 0000000..fda986c
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/split.py
@@ -0,0 +1,15 @@
+# split.py
+import re
+SEP = re.compile(r"\s*[,;]\s*")
+
+def split(text):
+ """Split a string taking as separators "," ";".
+ Example:
+ >>> from split import split
+ >>> split("hello, world!; welcome to PyUK!")
+ ['hello', 'world!', 'welcome to PyUK!']
+ """
+ return SEP.split(text)
+
+if __name__ == "__main__":
+ import doctest; doctest.testmod()
diff --git a/pypers/marelli/materiale/doctest_talk/split.txt b/pypers/marelli/materiale/doctest_talk/split.txt
new file mode 100755
index 0000000..8e3e8fe
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/split.txt
@@ -0,0 +1,18 @@
+Documentation for the 'split' module
+=====================================
+
+The module contains a 'split' function, which
+splits a string taking as separators "," and ";".
+This is an example of usage:
+
+>>> from split import split
+>>> split("hello, world!; welcome to the Italian Code Jam!")
+['hello', 'world!', 'welcome to the Italian Code Jam!']
+
+Notice that 'split' eats whitespaces:
+
+>>> split("hello , world")
+['hello', 'world']
+
+>>> split("hello , ; world")
+['hello', '', 'world']
diff --git a/pypers/marelli/materiale/doctest_talk/talk.txt b/pypers/marelli/materiale/doctest_talk/talk.txt
new file mode 100755
index 0000000..c3b2991
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/talk.txt
@@ -0,0 +1,403 @@
+Automatic testing in Python: wonderful doctest!
+===============================================
+
+<center>
+
+ ACCU Conference 2005 <br/> <br/>
+
+ 22 Apr 2005 <br/> <br/>
+
+ Michele Simionato <br/> <br/>
+
+ michele.simionato@gmail.com <br/> <br/>
+
+</center>
+
+
+Summary
+------------
+
+<ul>
+ <li> What is automatic testing? </li>
+ <li> Why automatic testing is better? </li>
+ <li> Which kind of automatic testing? </li>
+ <li> How does it work, in practice? </li>
+ <li> What's the message?</li>
+<ul>
+
+
+What is automatic testing
+-------------------------
+
+Any methodology that allows you to test
+your application mechanically, repeatedly
+and in a <em>controlled reproducible</em> way.
+
+
+Automatic testing is better (1)
+-----------------------------------
+
+When doing manual testing typically you spend
+
+<center><h2>
+
+ 1 hour of coding + 10 hours of testing/debugging
+
+</center></h2>
+
+on the other hand ...
+
+
+Automatic testing is better (2)
+-----------------------------------
+
+... when doing automatic testing typically you spend
+
+<br/> <br/>
+<center><h2>
+
+ 1 hour of coding + 10 hours of testing/debugging !
+
+</center></h2>
+
+
+However ...
+---------------------------------------
+
+Think about six month later!
+ <br/><br/>
+<center><em>
+
+ there is a difference</em>
+
+ <h2><u>Refactoring!</u><h2>
+
+</center>
+
+
+Automatic testing in Python
+-------------------------------
+
+There are two standard testing frameworks in Python:
+
+<ol>
+ <li> unittest </li>
+ <li> doctest </li>
+</ol>
+
+Which one should I use?
+
+
+Well,
+-------------------------
+
+since my talk has <em>doctest</em> in the title ...
+
+ ;-)
+
+
+More seriously ...
+--------------------------
+
+Use different testing frameworks; each one has advantages
+and disadvantages; use combinations of them; invent your
+own testing procedure.
+
+I use combinations of
+
+<ul>
+ <li> unittest </li>
+ <li> doctest </li>
+ <li> custom tests </li>
+ <li> Makefile driven tests </li>
+ <li> et al. </li>
+</ul>
+
+doctest emphasis is on <em>documentation</em>
+
+
+What is doctest?
+--------------------------------
+
+In its simplest form (which I do not use that much) doctest allows
+you to include tests in the docstrings of your application.
+
+
+Example
+-------
+
+.. include:: split.py
+
+
+Running doctest in verbose mode
+--------------------------------------------------------------------
+
+<pre>
+$ python split.py -v
+Running __main__.__doc__
+0 of 0 examples failed in __main__.__doc__
+Running __main__.split.__doc__
+Trying: from split import split
+Expecting: nothing
+ok
+Trying: split("hello, world!; welcome to Oxford!")
+Expecting: ['hello', 'world!', 'welcome to Oxford!']
+ok
+0 of 2 examples failed in __main__.split.__doc__
+1 items had no tests:
+ __main__
+1 items passed all tests:
+ 2 tests in __main__.split
+2 tests in 2 items.
+2 passed and 0 failed.
+Test passed.
+</pre>
+
+
+Why I do not use the docstring approach
+-------------------------------------------------------
+
+<ul>
+<li> It makes you end up with very large docstrings</li>
+
+<li> It abuses the original purpose of docstrings</li>
+
+<li> It conflates two different aspects (code and tests on the code)</li>
+
+<li> It is much easier to write the documentation in a separate
+ text file </li>
+
+<li> Testing should be done by an external tool anyway </li>
+</ul>
+
+
+How I use doctest
+---------------------
+
+I hacked inside doctest and wrote a custom utility
+to extract doctests from documentation files since
+
+<ul>
+ <li>I like keeping the documentation on a separate rst file</li>
+
+ <li>there is no sync problem since you run the tests all the time</li>
+
+ <li>it is useful for writing articles ...</li>
+
+ <li> ... but also documentation for internal usage in the company</li>
+</ul>
+
+http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/410052
+
+<pre>
+$ python -m doctester < split.txt
+doctest: run 4 tests, failed 0
+</pre>
+
+
+Testing the doctester frontend
+--------------------------------------------------
+
+<pre>
+>>> from ms.webtester import start_server, stop_server
+>>> from ms.http_utils import urlopen
+>>> baseurl = "http://localhost:7080/"
+>>> home = "/home/micheles/md/python/quixote/"
+
+>>> start_server(home + "doctester_frontend.py")
+>>> import time; time.sleep(2) # wait a bit
+
+Making a POST:
+
+>>> res = urlopen(baseurl, dict(txt=">>> 1 + 1\n2")).read()
+>>> assert "tests" in res
+>>> stop_server()
+
+</pre>
+
+
+Managing exceptions
+--------------------------------------------------------------
+
+It is possible to test that your program raises the exception you
+expect:
+
+<pre>
+
+$ echo "# split cannot work on a list
+>>> from split import split
+>>> split([])
+Traceback (most recent call last):
+ ...
+TypeError: expected string or buffer
+" > x.txt
+
+$ doct x.txt
+x.txt: 2 tests passed in 0.01 seconds
+
+</pre>
+
+(notice however that relying on exception messages may be risky)
+
+
+When tests fail
+-----------------------------------------------------------------
+
+<pre>
+
+$ cat split-failure.txt
+An example of failed text:
+
+>>> from split import split
+>>> split("hello, world")
+['hello', ' world']
+
+$ doct split-failure.txt
+*****************************************************************
+Failure in example: split("hello, world")
+from line #5 of split-failure.txt
+Expected: ['hello', ' world']
+Got: ['hello', 'world']
+
+</pre>
+
+
+Converting doctests to unittests
+------------------------------------------------------------------
+
+<pre>
+ import unittest
+ import doctest
+ import my_module_with_doctests
+
+ suite = doctest.DocTestSuite(my_module_with_doctests)
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
+</pre>
+
+<h2>For Python 2.3+<h2>
+
+
+doctest is becoming even better
+----------------------------------------------------
+
+With Python 2.4 you can run doctests on external text files:
+
+<pre>
+ import doctest, unittest
+ doctest.testfile(my_documentation_file, package=mypackage)
+</pre>
+
+you can also convert these doctests into unittests:
+
+<pre>
+ import doctest, unittest
+ suite = doctest.DocFileSuite(my_documentation_file, package=mypackage)
+ unittest.TextTestRunner().run(suite)
+</pre>
+
+
+Python 2.4 recognizes blank lines
+--------------------------------------------------------------
+
+Blank lines can be marked with &lt;BLANKLINE&gt; :
+<pre>
+>>> print 'foo\n\nbar\n'
+foo
+&lt;BLANKLINE&gt;
+bar
+&lt;BLANKLINE&gt;
+
+</pre>
+
+
+Python 2.4 recognizes flags!
+--------------------------------------------------------------
+
+<ul>
+<li> If the ellipsis flag is used, then '...' can be used to
+ elide substrings in the desired output: <pre>
+>>> print range(1000) #doctest: +ELLIPSIS
+[0, 1, 2, ..., 999]
+
+</pre></li>
+
+<li>
+ If the whitespace normalization flag is used, then
+ differences in whitespace are ignored.<pre>
+>>> print range(20) #doctest: +NORMALIZE_WHITESPACE
+[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+12, 13, 14, 15, 16, 17, 18, 19]
+
+</pre></li>
+
+</ul>
+
+
+Zope experience
+----------------------------------------------------------------
+
+Literal quote from the PyCON doctest talk:
+
+<ul>
+<li> ~ 5600 tests (~3500 in Zope 3, ~1300 in ZODB, ~800 in Zope 2)</li>
+<li> we wrote lots of tests before we knew what we were doing</li>
+<li> debugging failed tests is really hard when intent is unclear</li>
+<li> often refactor or reimplement tests to make them clearer</li>
+<li> most new tests are doctest based</li>
+</ul>
+
+
+Conclusion (1): good reasons to use doctest
+-----------------------------------------------------------
+
+<quote>
+"Test coverage is important, but test readability is much more important"
+</quote>
+
+<em>-- Tim Peters and Jim Fulton</em> <br/> <br/>
+
+doctest is good since:
+
+<ol>
+ <li> it is easy to understand, to explain and to use </li>
+
+ <li> it makes you improve the quality of your documentation </li>
+
+ <li> it can be converted to unittest anyway </li>
+
+</ol>
+
+
+Conclusion (2): the message of this talk
+-----------------------------------------------------------
+
+Automatic testing is good for tons of practical reasons, but also
+because:
+
+<ol>
+
+<li>It teaches you <em>discipline</em> </li>
+
+<li>It makes you
+ <em>think differently</em> </li>
+
+<li>It is more <em>fun!</em> </li>
+
+</ol>
+
+
+References
+-----------------------------------------------------------
+
+<ul>
+
+<li>The standard library documentation
+http://docs.python.org/lib/module-doctest.html </li>
+
+<li> The doctest talk by Tim Peters and Jim Fulton
+http://www.python.org/pycon/dc2004/papers/4/</li>
+
+<li> doctest.py <em>(use the source, Luke!)</em></li>
+</ul>
+
diff --git a/pypers/marelli/materiale/doctest_talk/test_pkg/__init__.py b/pypers/marelli/materiale/doctest_talk/test_pkg/__init__.py
new file mode 100755
index 0000000..3963e63
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/test_pkg/__init__.py
@@ -0,0 +1,6 @@
+"""Trying to doctest a package.
+
+>>> 1 + 1 == 2
+True
+
+"""
diff --git a/pypers/marelli/materiale/doctest_talk/test_pkg/a.py b/pypers/marelli/materiale/doctest_talk/test_pkg/a.py
new file mode 100755
index 0000000..ef2abf0
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/test_pkg/a.py
@@ -0,0 +1,7 @@
+"""
+Module a
+
+>>> 1 + 1 == 2
+True
+
+"""
diff --git a/pypers/marelli/materiale/doctest_talk/test_pkg/b.py b/pypers/marelli/materiale/doctest_talk/test_pkg/b.py
new file mode 100755
index 0000000..f17cd98
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/test_pkg/b.py
@@ -0,0 +1,7 @@
+"""
+Module b
+
+>>> 1 + 1 == 2
+True
+
+"""
diff --git a/pypers/marelli/materiale/doctest_talk/testfile_ex.py b/pypers/marelli/materiale/doctest_talk/testfile_ex.py
new file mode 100755
index 0000000..3d85fcc
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/testfile_ex.py
@@ -0,0 +1,11 @@
+import doctest, unittest
+suite = doctest.DocFileSuite("example.txt", package='ms.test')
+unittest.TextTestRunner().run(suite)
+
+# alternatively
+
+#import types
+#f = file("/home/micheles/md/scripts/ms/test/example.txt")
+#mod = types.ModuleType("example", f.read())
+#suite = doctest.DocTestSuite(mod)
+#unittest.TextTestRunner().run(suite)
diff --git a/pypers/marelli/materiale/doctest_talk/the_story.txt b/pypers/marelli/materiale/doctest_talk/the_story.txt
new file mode 100755
index 0000000..ccdbdbd
--- /dev/null
+++ b/pypers/marelli/materiale/doctest_talk/the_story.txt
@@ -0,0 +1,23 @@
+- a physicist perspective
+- the story of this talk
+- making the slides
+- what I wanted to realize
+- shallow knowledge
+- browser requirements
+- a word about security
+- the preparation of my lectures
+- emacs
+- importance of documentation
+- the right mindset
+- the doctester at work
+- real life experience with outsourcing
+- if you want to start a new company ...
+- /home/micheles/code/branches/1.3/lib/python/partecs_voting/tests
+- doctest vs. unittest
+- show the slides till page 6
+- a word about converting to testing methodologies
+- doctesting web applications
+- doctest 2 unittest
+- zope experience
+- cleverness vs. wisdom
+- three things to remember
diff --git a/pypers/marelli/materiale/doctester.py b/pypers/marelli/materiale/doctester.py
new file mode 100755
index 0000000..e759e5b
--- /dev/null
+++ b/pypers/marelli/materiale/doctester.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python2.4
+# Author: michele.simionato@gmail.com
+"""\
+Example of usage:
+$ doctester.py -v file.txt
+"""
+import sys, doctest, textwrap, re, types
+#import warnings;warnings.filterwarnings('ignore', category=DeprecationWarning)
+
+# regular expressions to identify code blocks of the form
+#<scriptname.py> ... </scriptname.py>
+DOTNAME = r'\b[a-zA-Z_][\w\.]*', # identifier with or without dots
+SCRIPT = re.compile(r'(?s)#<(%s)>(.*?)#</\1>' % DOTNAME)
+
+class file_(file):
+ """This is a file class which treats specially the filename "-",
+ returning stdin or stdout according to the mode."""
+ def __new__(cls, name, mode="r", buffering=1):
+ if name == "-" and "w" in mode or "a" in mode:
+ return sys.stdout
+ elif name == "-" and "r" in mode:
+ return sys.stdin
+ return super(file_, cls).__new__(cls, name, mode, buffering)
+
+# a simple utility to extract the scripts contained in the original text
+def scripts(txt):
+ for MO in SCRIPT.finditer(txt):
+ yield MO.group(1), textwrap.dedent(MO.group(2))
+
+# save the scripts in the current directory
+def savescripts(fname, txt):
+ scriptdict = {}
+ for scriptname, script in scripts(txt): # read scripts
+ if scriptname not in scriptdict:
+ scriptdict[scriptname] = script
+ else:
+ scriptdict[scriptname] += script
+ for scriptname in scriptdict: # save scripts
+ code = '# ' + scriptname + scriptdict[scriptname]
+ print >> file(scriptname, 'w'), code
+ return scriptdict
+
+# based on a clever trick: converts the original text into the docstring of
+# the _main module; works both for Python 2.3 and 2.4; threads work properly
+# too.
+
+def runtests(fname, txt, verbose=False):
+ if "_main.py" in savescripts(fname, txt):
+ _main = __import__("_main") # real module
+ else: # dynamic module
+ _main = types.ModuleType("__main__")
+ _main.__doc__ = txt
+ failed, tot = doctest.testmod(_main, verbose=verbose)
+ doctest.master = None # cleanup the DocTestRunner
+ # needed to avoid a warning in case of multiple calls of runtests
+ if not verbose:
+ print >> sys.stderr, "doctest: run %s tests, failed %s" % (tot, failed)
+ # remove scripts
+ return failed, tot
+
+if __name__ == '__main__':
+ try: set # need sets for option parsing
+ except NameError: import sets; set = sets.Set # for Python 2.3
+ try: fname = sys.argv[1]
+ except IndexError: sys.exit(__doc__)
+ valid_options = set("-v -h".split())
+ options = set(sys.argv[2:])
+ assert options < valid_options, "Unrecognized option"
+ if "-h" in options: # print usage message and exit
+ sys.exit(__doc__)
+ runtests(fname, file_(fname).read(), "-v" in options)
diff --git a/pypers/marelli/materiale/esempio1.py b/pypers/marelli/materiale/esempio1.py
new file mode 100755
index 0000000..61eb4b0
--- /dev/null
+++ b/pypers/marelli/materiale/esempio1.py
@@ -0,0 +1,20 @@
+# esempio1.py
+
+import threading, time, sys
+
+def print_hello():
+ for i in range(10):
+ print "hello"
+ if i == 5:
+ raise RuntimeError("Problema a runtime")
+ time.sleep(1)
+
+def print_world():
+ for i in range(10):
+ print "world"
+ time.sleep(1)
+
+threading.Thread(target=print_hello).start()
+threading.Thread(target=print_world).start()
+
+
diff --git a/pypers/marelli/materiale/esempio_banale.py b/pypers/marelli/materiale/esempio_banale.py
new file mode 100755
index 0000000..bdc14d1
--- /dev/null
+++ b/pypers/marelli/materiale/esempio_banale.py
@@ -0,0 +1,12 @@
+# esempio_banale.py
+
+def sum12():
+ """Questa funzione ritorna la somma di 1 + 2::
+ >>> sum12()
+ 3"""
+ return 1+2
+
+if __name__ == "__main__":
+ import doctest; doctest.testmod()
+
+
diff --git a/pypers/marelli/materiale/example.py b/pypers/marelli/materiale/example.py
new file mode 100755
index 0000000..10da18f
--- /dev/null
+++ b/pypers/marelli/materiale/example.py
@@ -0,0 +1,4 @@
+import exc_debug
+a = 1
+b = 0
+a/b
diff --git a/pypers/marelli/materiale/exc_debug.py b/pypers/marelli/materiale/exc_debug.py
new file mode 100755
index 0000000..32d507c
--- /dev/null
+++ b/pypers/marelli/materiale/exc_debug.py
@@ -0,0 +1,19 @@
+# recipe in the Python cookbook first edition, chapter 14.5
+
+import sys
+
+def info(type, value, tb):
+ if hasattr(sys, 'ps1') or not sys.stderr.isatty() or \
+ type == SyntaxError:
+ # we are in interactive mode or we don't have a tty-like
+ # device, so we call the default hook
+ sys.__excepthook__(type, value, tb)
+ else:
+ import traceback, pdb
+ # we are NOT in interactive mode, print the exception...
+ traceback.print_exception(type, value, tb)
+ print
+ # ...then start the debugger in post-mortem mode.
+ pdb.pm()
+
+sys.excepthook = info
diff --git a/pypers/marelli/materiale/gentable.py b/pypers/marelli/materiale/gentable.py
new file mode 100755
index 0000000..cf1c3cf
--- /dev/null
+++ b/pypers/marelli/materiale/gentable.py
@@ -0,0 +1,17 @@
+# gentable.py
+
+def gentable(N):
+ for i in range(1, N+1):
+ for j in range(1, N+1):
+ yield i*j
+
+def printtable(lst, N):
+ for i, el in enumerate(lst):
+ print "%4d" % el,
+ if (i+1) % 10 == 0:
+ print
+
+if __name__ == "__main__":
+ printtable(gentable(10), 10)
+
+
diff --git a/pypers/marelli/materiale/getattr_ex.py b/pypers/marelli/materiale/getattr_ex.py
new file mode 100755
index 0000000..0140ea4
--- /dev/null
+++ b/pypers/marelli/materiale/getattr_ex.py
@@ -0,0 +1,14 @@
+# getattr_ex.py
+
+class C(object):
+ def m1(self):
+ print "chiamato m1"
+ def m2(self):
+ print "chiamato m2"
+
+if __name__ == "__main__":
+ c = C()
+ method = raw_input("Che metodo devo chiamare? [m1 o m2] ")
+ getattr(c, method)()
+
+
diff --git a/pypers/marelli/materiale/isnumber.py b/pypers/marelli/materiale/isnumber.py
new file mode 100755
index 0000000..024665c
--- /dev/null
+++ b/pypers/marelli/materiale/isnumber.py
@@ -0,0 +1,12 @@
+# isnumber.py
+
+def is_number(arg):
+ "Verifica se la stringa arg è un numero valido"
+ try:
+ float(arg)
+ except ValueError:
+ return False
+ else:
+ return True
+
+
diff --git a/pypers/marelli/materiale/main.py b/pypers/marelli/materiale/main.py
new file mode 100755
index 0000000..c1495a5
--- /dev/null
+++ b/pypers/marelli/materiale/main.py
@@ -0,0 +1,14 @@
+# main.py
+
+"Chiama due processi proc1a.py e proc1b.py"
+
+import subprocess
+
+CMD_a = ["python", "-c", "import proc1a; proc1a.main()"]
+CMD_b = ["python", "-c", "import proc1b; proc1b.main()"]
+
+if __name__ == "__main__":
+ p_a = subprocess.Popen(CMD_a)
+ p_b = subprocess.Popen(CMD_b)
+
+
diff --git a/pypers/marelli/materiale/maketable.py b/pypers/marelli/materiale/maketable.py
new file mode 100755
index 0000000..f950293
--- /dev/null
+++ b/pypers/marelli/materiale/maketable.py
@@ -0,0 +1,67 @@
+# maketable.py
+
+# non graphic
+N = 10
+for i in range(1, N+1):
+ for j in range(1, N+1):
+ print "%4d" % (i*j),
+ print
+
+# HTML
+def maketable(iterable, N):
+ iterable = iter(iterable)
+ print "<table border='1'>"
+ stop = False
+ while not stop:
+ print "<tr>"
+ for j in range(1, N+1):
+ try:
+ print "<td>%s</td>" % iterable.next(),
+ except StopIteration:
+ print "<td></td>"
+ stop = True
+ print "</tr>"
+ print "</table>"
+
+import tempfile, webbrowser, os, sys
+
+def showtable(iterable, N):
+ stdout = sys.stdout # shows how to redirect stdout correctly
+ fd, name = tempfile.mkstemp(suffix=".html")
+ sys.stdout = os.fdopen(fd, "w")
+ maketable(iterable, N)
+ webbrowser.open(name)
+ sys.stdout = stdout
+
+showtable((i*j for j in range(1, N+1) for i in range(1, N+1)), N)
+
+
+
+def get_files_with_ext(ext, d):
+ """
+ ext can be a string or a set of strings; for instance
+ get_files_with_ext(".png") or get_files_with_ext(set(".png", ".gif"))
+ """
+ if not isinstance(ext, set):
+ ext_set = set([ext])
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ if ext.lower() in ext_set:
+ yield os.path.join(cwd, f)
+
+class Picture(object):
+ """An example of the utility of __str__"""
+ def __init__(self, pathname):
+ self.pathname = pathname
+ self.name = os.path.basename(pathname)
+ def __str__(self):
+ return "<img src=%r width=100>" % self.pathname
+
+if sys.platform == 'win32':
+ drive = "C:\\"
+else:
+ drive = "/"
+showtable(map(Picture, get_files_with_ext(".jpg", drive)), N)
+
+
diff --git a/pypers/marelli/materiale/proc1a.py b/pypers/marelli/materiale/proc1a.py
new file mode 100755
index 0000000..5402c7d
--- /dev/null
+++ b/pypers/marelli/materiale/proc1a.py
@@ -0,0 +1,13 @@
+# proc1a.py
+
+import time
+
+def main():
+ for i in range(10):
+ print "hello"
+ time.sleep(1)
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/pypers/marelli/materiale/proc1b.py b/pypers/marelli/materiale/proc1b.py
new file mode 100755
index 0000000..5d290d2
--- /dev/null
+++ b/pypers/marelli/materiale/proc1b.py
@@ -0,0 +1,20 @@
+# proc1b.py
+
+import time, sys
+
+def main():
+ try:
+ f = file("proc1b.py")
+ for i in range(10):
+ print "world"
+ if i == 5:
+ raise RuntimeError("Ahia!")
+ time.sleep(1)
+ finally:
+ f.close()
+ print "Il file è stato chiuso correttamente."
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/pypers/marelli/materiale/proc2a.py b/pypers/marelli/materiale/proc2a.py
new file mode 100755
index 0000000..565b1b1
--- /dev/null
+++ b/pypers/marelli/materiale/proc2a.py
@@ -0,0 +1,17 @@
+# proc2a.py
+"Un processo che genera numeri casuali e li salva nel file data.txt"
+
+import random
+
+def main():
+ ro = random.Random()
+ out = file("data.txt", "w")
+ for number in ro.sample(range(1000), 100):
+ print >> out, number
+ out.close()
+ print "Dati salvati sul file 'data.txt'"
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/pypers/marelli/materiale/proc2b.py b/pypers/marelli/materiale/proc2b.py
new file mode 100755
index 0000000..19ae87c
--- /dev/null
+++ b/pypers/marelli/materiale/proc2b.py
@@ -0,0 +1,15 @@
+# proc2b.py
+
+"Un processo che genera l'istogramma histo.png dai dati in data.txt"
+
+from pylab import hist,savefig
+
+def main():
+ hist([int(n) for n in file("dat.txt")], 10)
+ savefig("histo.png")
+ print "Istogramma salvato sul file 'histo.png'"
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/pypers/marelli/materiale/test_exc.py b/pypers/marelli/materiale/test_exc.py
new file mode 100755
index 0000000..1a71452
--- /dev/null
+++ b/pypers/marelli/materiale/test_exc.py
@@ -0,0 +1,20 @@
+# test_exc.py
+
+import unittest
+
+def divide(a, b):
+ return a/b
+
+class TestIsNumber(unittest.TestCase):
+ def test_1(self):
+ "Divide 4/2"
+ self.assertEqual(divide(4,2), 2)
+ def test_2(self):
+ "Divide 4/0"
+ self.assertRaises(ZeroDivisionError, divide, 4, 0)
+
+
+if __name__ == "__main__":
+ unittest.main()
+
+
diff --git a/pypers/marelli/materiale/test_isnumber.py b/pypers/marelli/materiale/test_isnumber.py
new file mode 100755
index 0000000..f5acbf2
--- /dev/null
+++ b/pypers/marelli/materiale/test_isnumber.py
@@ -0,0 +1,43 @@
+# test_isnumber.py
+
+import unittest
+
+from isnumber import is_number
+
+class TestIsNumber(unittest.TestCase):
+
+ def setUp(self):
+ print "sto inizializzando"
+
+ # test positivi
+ def test_1(self):
+ "Testa che '1' è un numero buono."
+ self.assertTrue(is_number("1"))
+ def test_2(self):
+ "Testa che '1.3' è un numero buono."
+ self.assertTrue(is_number("1.3"))
+ def test_3(self):
+ "Testa che '+1.3' è un numero buono."
+ self.assertTrue(is_number("+1.3"))
+ def test_4(self):
+ "Testa che '-1.3' è un numero buono."
+ self.assertTrue(is_number("-1.3"))
+
+ # test negativi
+ def test_5(self):
+ "Testa che '1-.3' non è un numero buono."
+ self.assertFalse(is_number("1-.3"))
+ def test_6(self):
+ "Testa che 'à non è un numero buono."
+ self.assertFalse(is_number("a"))
+ def test_7(self):
+ "Testa che '42' è un numero buono."
+ self.assertTrue(is_number("42"))
+
+ def tearDown(self):
+ print "Sto chiudendo quello che c'è da chiudere"
+
+if __name__ == "__main__":
+ unittest.main()
+
+
diff --git a/pypers/marelli/materiale/twisted_main.py b/pypers/marelli/materiale/twisted_main.py
new file mode 100755
index 0000000..116852f
--- /dev/null
+++ b/pypers/marelli/materiale/twisted_main.py
@@ -0,0 +1,37 @@
+# twisted_main.py
+
+"Il main che chiama proc2a.py e proc2b.py nell'ordine e gestisce gli errori"
+
+import webbrowser, sys
+if sys.platform == "win32":
+ from twisted.internet import win32eventreactor
+ win32eventreactor.install()
+
+from twisted.internet.utils import getProcessOutput
+from twisted.internet import reactor
+
+def scrivi_messaggio(err):
+ print err.getErrorMessage()
+ reactor.stop()
+ import pdb; pdb.set_trace() # fa partire il debugger in caso di errore
+
+def visualizza_histo(out_di_genera_histo):
+ print out_di_genera_histo
+ webbrowser.open("histo.png")
+
+def genera_histo(out_di_genera_dati):
+ print out_di_genera_dati
+ getProcessOutput(sys.executable, (r"c:\corso\processi\proc2b.py",)) \
+ .addCallback(visualizza_histo) \
+ .addErrback(scrivi_messaggio)
+
+def genera_dati():
+ getProcessOutput(sys.executable, (r"c:\corso\processi\proc2a.py",)) \
+ .addCallback(genera_histo) \
+ .addErrback(scrivi_messaggio)
+
+if __name__ == "__main__":
+ reactor.callLater(0, genera_dati) # call "genera_dati" after 0 seconds
+ reactor.run()
+
+
diff --git a/pypers/marelli/modulo1/debug_me.py b/pypers/marelli/modulo1/debug_me.py
new file mode 100755
index 0000000..d3e0e81
--- /dev/null
+++ b/pypers/marelli/modulo1/debug_me.py
@@ -0,0 +1,9 @@
+def f():
+ print "step 1"
+ print "step 2"
+ print "step 3"
+
+f()
+print "step 4"
+print "step 5"
+print "step 6"
diff --git a/pypers/marelli/modulo1/try_finally.py b/pypers/marelli/modulo1/try_finally.py
new file mode 100755
index 0000000..ca512a4
--- /dev/null
+++ b/pypers/marelli/modulo1/try_finally.py
@@ -0,0 +1,17 @@
+"""
+How try .. finally works:
+CTRL-C is caught, CTRL-Break is NOT
+"""
+import time
+F = "x.txt"
+
+f = file(F, "w")
+try:
+ for i in range(10):
+ print >> f, "line %s" % (i + 1)
+ time.sleep(1)
+finally:
+ f.close()
+ print "File %r was closed correctly. Current content:" % F
+ for line in file(F): print line,
+
diff --git a/pypers/marelli/modulo1/x.txt b/pypers/marelli/modulo1/x.txt
new file mode 100755
index 0000000..fc287e2
--- /dev/null
+++ b/pypers/marelli/modulo1/x.txt
@@ -0,0 +1,7 @@
+line 1
+line 2
+line 3
+line 4
+line 5
+line 6
+line 7
diff --git a/pypers/marelli/modulo2/TestLauncher.py b/pypers/marelli/modulo2/TestLauncher.py
new file mode 100755
index 0000000..f11a6b4
--- /dev/null
+++ b/pypers/marelli/modulo2/TestLauncher.py
@@ -0,0 +1,2902 @@
+#############################################################################################################
+# FILE: TestLauncher.py
+# AUTHOR: Alberto Mantovani
+# DATE: 16.07.2003
+# DESCRIPTION: Interfaccia grafica di lancio test
+# - individua i file descrittori dei TD
+# - crea l'interfaccia grafica relativa alle informazioni trovate
+# - lancia gli script che a loro volta lanciano i TD
+# - visualizza il risultato dei singoli TC
+#
+# REQUIREMENTS: file .txt descrittori dei TD
+# Ultimo Identificativo per pulsanti usato=156 (devono essere esclusi gli identificativi terminanti con 0 1 2)
+#
+# MODIFY
+# AUTHOR: Alberto Mantovani
+# DATE: 12.08.2003
+# DESCRIPTION: Al lancio dell'eseguibile viene creato un file path.py che contiene la costante LauncherPath
+# con il percorso appunto del launcher.
+# DATE: 03.10.2003
+# DESCRIPTION:
+# - I descrittori di files lay_descr.txt sono aperti solo in lettura e non anche in scrittura
+# - Nel combo del project non vengono visualizzati i files, e le cartelle del report e trash
+# - Pulsante per cancellare i moduli importati
+# - Pulsante per settare il path di lavoro
+# - Pulsante per cambiare gli stimoli
+# DATE: 22.12.2003
+# DESCRIPTION:
+# - Viene esteso il Launcher anche all'NSI Tester e predisposto per lo SPIL. Per fare ciò viene preso in considerazione e
+# anche il tag *INSTRUMENT presente nel lay_descr.txt. Le TD relative all'NSI saranno visualizzate in BLU
+# mentre rimarranno nere quelle del HIL. Quelle per lo SPIL sono in bianco.
+# Questo ha portato a modificare il file led_status.txt in quanto oltre alla lista dei LED vi è anche un flag
+# che segnala la fine della sessione per un certo strumento.
+# - E' stato aggiunto un pulsantino che permette di aprire il log. Rimane verde se non ci sono stati
+# problemi d'esecuzione, rosso altrimenti.
+# - La dimensione X del radiobox è stata fissata anzichè ottenerla automaticamente. In questo modo Test Case
+# dal nome lungo non deformano la grafica.
+# - Si fa un controllo sulla lunghezza del titolo della TD e se troppo lungo si diminuisce il font e si va a capo
+# - Messa icona di APOLLO13 nella barra del frame e compilando con l'opzione python setup.py py2exe --icon launcher.ico
+# si ottiene icona per l'eseguibile. (solo se si compila da NT o Win2000)
+# DATE: 22.12.2003
+# DESCRIPTION:
+# - E' cambiata la gestione del colore del pulsante di log. Per farlo diventare rosso si fa un confronto tra
+# lo stato dei led e i test selezionati. In questo modo il pulsante di log diventa rosso anche per i test di HIL
+# DATE: 28.03.2004
+# DESCRIPTION:
+# - Correzione baco : in modalità debug lancio il primo TD selezionato e non il primo assoluto
+# DATE: 06.04.2004
+# DESCRIPTION:
+# - Per i test NSI riconosco che c'è errore di compilazione se vedo diverso da 0 a sx di error(s) e non error
+# in quanto vi possono essere casi di ambiguità
+# - Se vi è un errore di sistema che fa colorare il log di rosso scrivo nel log TEST FALLITO
+#4.0.3 :
+# Modifica gestione errori in caso di errata lettura del file load
+# Correzione nome zip
+# Modifica nome cartella report (messo i campi di gg hh mm ss tra parentesi)
+#4.0.4 :
+# Passo alla setvar anche il path del progetto
+#4.0.5 :
+# Gestisco OL e CL passandolo alla MatStop
+# Creato pulsante nella finestra delle utility SPIL che converte gli output SPIL in output Matlab
+#4.0.6 :
+# Correzione Baco sulla selezione librerie di progetto
+#4.0.7 :
+# Settaggio variabile d'ambiente LIB x NSI in modalità RUN
+# Aggiunto path del launcher nel file command
+#4.0.8 :
+# Possibilità di scegliere l'opzione coverage
+# Lancio dello stimulus editor x SPIL
+# Correzione baco su scelta progetto nel caso delle utility SPIL
+# Creazione della cartella DD nel caso non esista
+#4.0.9 :
+# Nella modalità debug mancava un \n alla fine dell'IssStrtup.cmm
+#4.0.10 :
+# Gestione degli errori nella fase di pre-processing post-processing e SPIL
+#4.0.11 :
+# Anche in modalità debug scrivo nel report la parte di SETUP
+#4.0.12 :
+#-Aggiunta chekbox nel dSPACE che cancella i file .pyc se nella stessa cartella vi sono file omonimi
+#ma con estensione .py. La ricerca vieve effettuata nelle librerie, nei TD e nella cartella Work
+#-Messo nella configurazione dell'HIL il checkbox per ottenere la lista del NS di riferimento
+#-Aggiunta possibilità di ripetere la sequenza di test selezionati
+#-Correzione baco nel caso non vi sia il file degli IR
+#-Aggiunto pulsante SPIL x convertire pattern da STB a SDT
+#4.0.13 :
+#-Correzioni baco x l'iterzioni dei test
+#4.0.14 :
+#-Correzioni baco x il coverage quando non si sceglie il primo TC
+#4.0.15:
+#-Creazione del menù File in cui c'è l'opzione Exit
+#-Correzione path assoluto nello SPIL per il caricamento del load.cmm
+#4.0.16:
+#-Messa opzione Debug IDLE x dspace
+#4.0.17:
+#-Gestione diagnostica errori nel MatStrtp solo in fase RUN
+#4.0.18:
+#-Correzione baco nella gestione della ripetizione dei test (in realtà non funzionava). Il for è sulla RUN_TEST
+#anzichè essere su ogni strumento. La fine del test si ha quando sono finiti tutti gli strumenti e anche il
+#ciclo è finito. L'inizializzazione del file led_status.txt è fatto ad ogni ripetizione e quindi è stato sposta-
+#to nella RUN_TEST. Tra le altre modifiche la ripetizione non è abilitata in debug mode
+#-Ci si svincola completamente dal percorso M:\work
+#-Il browser dello stimulus editor dello SPIL diventa browser di file
+#-Il change stimulus dell'HIL si colloca nella directory del progetto
+#-Nel MatStrtp viene aggiunto il parametro CompareList nella IOCdiag
+#-Correzione scrittura nel log di test eseguiti o falliti x NSI
+#-
+############################################################################################################
+
+
+#################################################
+# INCLUDED FILES (libraries)
+#################################################
+import sys
+from wxPython.wx import*
+import threading
+import string
+import glob
+import os
+import time
+import traceback
+import shutil
+import stat
+import time
+import zipfile
+import win32api
+############################################################################################################
+# FUNCTION NAME : GetSpilTdData
+# FUNCTION DESCRIPTION:
+# Specificatamente per lo SPIL vengono creati automaticamente i campi di *MAIN,*TD e *TC prendendo le informazioni
+# dai nomi presenti nel TD
+#
+# INPUT PARAMETERS:
+# 1) TD: è il path della TD in cui si vanno a ricercare i files.
+#
+# OUTPUT PARAMETERS:
+# 1) TD aggiornato con i campi *MAIN *TD e *TC
+# es:['M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM08_4TV', 'SpilMainDummy', ['SM08','SM08_TP_01_in', 'SM08_TP_02_in']]
+############################################################################################################
+def GetSpilTdData(TD):
+ FileSearch=TD[0]+'\\*_TP_??_in.mat'
+ TClist=glob.glob(FileSearch)
+ tmp=[]
+ TDname=[]
+ for TCpath in TClist:
+ tmp.append(os.path.splitext(os.path.basename(TCpath))[0])
+ if tmp!=[]:
+ tmp.sort()
+ TDnamestp=string.find(tmp[-1],"_TP_")
+ TDname=[tmp[-1][0:TDnamestp]]
+ tmp=TDname+tmp
+ TD[1]=('SpilMainDummy')
+ TD.append(tmp)
+ else:
+ TD=[]
+ return TD
+
+
+
+############################################################################################################
+# FUNCTION NAME : TdParse
+# FUNCTION DESCRIPTION:
+# Vengono ricercati tutti i file che rispondono al path passato come argomento e analizzato il loro contenuto.
+# Questi files devono contenere le caratteristiche della TD per il layout grafico e il nome del file main della TD
+# Affinchè il TD sia trovato dal launcher, in ogni cartella TD deve esserci un file descrittore di TD es:lay_descr.txt
+#
+# INPUT PARAMETERS:
+# 1) file_path: è il path in cui si vanno a ricercare i files. (* è il simbolo jolly) es: "M:\Work\*\*\*\lay_descr.txt"
+#
+# OUTPUT PARAMETERS:
+# 1) TD_DATA: è la lista dei dati raccolti dal parse in generale è:
+# TD_DATA=[['TD1path','TD1main',["TD1 NAME","TC1 NAME","TC2 NAME",..,"TCn NAME"]],...,['TDmpath','TDmmain',["TDm NAME","TC1 NAME",...,"TCz NAME"]]]
+# -TDxpath è il path della TD
+# -TDxmain è il file main della TD
+# -TDx NAME è la label del TD
+# -TCx NAME è la label dei TC
+# raccoglie i dati di tutti gli strumenti presenti nell'ordine HIL,NSI,SPIL
+# 2) [0,RangeHIL,RangeNSI,RangeSPIL] poichè il TD_DATA non ha nessun riferimento a quali sono
+# i test relativi ad uno strumento piuttosto che ad un'altro occorre passare questo vettore che
+# indica per ogni strumento quali TD fanno capo. Se per es ci fossero 3 TD x HIL,2 TD x NSI,0 TD x SPIL
+# il vettore sarebbe [0,3,5,5]
+############################################################################################################
+
+def TdParse(file_path):
+ #main_list è la lista dei file descrittori trovati con il criterio del file_path (ogni cartella TD deve averne uno solo)
+ main_list=glob.glob(file_path)
+ #LEGGO IL FILE .TXT DI OGNI TD
+ TD_DATA=[] #raccoglitore globale sul quale viene costruito il layout
+ TD_DATA_HILdSPACE=[] #raccoglitore dei test su dspace
+ TD_DATA_NSI=[] #raccoglitore test su NSI
+ TD_DATA_SPIL=[] #raccoglitore test su SPIL
+ for mainpy in main_list:
+ #check flag che viene settato a 0 se il descrittore non è compilato correttamente per quanto riguarda le informazioni grafiche
+ check=1
+ #path della TD
+ path=os.path.dirname(mainpy)
+ f=open(mainpy,'r')
+ f.seek(0)
+ testo=f.read()
+ f.close()
+ TD=[path]
+
+ #Leggo il campo MAIN (file che viene lanciato dal launcher)
+ funzione_start=string.find(testo,"*MAIN=")
+ if funzione_start>=0 :
+ line_start=string.find(testo,"=",funzione_start)+1
+ line_stop=string.find(testo,"\n",line_start)
+ line=testo[line_start:line_stop]
+ TD=TD+[line]
+ else:
+ check=0
+
+ #Leggo il campo TD (label nome della TD)
+ TC=[]
+ td_start=string.find(testo,"*TD=")
+ if td_start>=0 :
+ line_start=string.find(testo,"=",td_start)+1
+ line_stop=string.find(testo,"\n",line_start)
+ line=testo[line_start:line_stop]
+ TC=TC+[line]
+ else:
+ check=0
+
+ #Leggo il campo TC (label nome della TC)
+ tc_start=0
+ while tc_start>=0:
+ tc_start=string.find(testo,"*TC=",tc_start+1)
+ if tc_start>=0 :
+ line_start=string.find(testo,"=",tc_start)+1
+ line_stop=string.find(testo,"\n",line_start)
+ line=testo[line_start:line_stop]
+ TC=TC+[line]
+ if len(TC)<=1:
+ check=0
+ TD.append(TC)
+
+ #Leggo il campo INSTRUMENT e inserisco i dati raccolti nella lista del relativo strumento
+# if check==1:
+ funzione_start=string.find(testo,"*INSTRUMENT=")
+ if funzione_start>=0 :
+ line_start=string.find(testo,"=",funzione_start)+1
+ line_stop=string.find(testo,"\n",line_start)
+ line=testo[line_start:line_stop]
+ if check==1 or line=="SPIL":
+ if line=="HILdSPACE":
+ TD_DATA_HILdSPACE.append(TD)
+ elif line=="NSI":
+ TD_DATA_NSI.append(TD)
+ elif line=="SPIL":
+ TD=GetSpilTdData(TD)
+ if TD!=[]:
+ TD_DATA_SPIL.append(TD)
+ else:
+ print "TD ",path,"non importata in quanto strumento non riconosciuto \n(correggere campo *INSTRUMENT nel lay_descr.txt)"
+ else:
+ print "TD ",path,"non importata in quanto non trovati i campi *MAIN e/o *TD e/o *TC nel lay_descr.txt"
+ else:
+ print "TD ",path,"non importata in quanto campo INSTRUMENT nel lay_descr.txt non trovato"
+
+ #Metto in ordine i TD per strumento: prima HIL, poi NSI, poi SPIL
+ if len(TD_DATA_HILdSPACE)!=0:
+ TD_DATA=TD_DATA+TD_DATA_HILdSPACE
+ if len(TD_DATA_NSI)!=0:
+ TD_DATA=TD_DATA+TD_DATA_NSI
+ if len(TD_DATA_SPIL)!=0:
+ TD_DATA=TD_DATA+TD_DATA_SPIL
+ #ritorno il TD_DATA e anche una lista nella quale sono indicati i range dei TD strumento x strumento
+ RangeHIL=len(TD_DATA_HILdSPACE)
+ RangeNSI=RangeHIL+len(TD_DATA_NSI)
+ RangeSPIL=RangeNSI+len(TD_DATA_SPIL)
+ return TD_DATA,[0,RangeHIL,RangeNSI,RangeSPIL]
+
+
+
+############################################################################################################
+# FUNCTION NAME : SelectorFrame
+# FUNCTION DESCRIPTION: Creazione della finestra contenente i TD, i TC e i led
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def SelectorFrame(self):
+
+ #self.scmain.sc --> finestra con lo scroll
+ self.scmain.sc=wxScrolledWindow(self.scmain, -1,pos = (200,0), size = (self.ScreenWidth*1.3-200,self.ScreenHeight*1.3-20), style = wxHSCROLL | wxVSCROLL, name = "scrolledWindow")
+ self.scmain.sc.SetScrollbars(10, 10, 1000, 1000, xPos = 0, yPos = 0, noRefresh = FALSE)
+
+ #Caratteristiche grafiche
+ TDW=200 #larghezza TD*
+ #TCH=40 #altezza TC
+ LEDW=20 #larghezza led*
+ LEDH=20 #altezza led*
+ DXLED=165 #delta x led*
+ DYLED=15 #delta y led*
+ #DXTD=197 #delta x TD*
+ DXTD=200 #delta x TD*
+ DYTC=50 #delta y TC*
+ DXTC=5 #delta x TC*
+ SXTD=20 #start x TD*
+ SYTD=10 #start y TD*
+ TCALLW=50 #larghezza TCALL
+ TCALLH=20 #altezza TCALL
+ DYTCALL=60 #delta y TCALL
+ TCdefvalue=2 #posizione di default del radio
+ DYWIN=85 #spazio al di sotto dei TCALL
+ LEDdefvalue=0 #posizione di default del radio
+ sampleList = ['NO ', 'OL ', 'CL ']
+ font = wxFont(18, wxSWISS, wxNORMAL, wxNORMAL, False, "Arial")
+
+
+ #creo TD
+ posx=SXTD
+ posy=SYTD
+ for indexTD in range(len(self.TD_DATA)):
+ posy=SYTD
+ #self.scmain.sc.TDx --> finestra in cui x è il numero della TD considerataa
+ TDH=(len(self.TD_DATA[indexTD][2])-1)*DYTC+TCALLH+DYWIN
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+" = wxWindow(self.scmain.sc, -1, (posx,posy), (TDW,TDH), wxSUNKEN_BORDER)"
+ #es: self.scmain.sc.TD1 = wxWindow(self.scmain.sc, -1, (posx,posy), (TDW,TDH), wxSUNKEN_BORDER)
+ exec(str2exe)
+ #Se la lunghezza del nome della TD è> 15 allora rimpicciollisci e va a capo
+ if len(self.TD_DATA[indexTD][2][0])>14:
+ self.TD_DATA[indexTD][2][0]=self.TD_DATA[indexTD][2][0][:17]+"\\n"+self.TD_DATA[indexTD][2][0][17:]
+ font = wxFont(14, wxSWISS, wxNORMAL, wxNORMAL, False, "Arial")
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".textTD"+str(indexTD+1)+"=wxStaticText(self.scmain.sc.TD"+str(indexTD+1)+", -1, '"+self.TD_DATA[indexTD][2][0]+"', wxDefaultPosition, wxDefaultSize)"
+ #es: self.scmain.sc.TD1.textTD1 = =wxStaticText(self.scmain.sc.TD1, -1, "TD GLAM", wxDefaultPosition, wxDefaultSize)
+ exec(str2exe)
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".textTD"+str(indexTD+1)+".SetFont(font)"
+ #es: self.scmain.sc.TD1.textTD1.SetFont(font)
+ exec(str2exe)
+ #In base al tipo di strumento cambio il colore nella visualizzazione
+ #colore BLU per NSI
+ if self.TD_NumTdXInstr[1]<=indexTD<self.TD_NumTdXInstr[2]:
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".textTD"+str(indexTD+1)+".SetForegroundColour(wxBLUE)"
+ exec(str2exe)
+ #colore BIANCO per SPIL
+ if self.TD_NumTdXInstr[2]<=indexTD<self.TD_NumTdXInstr[3]:
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".textTD"+str(indexTD+1)+".SetForegroundColour(wxWHITE)"
+ exec(str2exe)
+
+
+ #creo radio TC e LED
+ for indexTC in range(len(self.TD_DATA[indexTD][2])-1):
+ posy=posy+DYTC
+ #self.scmain.sc.TDx.rby_x --> radiobutton dove x è il numero della TD y del TC considerato,
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".rb"+str(indexTC+1)+"_"+str(indexTD+1)+" = wxRadioBox(self.scmain.sc.TD"+str(indexTD+1)+", -1, '"+self.TD_DATA[indexTD][2][indexTC+1]+"', wxDefaultPosition, (155,-1),sampleList)"
+ #es: self.scmain.sc.TD1.rb1_1 = wxRadioBox(self.scmain.sc.TD1, -1, "tc name", wxDefaultPosition, wxDefaultSize,sampleList)
+ exec(str2exe)
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".rb"+str(indexTC+1)+"_"+str(indexTD+1)+".SetPosition((DXTC,posy))"
+ #es: self.scmain.sc.TD1.rb1_1.SetPosition((DXTC,posy))
+ exec(str2exe)
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".rb"+str(indexTC+1)+"_"+str(indexTD+1)+".SetSelection(2)"
+ #es: self.scmain.sc.TD1.rb1_1.SetSelection(2)
+ exec(str2exe)
+ #self.scmain.sc.TDx.ledy_x --> led dove x è il numero della TD y del TC considerato,
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".led"+str(indexTC+1)+"_"+str(indexTD+1)+" = wxWindow(self.scmain.sc.TD"+str(indexTD+1)+", -1, (DXLED,posy+DYLED), (LEDW,LEDH), wxSUNKEN_BORDER)"
+ #es: self.scmain.sc.TD1.led1_1 = wxWindow(self.scmain.sc.TD1, -1, (DXLED,posy+DYLED), (LEDW,LEDH), wxSUNKEN_BORDER)
+ exec(str2exe)
+ #colore BLU per NSI
+ if self.TD_NumTdXInstr[1]<=indexTD<self.TD_NumTdXInstr[2]:
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".rb"+str(indexTC+1)+"_"+str(indexTD+1)+".SetForegroundColour(wxBLUE)"
+ exec(str2exe)
+ #colore BIANCO per SPIL
+ if self.TD_NumTdXInstr[2]<=indexTD<self.TD_NumTdXInstr[3]:
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".rb"+str(indexTC+1)+"_"+str(indexTD+1)+".SetForegroundColour(wxWHITE)"
+ exec(str2exe)
+
+
+ #nox=xy --> dove x TD considerata e y è la funzione associata:0=NO, 1=OL, 2=CL
+ str2exe="no"+str(indexTD+1)+"="+str(indexTD+1)+"0"
+ #es: no1=10
+ exec(str2exe)
+ str2exe="ol"+str(indexTD+1)+"="+str(indexTD+1)+"1"
+ #es: ol1=11
+ exec(str2exe)
+ str2exe="cl"+str(indexTD+1)+"="+str(indexTD+1)+"2"
+ #es: cl1=12
+ exec(str2exe)
+
+ #creo pulsanti e relativi eventi per la selezione rapida nel TD
+ #NO
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".no"+str(indexTD+1)+"=wxButton(self.scmain.sc.TD"+str(indexTD+1)+", no"+str(indexTD+1)+",'NO',(DXTC,posy+DYTCALL),size=(TCALLW,TCALLH))"
+ #es: self.scmain.sc.TD1.no1=wxButton(self.scmain.sc.TD1, no1,'NO',(DXTC,posy+DYTCALL),size=(TCALLW,TCALLH))
+ exec(str2exe)
+ str2exe="EVT_BUTTON(self, no"+str(indexTD+1)+", self.EvtTcAll)"
+ #es: EVT_BUTTON(self, no1, self.EvtTcAll)
+ exec(str2exe)
+ #OL
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".ol"+str(indexTD+1)+"=wxButton(self.scmain.sc.TD"+str(indexTD+1)+", ol"+str(indexTD+1)+",'OL',(DXTC+TCALLW,posy+DYTCALL),size=(TCALLW,TCALLH))"
+ #es: self.scmain.sc.TD1.ol1 = wxButton(self.scmain.sc.TD1, ol1,'OL',(DXTC+TCALLW,posy+DYTCALL),size=(TCALLW,TCALLH))
+ exec(str2exe)
+ str2exe="EVT_BUTTON(self, ol"+str(indexTD+1)+", self.EvtTcAll)"
+ #es: EVT_BUTTON(self, ol1, self.EvtTcAll)
+ exec(str2exe)
+ #CL
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".cl"+str(indexTD+1)+"=wxButton(self.scmain.sc.TD"+str(indexTD+1)+", cl"+str(indexTD+1)+",'CL',(DXTC+2*TCALLW,posy+DYTCALL),size=(TCALLW,TCALLH))"
+ #es: self.scmain.sc.TD1.cl1 = wxButton(self.scmain.sc.TD1, cl1,'CL',(DXTC+2*TCALLW,posy+DYTCALL),size=(TCALLW,TCALLH))
+ exec(str2exe)
+ str2exe="EVT_BUTTON(self, cl"+str(indexTD+1)+", self.EvtTcAll)"
+ #es: EVT_BUTTON(self, cl1, self.EvtTcAll)
+ exec(str2exe)
+
+ posx=posx+DXTD
+
+
+
+############################################################################################################
+# FUNCTION NAME : TdBrowse
+# FUNCTION DESCRIPTION: Creazione di un box contenente la lista dei TD scaricati
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+#
+############################################################################################################
+def TdBrowse(self):
+ #compongo la lista prendendo le label dei descrittori di TD
+ self.TDlist=[]
+ for indexTD in self.TD_DATA:
+ self.TDlist.append(indexTD[2][0])
+ self.wnd.launcher.ch = wxListBox(self.wnd.launcher, 5, (5, 220),(150,100), choices = self.TDlist)
+ #setto evento della lista
+ EVT_LISTBOX(self, 5, self.EvtChoice)
+
+
+
+############################################################################################################
+# FUNCTION NAME : LauncherFrame
+# FUNCTION DESCRIPTION: Creazione di una finestra contenente:pulsante di GO, selezione globale dei TC, TdBrowse, selezione tipo ecu
+# Creazione pulsante GO
+# Creazione pulsanti NO OL CL
+# Creazione radiobox tipo di ecu
+# Creazione radiobox per modalità di lancio
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def LauncherFrame(self):
+ #Creazione finestra launcher
+ self.wnd.launcher = wxWindow(self.wnd, -1, (10,10), (170,400), wxSUNKEN_BORDER)
+ self.wnd.lbl=wxStaticText(self.wnd.launcher, -1," LAUNCHER", wxDefaultPosition, wxDefaultSize)
+ font = wxFont(18, wxSWISS, wxNORMAL, wxNORMAL, False, "Arial")
+ self.wnd.lbl.SetFont(font)
+ #Creazione radiobox per selezione tipo ecu
+ self.wnd.launcher.ECU = wxRadioBox(self.wnd.launcher, -1,"", (5,30), wxDefaultSize,["Ecu Svil.","Ecu Prod."])
+ #creazione pulsante GO
+ self.wnd.GO=wxButton(self.wnd.launcher, 3,'GO',pos=(5,80),size=(150,70))
+ EVT_BUTTON(self,3,self.EvtGO)
+ #Creazione SpinButton x ripetizione test
+ self.wnd.RptTestTxt = wxTextCtrl(self.wnd.launcher, 148, "1", wxPoint(65, 190), wxSize(30, 23))
+ self.wnd.RptTestSpn = wxSpinButton(self.wnd.launcher, 149, wxPoint(98, 190), wxSize(20, 22), wxSP_VERTICAL)
+ self.wnd.RptTestLbl = wxStaticText(self.wnd.launcher, -1, "Repeat for", pos=(5,195), size=(55,20),style=wxALIGN_LEFT)
+ self.wnd.RptTestLbl = wxStaticText(self.wnd.launcher, -1, "times", pos=(122,195), size=(25,20),style=wxALIGN_RIGHT)
+ self.wnd.RptTestSpn.SetRange(1, 100)
+ self.wnd.RptTestSpn.SetValue(1)
+ EVT_SPIN(self.wnd.RptTestSpn, 149, self.RptTest)
+ #creazione pulsante NO
+ self.wnd.launcher.NO=wxButton(self.wnd.launcher, 0,'NO',pos=(5,150),size=(50,30))
+ EVT_BUTTON(self,0,self.EvtTcAll)
+ #creazione pulsante OL
+ self.wnd.launcher.OL=wxButton(self.wnd.launcher, 1,'OL',pos=(55,150),size=(50,30))
+ EVT_BUTTON(self,1,self.EvtTcAll)
+ #creazione pulsante CL
+ self.wnd.launcher.CL=wxButton(self.wnd.launcher, 2,'CL',pos=(105,150),size=(50,30))
+ EVT_BUTTON(self,2,self.EvtTcAll)
+ #Creazione selettore per modalità di lancio run o debug
+ self.wnd.launcher.run = wxRadioBox(self.wnd.launcher, -1,"Launch Modality", (5,325), wxDefaultSize,["Run ","Debug "])
+ #Creazione del pulsanti di log
+ self.wnd.launcher.log=wxButton(self.wnd.launcher, 116,'Log',pos=(5,375),size=(25,15))
+ EVT_BUTTON(self,116,self.EvtLog)
+
+
+############################################################################################################
+# FUNCTION NAME : ReloadButton
+# FUNCTION DESCRIPTION: Creazione pulsante per il rinfresco della finestra del TD Selector
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def ReloadButton(self):
+ #RELOAD
+ self.wnd.reload=wxButton(self.wnd, 6,'RELOAD',pos=(5,470),size=(180,40))
+ EVT_BUTTON(self,6,self.EvtReload)
+
+############################################################################################################
+# FUNCTION NAME : MenuBar
+# FUNCTION DESCRIPTION: Creazione Menu per la configurazione dell'ambiente di lavoro
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def MenuBar(self):
+ menuBar = wxMenuBar()
+ # menu0 = File menu per Exit
+ menu0 = wxMenu()
+ menu0.Append(156, "&Exit Alt+F4", "")
+ # menu1 = General Set per settare il path dei progetti e dei files descrittori di TD
+ menu1 = wxMenu()
+ menu1.Append(108, "&Td Set...", "")
+ # menu2 = Instruments Set per settare i path dello strumento
+ menu2 = wxMenu()
+ menu2.Append(105, "&dSPACE HIL...", "")
+ menu2.Append(106, "&NSI...", "")
+ menu2.Append(107, "&SPIL...", "")
+ # Add menu to the menu bar
+ menuBar.Append(menu0, "&File")
+ menuBar.Append(menu1, "&General Set")
+ menuBar.Append(menu2, "&Instruments Set")
+ self.SetMenuBar(menuBar)
+ #setto eventi
+ EVT_MENU(self, 105, self.Configuration)
+ EVT_MENU(self, 108, self.Configuration)
+ EVT_MENU(self, 106, self.Configuration)
+ EVT_MENU(self, 107, self.Configuration)
+ EVT_MENU(self, 156, self.Configuration)
+############################################################################################################
+# FUNCTION NAME : PyConfig
+# FUNCTION DESCRIPTION: Creazione delle finestre di settaggio configurazione del python
+# -Python.exe
+# -Pythonwin.exe
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def PyConfig(self):
+ #creazione frame generale
+ self.PyConfigFrame=wxMiniFrame(None, -1, title="Hil Configuration", pos=(200,100), size=(500,300), style=wxDEFAULT_FRAME_STYLE)
+ self.PyConfigFrame.Panel = wxPanel(self.PyConfigFrame, -1,pos=(0,0), size=(500,300))
+ #creazione text control e browse di Python.exe
+ self.PyConfigFrame.Panel.PythonLabel = wxStaticText(self.PyConfigFrame.Panel, -1, "Python.exe:", pos=(5,7), size=(95,20),style=wxALIGN_RIGHT)
+ self.PyConfigFrame.Panel.PythonText = wxTextCtrl(self.PyConfigFrame.Panel, -1, self.PythonPath,pos=(100,5), size=(300, 20))
+ self.PyConfigFrame.Panel.PythonBrowse =wxButton(self.PyConfigFrame.Panel, 1, "...",pos=(405,5),size=(18,20))
+ EVT_BUTTON(self.PyConfigFrame.Panel.PythonBrowse, 1, self.OnBrowse)
+ #creazione text control e browse di Pythonwin.exe
+ self.PyConfigFrame.Panel.PythonwinLabel = wxStaticText(self.PyConfigFrame.Panel, -1, "Pythonwin.exe:\nidle.pyw:", pos=(5,40), size=(95,50),style=wxALIGN_CENTRE)
+ self.PyConfigFrame.Panel.PythonwinText = wxTextCtrl(self.PyConfigFrame.Panel, -1, self.PythonwinPath,pos=(100,45), size=(300, 20))
+ self.PyConfigFrame.Panel.PythonwinBrowse =wxButton(self.PyConfigFrame.Panel, 2, "...",pos=(405,45),size=(18,20))
+ EVT_BUTTON(self.PyConfigFrame.Panel.PythonwinBrowse, 2, self.OnBrowse)
+ #creazione pulsante per creazione del ClearNS
+ self.PyConfigFrame.Panel.CreateNSBox = wxCheckBox(self.PyConfigFrame.Panel, 147, "Generate Pythonwin NS reference (PythonWin must be down)", wxPoint(100, 80), wxSize(380, 30), wxNO_BORDER)
+ self.PyConfigFrame.Panel.CreateNSBox.SetValue(False)
+ #self.wnd.Develop.AddPage(self.wnd.Develop.Python, "dSPACE")
+
+
+ #self.PyConfigFrame.Panel.CreateNS=wxButton(self.PyConfigFrame.Panel, 147,'Create NS',pos=(150,100),size=(200,40))
+ #EVT_BUTTON(self.PyConfigFrame.Panel.CreateNS,147,self.CreateNS)
+ #creazione pulsante salvataggio
+ self.PyConfigFrame.Panel.SavePyConfig=wxButton(self.PyConfigFrame.Panel, 4,'Save Config',pos=(150,200),size=(200,40))
+ EVT_BUTTON(self.PyConfigFrame.Panel.SavePyConfig,4,self.SaveConfig)
+ self.PyConfigFrame.Show(1)
+
+
+
+############################################################################################################
+# FUNCTION NAME : GenConfig
+# FUNCTION DESCRIPTION: Creazione delle finestre di settaggio configurazione generale del launcher
+# - lay_descr.txt
+# - Project Dir
+# -PythonLib
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def GenConfig(self):
+ #creazione frame generale
+ self.GenConfigFrame=wxMiniFrame(None, -1, title="General Configuration", pos=(200,100), size=(500,300), style=wxDEFAULT_FRAME_STYLE)
+ self.GenConfigFrame.Panel = wxPanel(self.GenConfigFrame, -1,pos=(0,0), size=(500,300))
+ #creazione text control e browse di lay_descr.txt
+ self.GenConfigFrame.Panel.DescrLabel = wxStaticText(self.GenConfigFrame.Panel, -1, "lay_descr.txt:", pos=(5,87), size=(95,20),style=wxALIGN_RIGHT)
+ self.GenConfigFrame.Panel.DescrText = wxTextCtrl(self.GenConfigFrame.Panel, -1, self.DescrPath,pos=(100,85), size=(300, 20))
+ self.GenConfigFrame.Panel.DescrBrowse =wxButton(self.GenConfigFrame.Panel, 5, "...",pos=(405,85),size=(18,20))
+ EVT_BUTTON(self.GenConfigFrame.Panel.DescrBrowse, 5, self.OnBrowse)
+ #creazione text control e browse di Project Dir
+ self.GenConfigFrame.Panel.ProjLabel = wxStaticText(self.GenConfigFrame.Panel, -1, "Project Dir:", pos=(5,47), size=(95,20),style=wxALIGN_RIGHT)
+ self.GenConfigFrame.Panel.ProjText = wxTextCtrl(self.GenConfigFrame.Panel, -1, self.ProjPath,pos=(100,45), size=(300, 20))
+ self.GenConfigFrame.Panel.ProjBrowse =wxButton(self.GenConfigFrame.Panel, 7, "...",pos=(405,45),size=(18,20))
+ EVT_BUTTON(self.GenConfigFrame.Panel.ProjBrowse, 7, self.OnBrowse)
+ #creazione text control e browse di PythonLib
+ self.GenConfigFrame.Panel.PylibLabel = wxStaticText(self.GenConfigFrame.Panel, -1, "LibPath:", pos=(5,127), size=(95,20),style=wxALIGN_RIGHT)
+ self.GenConfigFrame.Panel.PylibText = wxTextCtrl(self.GenConfigFrame.Panel, -1, self.PylibPath,pos=(100,125), size=(300, 20))
+ self.GenConfigFrame.Panel.PylibBrowse =wxButton(self.GenConfigFrame.Panel, 3, "...",pos=(405,125),size=(18,20))
+ EVT_BUTTON(self.GenConfigFrame.Panel.PylibBrowse, 3, self.OnBrowse)
+ #creazione pulsante salvataggio
+ self.GenConfigFrame.Panel.SaveGenConfig=wxButton(self.GenConfigFrame.Panel, 6,'Save Config',pos=(150,200),size=(200,40))
+ EVT_BUTTON(self.GenConfigFrame.Panel.SaveGenConfig,6,self.SaveConfig)
+ self.GenConfigFrame.Show(1)
+
+############################################################################################################
+# FUNCTION NAME : NSIConfig
+# FUNCTION DESCRIPTION: Creazione delle finestre di settaggio configurazione dello strumento NSI
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def NSIConfig(self):
+ #creazione frame generale
+ self.NSIConfigFrame=wxMiniFrame(None, -1, title="NSI Configuration", pos=(200,100), size=(500,300), style=wxDEFAULT_FRAME_STYLE)
+ self.NSIConfigFrame.Panel = wxPanel(self.NSIConfigFrame, -1,pos=(0,0), size=(500,300))
+ #creazione text control e browse di MSDevDir
+ self.NSIConfigFrame.Panel.MSDevDirLabel = wxStaticText(self.NSIConfigFrame.Panel, -1, "MSDevDir:", pos=(5,37), size=(95,20),style=wxALIGN_RIGHT)
+ self.NSIConfigFrame.Panel.MSDevDirText = wxTextCtrl(self.NSIConfigFrame.Panel, -1, self.NSIMSDevDir,pos=(100,35), size=(300, 20))
+ self.NSIConfigFrame.Panel.MSDevDirBrowse =wxButton(self.NSIConfigFrame.Panel, 117, "...",pos=(405,35),size=(18,20))
+ EVT_BUTTON(self.NSIConfigFrame.Panel.MSDevDirBrowse, 117, self.OnBrowse)
+ #creazione text control e browse di MSVCDir
+ self.NSIConfigFrame.Panel.MSVCDirLabel = wxStaticText(self.NSIConfigFrame.Panel, -1, "MSVCDir:", pos=(5,87), size=(95,20),style=wxALIGN_RIGHT)
+ self.NSIConfigFrame.Panel.MSVCDirText = wxTextCtrl(self.NSIConfigFrame.Panel, -1, self.NSIMSVCDir,pos=(100,85), size=(300, 20))
+ self.NSIConfigFrame.Panel.MSVCDirBrowse =wxButton(self.NSIConfigFrame.Panel, 118, "...",pos=(405,85),size=(18,20))
+ EVT_BUTTON(self.NSIConfigFrame.Panel.MSVCDirBrowse, 118, self.OnBrowse)
+ #creazione text control e browse di NSIDir
+ self.NSIConfigFrame.Panel.NSIDirLabel = wxStaticText(self.NSIConfigFrame.Panel, -1, "NSIDir:", pos=(5,137), size=(95,20),style=wxALIGN_RIGHT)
+ self.NSIConfigFrame.Panel.NSIDirText = wxTextCtrl(self.NSIConfigFrame.Panel, -1, self.NSIDir,pos=(100,135), size=(300, 20))
+ self.NSIConfigFrame.Panel.NSIDirBrowse =wxButton(self.NSIConfigFrame.Panel, 123, "...",pos=(405,135),size=(18,20))
+ EVT_BUTTON(self.NSIConfigFrame.Panel.NSIDirBrowse, 123, self.OnBrowse)
+ #creazione pulsante salvataggio
+ self.NSIConfigFrame.Panel.SaveNSIConfigFrame=wxButton(self.NSIConfigFrame.Panel, 119,'Save Config',pos=(150,200),size=(200,40))
+ EVT_BUTTON(self.NSIConfigFrame.Panel.SaveNSIConfigFrame,119,self.SaveConfig)
+ self.NSIConfigFrame.Show(1)
+
+
+############################################################################################################
+# FUNCTION NAME : SPILConfig
+# FUNCTION DESCRIPTION: Creazione delle finestre di settaggio configurazione dello strumento SPIL
+# MatLabInstallation=r'C:\Programmi\matlab65p1\bin\win32\matlab.exe' #da configurazione
+# StartUpMatlabPath=r'C:\Programmi\matlab65p1\toolbox\local\startup' #da configurazione
+# IssInstallation=r'C:\Programmi\T32\T32M166.EXE' #da configurazione
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def SPILConfig(self):
+ #creazione frame generale
+ self.SPILConfigFrame=wxMiniFrame(None, -1, title="SPIL Configuration", pos=(200,100), size=(500,300), style=wxDEFAULT_FRAME_STYLE)
+ self.SPILConfigFrame.Panel = wxPanel(self.SPILConfigFrame, -1,pos=(0,0), size=(500,300))
+ #creazione text control e browse di MatlabInstallation
+ self.SPILConfigFrame.Panel.MtlbInstallLabel = wxStaticText(self.SPILConfigFrame.Panel, -1, "Matlab.exe:", pos=(5,37), size=(95,20),style=wxALIGN_RIGHT)
+ self.SPILConfigFrame.Panel.MtlbInstallText = wxTextCtrl(self.SPILConfigFrame.Panel, -1, self.MtlbInstall,pos=(100,35), size=(300, 20))
+ self.SPILConfigFrame.Panel.MtlbInstallBrowse =wxButton(self.SPILConfigFrame.Panel, 124, "...",pos=(405,35),size=(18,20))
+ EVT_BUTTON(self.SPILConfigFrame.Panel.MtlbInstallBrowse, 124, self.OnBrowse)
+ #creazione text control e browse di StartUpMatlabPath
+ self.SPILConfigFrame.Panel.StimulusLabel = wxStaticText(self.SPILConfigFrame.Panel, -1, "waveman.exe:", pos=(5,87), size=(95,20),style=wxALIGN_RIGHT)
+ self.SPILConfigFrame.Panel.StimulusText = wxTextCtrl(self.SPILConfigFrame.Panel, -1, self.Stimulus,pos=(100,85), size=(300, 20))
+ self.SPILConfigFrame.Panel.StimulusBrowse =wxButton(self.SPILConfigFrame.Panel, 125, "...",pos=(405,85),size=(18,20))
+ EVT_BUTTON(self.SPILConfigFrame.Panel.StimulusBrowse, 125, self.OnBrowse)
+ #creazione text control e browse di IssInstallation
+ self.SPILConfigFrame.Panel.IssInstallLabel = wxStaticText(self.SPILConfigFrame.Panel, -1, "T32xxx.exe:", pos=(5,137), size=(95,20),style=wxALIGN_RIGHT)
+ self.SPILConfigFrame.Panel.IssInstallText = wxTextCtrl(self.SPILConfigFrame.Panel, -1, self.IssInstall,pos=(100,135), size=(300, 20))
+ self.SPILConfigFrame.Panel.IssInstallBrowse =wxButton(self.SPILConfigFrame.Panel, 126, "...",pos=(405,135),size=(18,20))
+ EVT_BUTTON(self.SPILConfigFrame.Panel.IssInstallBrowse, 126, self.OnBrowse)
+ #creazione text control e browse di ReportSpil
+ self.SPILConfigFrame.Panel.ReportSpilLabel = wxStaticText(self.SPILConfigFrame.Panel, -1, "ReportDir:", pos=(5,187), size=(95,20),style=wxALIGN_RIGHT)
+ self.SPILConfigFrame.Panel.ReportSpilText = wxTextCtrl(self.SPILConfigFrame.Panel, -1, self.ReportSpil,pos=(100,185), size=(300, 20))
+ self.SPILConfigFrame.Panel.ReportSpilBrowse =wxButton(self.SPILConfigFrame.Panel, 128, "...",pos=(405,185),size=(18,20))
+ EVT_BUTTON(self.SPILConfigFrame.Panel.ReportSpilBrowse, 128, self.OnBrowse)
+
+ #creazione pulsante salvataggio
+ self.SPILConfigFrame.Panel.SaveSPILConfigFrame=wxButton(self.SPILConfigFrame.Panel, 127,'Save Config',pos=(150,230),size=(200,40))
+ EVT_BUTTON(self.SPILConfigFrame.Panel.SaveSPILConfigFrame,127,self.SaveConfig)
+ self.SPILConfigFrame.Show(1)
+
+
+############################################################################################################
+# FUNCTION NAME : ExitProc
+# FUNCTION DESCRIPTION: Processo di chiusura del Launcher
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def ExitProc(self):
+ self.Destroy()
+
+
+
+############################################################################################################
+# FUNCTION NAME : ProjectCombo
+# FUNCTION DESCRIPTION: Creazione di un combobox contenente i progetti scaricati. Nel Selector Frame vi saranno
+# solo i TD relativi al progetto selezionato
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def ProjectCombo(self):
+ #Escludo dal combo i files e le cartelle indicate in Dir2NoShow
+ self.Prj_Lst=[]
+ FileList=glob.glob(self.ProjPath)
+ Dir2NoShow=[string.lower(os.path.split(self.ProjPath)[0]+'\\reports'),string.lower(os.path.split(self.ProjPath)[0]+'\\trash')]
+ for File in FileList:
+ if os.path.isdir(File) and not(Dir2NoShow.count(os.path.normcase(File))):
+ self.Prj_Lst.append(File)
+ if self.Prj_Lst.count(self.CurrentPrj):
+ InitProj=self.CurrentPrj
+ else:
+ if len(self.Prj_Lst)==0:
+ InitProj=''
+ else:
+ InitProj=self.Prj_Lst[0]
+ wxStaticText(self.wnd, -1, "Project:", wxPoint(5, 420), wxSize(75, 18))
+ self.wnd.Project = wxComboBox(self.wnd, 500, InitProj, wxPoint(5, 440), wxSize(180, -1),self.Prj_Lst, wxCB_DROPDOWN)#|wxTE_PROCESS_ENTER)
+
+
+############################################################################################################
+# FUNCTION NAME : DevelopUtility
+# FUNCTION DESCRIPTION: Creazione di un NoteBook per gestire utility dell'ambiente di sviluppo.
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def DevelopUtility(self):
+ self.wnd.Develop=wxNotebook(self.wnd, -1,pos=(5,525),size=(180,150))
+
+ #Tendina del dSPACE
+ self.wnd.Develop.Python = wxWindow(self.wnd.Develop, -1, (0,0), (30,30), wxSUNKEN_BORDER )
+ self.wnd.Develop.Python.Path=wxButton(self.wnd.Develop.Python, 113,'Set Path',(5,5),size=(155,22))
+ EVT_BUTTON(self,113,self.EvtPyUtility)
+ self.wnd.Develop.Python.Clear=wxButton(self.wnd.Develop.Python, 114,'Clr Module',(5,30),size=(155,22))
+ EVT_BUTTON(self,114,self.EvtPyUtility)
+ self.wnd.Develop.Python.ChangeStim=wxButton(self.wnd.Develop.Python, 115,'Change Stim',(5,55),size=(155,22))
+ EVT_BUTTON(self,115,self.EvtPyUtility)
+ #checkbox per la cancellazione dei pyc
+ self.wnd.Develop.Python.PycBox = wxCheckBox(self.wnd.Develop.Python, 146, " Clear .pyc", wxPoint(5, 80), wxSize(150, 20), wxNO_BORDER)
+ self.wnd.Develop.Python.PycBox.SetValue(False)
+ self.wnd.Develop.AddPage(self.wnd.Develop.Python, "dSPACE")
+
+ #Tendina dell' NSI
+ self.wnd.Develop.Nsi = wxWindow(self.wnd.Develop, -1, (0,0), (30,30), wxSUNKEN_BORDER )
+ self.wnd.Develop.AddPage(self.wnd.Develop.Nsi, "NSI")
+
+ #Tendina dello SPIL
+ self.wnd.Develop.Spil = wxWindow(self.wnd.Develop, -1, (0,0), (30,30), wxSUNKEN_BORDER )
+ #time x il debug
+ self.wnd.Develop.Spil.DebugTimeLabel=wxStaticText(self.wnd.Develop.Spil, -1, "Debug Stop Time(ms):",pos=(5,30), size=(95,30),style=wxALIGN_LEFT)
+ self.wnd.Develop.Spil.DebugTimeText = wxTextCtrl(self.wnd.Develop.Spil, -1, "0",pos=(80,33), size=(50, 20))
+ #pulsante x creazione sdt
+ self.wnd.Develop.Spil.SdtOut=wxButton(self.wnd.Develop.Spil, 129,'Output --> Sdt',(5,65),size=(75,20))
+ EVT_BUTTON(self,129,self.EvtSpilUtility)
+ #checkbox del coverage
+ self.wnd.Develop.Spil.CovBox = wxCheckBox(self.wnd.Develop.Spil, 138, " Coverage Enable", wxPoint(5, 5), wxSize(150, 20), wxNO_BORDER)
+ self.wnd.Develop.Spil.CovBox.SetValue(False)
+ #pulsante x apertura stimulus editor
+ self.wnd.Develop.Spil.OpenStim=wxButton(self.wnd.Develop.Spil, 139,'STIM',(90,65),size=(35,20))
+ EVT_BUTTON(self,139,self.EvtSpilUtility)
+ #pulsante x conversione da stimolo a sdt
+ self.wnd.Develop.Spil.OpenStim=wxButton(self.wnd.Develop.Spil, 143,'GEN',(125,65),size=(35,20))
+ EVT_BUTTON(self,143,self.EvtSpilUtility)
+ #pulsante x conversione da STB a sdt
+ self.wnd.Develop.Spil.STB=wxButton(self.wnd.Develop.Spil, 153,'Stb --> Sdt',(5,95),size=(75,20))
+ EVT_BUTTON(self,153,self.EvtSpilUtility)
+
+ self.wnd.Develop.AddPage(self.wnd.Develop.Spil, "SPIL")
+
+
+
+
+
+
+
+############################################################################################################
+# CLASS NAME: TdSelectorLay
+# CLASS DESCRIPTION: Gestione della grafica:
+# -Creazione frame di base
+# -Inizializzazione grafica
+# -Gestione eventi
+#
+# PARAMETERS: wxFrame: oggetto frame
+#
+# LIST OF METHODS: -OnBrowse
+# -SaveConfig
+# -EvtChoice
+# -EvtReload
+# -EvtTcAll
+# -EvtGO
+# -Configuration
+############################################################################################################
+class TdSelectorLay(wxFrame):
+
+ def __init__(self):
+ self.LauncherPath=os.getcwd() #lavoro sempre sulla cartella in cui è presente questo eseguibile
+ self.PythonPath="c:\\Programmi\\dSPACE\\dspace_r34_mlcu\\ControlDesk\\Python\\Python.exe"
+ self.PythonwinPath="c:\\Programmi\\dSPACE\\dspace_r34_mlcu\\ControlDesk\\Python\\Pythonwin\\Pythonwin.exe"
+ self.PylibPath="M:\\Work\\*\\Lib\\*"
+ self.DescrPath="M:\\Work\\*\\*\\*\\lay_descr.txt"
+ self.ProjPath="M:\\Work\\*"
+ self.NSIMSDevDir=r"C:\Programmi\Microsoft Visual Studio\Common\MSDev98"
+ self.NSIMSVCDir=r"C:\Programmi\Microsoft Visual Studio\VC98"
+ self.NSIDir=r"C:\MMB"
+ self.MtlbInstall=r"C:\Programmi\matlab65p1\bin\win32\matlab.exe"
+ self.Stimulus=r"C:\Programmi\waveman\waveman.exe"
+ self.IssInstall=r"C:\Programmi\T32\T32M166.EXE"
+ self.ReportSpil=r"M:\Work\Reports"
+
+
+
+ #se esiste il file config.txt in cui ho già configurato il launcher carico quello altrimenti prendo i default
+ if os.path.exists(self.LauncherPath+'\\config.txt'):
+ f=open(self.LauncherPath+'\\config.txt','r')
+ exec(f.readline()) #PythonPath
+ exec(f.readline()) #PythonwinPath
+ exec(f.readline()) #PylibPath
+ exec(f.readline()) #DescrPath
+ exec(f.readline()) #ProjPath
+ exec(f.readline()) #NSIMSDevDir
+ exec(f.readline()) #NSIMSVCDir
+ exec(f.readline()) #NSIDir
+ exec(f.readline()) #MtlbInstall
+ exec(f.readline()) #Stimulus
+ exec(f.readline()) #IssInstall
+ exec(f.readline()) #ReportSpil
+ f.close()
+ f=open(self.LauncherPath+'\\path.py','w')
+ f.write("LauncherPath=r'"+self.LauncherPath+"'")
+ f.close()
+
+ #creazione frame
+ wxFrame.__init__(self, NULL, -1,'TEST LAUNCHER vs 4.0.18')
+ self.Maximize(1) #massimizzo il frame
+ self.ScreenWidth,self.ScreenHeight=self.GetSizeTuple() #Larghezza e Altezza dello schermo
+ self.MngThr=threading.Event() #oggetto utile per gestire i thread
+ self.MngThr1=threading.Event() #oggetto utile per gestire i thread
+ self.MngThr2=threading.Event() #oggetto utile per gestire i thread
+ #creazione di scroll oriz e vert nel frame
+ self.scmain=wxScrolledWindow(self, -1,pos = wxDefaultPosition, size = wxDefaultSize, style = wxHSCROLL | wxVSCROLL, name = "scrolledWindow")
+ self.scmain.SetScrollbars(10, 10, 106, 70, xPos = 0, yPos = 0, noRefresh = FALSE)
+ self.wnd=wxWindow(self.scmain, -1, (0,10), (200,self.ScreenHeight*1.33), wxSUNKEN_BORDER)
+ #metto icona sulla barra
+ self.SetIcon(wxIcon('launcher.ico',wxBITMAP_TYPE_ICO))
+
+ #creazioni di tutti gli oggetti grafici
+
+ if len(glob.glob(self.ProjPath))>0:
+ self.CurrentPrj=glob.glob(self.ProjPath)[0] #setto il primo progetto trovato come progetto corrente da aprire
+ else:
+ self.CurrentPrj=''
+ ProjectCombo(self)
+ ProjectPath(self) #setta come corrente la directory relativa al progetto selezionato
+ self.TD_DATA=TdParse(self.CurrentDescrPath)[0] #faccio la ricerca dei TD sulla directory corrente
+ self.TD_NumTdXInstr=TdParse(self.CurrentDescrPath)[1] #Numero TD X strumento
+ SelectorFrame(self)
+ LauncherFrame(self)
+ TdBrowse(self)
+ ReloadButton(self)
+ DevelopUtility(self)
+ MenuBar(self)
+
+
+
+
+
+############################################################################################################
+# METHOD NAME: OnBrowse
+# METHOD DESCRIPTION: Evento del tasto di browse. Gestisce le finestre del browse presenti nel menubar
+# per la configurazione del launcher
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al pulsante di browse
+#
+############################################################################################################
+ def OnBrowse (self, event):
+ #browse per il python.exe(1) e pythonwin.exe(2)
+ if (event.GetId() == 1 or event.GetId() == 2):
+ self.wnd.dlg = wxFileDialog(self.PyConfigFrame.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ if event.GetId() == 1:
+ self.PyConfigFrame.Panel.PythonText.SetValue(self.wnd.dlg.GetPath())
+ if event.GetId() == 2:
+ self.PyConfigFrame.Panel.PythonwinText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per il path della libreria del python
+ if event.GetId() == 3:
+ self.wnd.dlg = wxDirDialog(self.GenConfigFrame.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.GenConfigFrame.Panel.PylibText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per il file descrittore della TD lay_descr.txt
+ if event.GetId() == 5 :
+ self.wnd.dlg = wxFileDialog(self.GenConfigFrame.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ if event.GetId() == 5:
+ self.GenConfigFrame.Panel.DescrText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per il path del progetto
+ if event.GetId() == 7:
+ self.wnd.dlg = wxDirDialog(self.GenConfigFrame.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.GenConfigFrame.Panel.ProjText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per MSDevDir
+ if event.GetId() == 117:
+ self.wnd.dlg = wxDirDialog(self.NSIConfigFrame.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.NSIConfigFrame.Panel.MSDevDirText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per MSVCDir
+ if event.GetId() == 118:
+ self.wnd.dlg = wxDirDialog(self.NSIConfigFrame.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.NSIConfigFrame.Panel.MSVCDirText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per NSIDir
+ if event.GetId() == 123:
+ self.wnd.dlg = wxDirDialog(self.NSIConfigFrame.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.NSIConfigFrame.Panel.NSIDirText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per l'exe del matlab
+ if event.GetId() == 124 :
+ self.wnd.dlg = wxFileDialog(self.SPILConfigFrame.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.SPILConfigFrame.Panel.MtlbInstallText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per lo stimulus editor
+ if event.GetId() == 125 :
+ self.wnd.dlg = wxFileDialog(self.SPILConfigFrame.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.exe", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.SPILConfigFrame.Panel.StimulusText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per l'exe dell'ISS
+ if event.GetId() == 126 :
+ self.wnd.dlg = wxFileDialog(self.SPILConfigFrame.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.SPILConfigFrame.Panel.IssInstallText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per la directory del report
+ if event.GetId() == 128 :
+ self.wnd.dlg = wxDirDialog(self.SPILConfigFrame.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.SPILConfigFrame.Panel.ReportSpilText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per l'output dello SPIL
+ if event.GetId() == 133:
+ self.wnd.dlg = wxFileDialog(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutTxtText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per il DataDictionary dello SPIL
+ if event.GetId() == 134:
+ self.wnd.dlg = wxFileDialog(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.DDText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per il file delle tolleranze dello SPIL
+ if event.GetId() == 135:
+ self.wnd.dlg = wxFileDialog(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, message = "", defaultDir = "", defaultFile = "",wildcard = "*.*", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutNameText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per l'output .mat dello SPIL
+ if event.GetId() == 136:
+ self.wnd.dlg = wxDirDialog(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.SdtNameText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per la directory contenente gli stimoli
+ if event.GetId() == 144 :
+ self.wnd.dlg = wxDirDialog(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.FolderStimulusText.SetValue(self.wnd.dlg.GetPath())
+
+ #browse per la directory contenente gli stimoli
+ if event.GetId() == 154 :
+ self.wnd.dlg = wxDirDialog(self.wnd.Develop.Spil.Stb2SdtDlg.Panel, message = "", defaultPath = "", style = wxOPEN)
+ if self.wnd.dlg.ShowModal() == wxID_OK:
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel.FolderStimulusText.SetValue(self.wnd.dlg.GetPath())
+
+
+
+ self.wnd.dlg.Destroy()
+
+
+
+############################################################################################################
+# METHOD NAME: SaveConfig
+# METHOD DESCRIPTION: Evento del tasto Save Config per il salvataggio della configurazione inserita tramite
+# menu bar
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al pulsante di Save Config
+#
+############################################################################################################
+ def SaveConfig(self, event):
+ #salvataggio ottenuto premendo il save dentro all' InstrumentsSet menu
+ if event.GetId() == 4 :
+ self.PythonPath=self.PyConfigFrame.Panel.PythonText.GetValue()
+ self.PythonwinPath=self.PyConfigFrame.Panel.PythonwinText.GetValue()
+ # se è spuntato il box per la creazione del NS allora chiama GetNS
+ if self.PyConfigFrame.Panel.CreateNSBox.GetValue():
+ self.ThCreateNS=threading.Thread(target=GetNS,args=(self,))
+ self.ThCreateNS.start()
+ self.PyConfigFrame.Destroy()
+ self.PyConfigFrame.Show(0)
+
+ #salvataggio ottenuto premendo il save dentro al GeneralSet menu
+ if event.GetId() == 6:
+ self.DescrPath=self.GenConfigFrame.Panel.DescrText.GetValue()
+ self.ProjPath=self.GenConfigFrame.Panel.ProjText.GetValue()
+ self.PylibPath=self.GenConfigFrame.Panel.PylibText.GetValue()
+ self.GenConfigFrame.Destroy()
+ self.GenConfigFrame.Show(0)
+
+ #salvataggio ottenuto premendo il save dentro al InstrumentsSet menu dell'NSI
+ if event.GetId() == 119:
+ self.NSIMSDevDir=self.NSIConfigFrame.Panel.MSDevDirText.GetValue()
+ self.NSIMSVCDir=self.NSIConfigFrame.Panel.MSVCDirText.GetValue()
+ self.NSIDir=self.NSIConfigFrame.Panel.NSIDirText.GetValue()
+ self.NSIConfigFrame.Destroy()
+ self.NSIConfigFrame.Show(0)
+
+ #salvataggio ottenuto premendo il save dentro al InstrumentsSet menu dell'SPIL
+ if event.GetId() == 127:
+ self.MtlbInstall=self.SPILConfigFrame.Panel.MtlbInstallText.GetValue()
+ self.Stimulus=self.SPILConfigFrame.Panel.StimulusText.GetValue()
+ self.IssInstall=self.SPILConfigFrame.Panel.IssInstallText.GetValue()
+ self.ReportSpil=self.SPILConfigFrame.Panel.ReportSpilText.GetValue()
+ self.SPILConfigFrame.Destroy()
+ self.SPILConfigFrame.Show(0)
+
+ #scrittura del file di config.txt
+ f=open(self.LauncherPath+'\\config.txt','w+')
+ f.write('self.PythonPath=r"'+self.PythonPath+'"')
+ f.write('\nself.PythonwinPath=r"'+self.PythonwinPath+'"')
+ f.write('\nself.PylibPath=r"'+self.PylibPath+'"')
+ f.write('\nself.DescrPath=r"'+self.DescrPath+'"')
+ f.write('\nself.ProjPath=r"'+self.ProjPath+'"')
+ f.write('\nself.NSIMSDevDir=r"'+self.NSIMSDevDir+'"')
+ f.write('\nself.NSIMSVCDir=r"'+self.NSIMSVCDir+'"')
+ f.write('\nself.NSIDir=r"'+self.NSIDir+'"')
+ f.write('\nself.MtlbInstall=r"'+self.MtlbInstall+'"')
+ f.write('\nself.Stimulus=r"'+self.Stimulus+'"')
+ f.write('\nself.IssInstall=r"'+self.IssInstall+'"')
+ f.write('\nself.ReportSpil=r"'+self.ReportSpil+'"')
+ f.close()
+
+
+
+############################################################################################################
+# METHOD NAME: EvtCreateSdt
+# METHOD DESCRIPTION: Evento scatenato dal pulsante di creazione dell'output sdt partendo dalla reg. SPIL
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al pulsante di Save Config
+#
+############################################################################################################
+ def EvtCreateSdt(self, event):
+ self.ThCreateSdt=threading.Thread(target=CreateSdt,args=(self,))
+ self.ThCreateSdt.start()
+
+############################################################################################################
+# METHOD NAME: EvtGenerateSdt
+# METHOD DESCRIPTION: Evento scatenato dal pulsante di generazione di SDT pertendo dallo stimolo
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al pulsante di Save Config
+#
+############################################################################################################
+ def EvtGenerateSdt(self, event):
+ self.ThGenerateSdt=threading.Thread(target=GenerateSdt,args=(self,))
+ self.ThGenerateSdt.start()
+
+############################################################################################################
+# METHOD NAME: EvtStb2Sdt
+# METHOD DESCRIPTION: Evento scatenato dal pulsante di generazione di SDT partendo da STB
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al pulsante di Save Config
+#
+############################################################################################################
+ def EvtStb2Sdt(self, event):
+ self.ThStb2Sdt=threading.Thread(target=Stb2Sdt,args=(self,))
+ self.ThStb2Sdt.start()
+
+
+############################################################################################################
+# METHOD NAME: EvtChoice
+# METHOD DESCRIPTION: Evento del TdBrowse. In base alla selezione fatta, la finestra del SelectorFrame si sposta
+# orizzontalmente di un tot agevolando la ricerca del TD
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al listbox del TdBrowse
+#
+############################################################################################################
+ def EvtChoice(self, event):
+ self.scmain.sc.Scroll(event.GetSelection()*20,0)
+
+
+############################################################################################################
+# METHOD NAME: EvtReload
+# METHOD DESCRIPTION: Evento del pulsante di RELOAD. Ricostruisce la finestra del SelectorFrame rianalizzando il
+# path relativo al progetto selezionato
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al pulsante RELOAD
+#
+############################################################################################################
+ def EvtReload(self, event):
+ #ricostruisce la lista del combo relativo al progetto in quanto potrebbe essere cambiata
+ ProjectPath(self)
+ self.wnd.Project.Destroy()
+ ProjectCombo(self)
+
+ #ricostruisce il SelectorFrame
+ self.scmain.sc.Destroy()
+ self.TD_DATA=TdParse(self.CurrentDescrPath)[0]
+ self.TD_NumTdXInstr=TdParse(self.CurrentDescrPath)[1] #Numero TD X strumento
+ self.wnd.launcher.ch.Destroy()
+ TdBrowse(self)
+ SelectorFrame(self)
+
+
+
+############################################################################################################
+# METHOD NAME: EvtTcAll
+# METHOD DESCRIPTION: Eventi di tutti i pulsanti di NO OL CL. Setta tutti i radiobutton al valore impostato
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato ai pulsanti di NO OL CL
+#
+############################################################################################################
+ def EvtTcAll(self, event):
+ #Gli Id dei pulsanti sono:
+ #NO globale = 0
+ #OL globale = 1
+ #CL globale = 2
+ #NO locale =x0 dove x è la TD relativa
+ #OL locale =x1 dove x è la TD relativa
+ #CL locale =x2 dove x è la TD relativa
+ ev=str(event.GetId())
+ TipoSel=ev[len(ev)-1] #la selezione è rappresenta sempre dalla cifra meno significativat
+ TD=ev[0:len(ev)-1] #il numero di TD è rappresentato dalle restanti cifrea più significativeve
+ #se TD='' significa che è quello globale e perciò faccio il for su tutti i TD
+ if TD=='':
+ for indexTD in range(len(self.TD_DATA)):
+ TD=str(indexTD+1)
+ GeneralSel(self,TD,TipoSel)
+ else:
+ GeneralSel(self,TD,TipoSel)
+
+############################################################################################################
+# METHOD NAME: EvtGO
+# METHOD DESCRIPTION: Al premere del GO raccolgo tutte le selezioni dei TC e lancio il RUN e il controllore di led
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato al GO
+#
+############################################################################################################
+ def EvtGO(self, event):
+ self.GlobalTestList=[]
+ for TD in range(len(self.TD_DATA)):
+ exec('TypeTestListTD'+str(TD+1)+'=[]')
+ for TC in range(len(self.TD_DATA[TD][2])-1):
+ str2exe="TypeTestListTD"+str(TD+1)+".append(self.scmain.sc.TD"+str(TD+1)+".rb"+str(TC+1)+"_"+str(TD+1)+".GetSelection())"
+ exec(str2exe)
+ str2exe="self.GlobalTestList.append(TypeTestListTD"+str(TD+1)+")"
+ exec(str2exe)
+
+ #se non è stato selezionato nessun TC non faccio partire il RUN_TESTl
+ NoTest=1
+ for TypeTestListTD in self.GlobalTestList:
+ if TypeTestListTD.count(1) or TypeTestListTD.count(2):
+ NoTest=0
+ break
+ else:
+ NoTest=1
+ if not(NoTest):
+ #parte il thread che controlla il file dei led
+ self.ThLed=threading.Thread(target=CheckLed,args=(self,))
+ self.ThLed.start()
+ #parte il thread che lancia i launcher dei vari strumenti
+ ThRun=threading.Thread(target=RUN_TEST,args=(self,))
+ ThRun.start()
+
+
+############################################################################################################
+# FUNCTION NAME : RptTest
+# FUNCTION DESCRIPTION: Incremento del TextControl x ripetizione test
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) evento
+#
+############################################################################################################
+ def RptTest(self,event):
+ self.wnd.RptTestTxt.SetValue(str(event.GetPosition()))
+
+
+
+############################################################################################################
+# METHOD NAME: Configuration
+# METHOD DESCRIPTION: gestione eventi menu configurazione
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: eventi legati al menu
+#
+############################################################################################################
+ def Configuration(self,event):
+ #menu Instruments
+ if event.GetId() == 105:
+ PyConfig(self)
+ #menu TD set
+ if event.GetId() == 108:
+ GenConfig(self)
+ #menu NSI set
+ if event.GetId() == 106:
+ NSIConfig(self)
+ #menu SPIL set
+ if event.GetId() == 107:
+ SPILConfig(self)
+ #menu Exit set
+ if event.GetId() == 156:
+ ExitProc(self)
+
+
+############################################################################################################
+# METHOD NAME: EvtPyUtility
+# METHOD DESCRIPTION: Evento dei pulsanti di Utility Python
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato ai pulsanti del python utility
+#
+############################################################################################################
+ def EvtPyUtility(self, event):
+ #Setto il path (in un thread separato con win98 non necessario)
+ if event.GetId() == 113:
+ self.ThSetPath=threading.Thread(target=SetPath,args=(self,))
+ self.ThSetPath.start()
+
+ #Cancello i moduli importati (in un thread separato con win98 non necessario)
+ if event.GetId() == 114:
+ self.ThClrNS=threading.Thread(target=ClrNS,args=(self,))
+ self.ThClrNS.start()
+
+ #Invoco il ChangeStimolo
+ if event.GetId() == 115:
+ #creazione frame generale
+ self.wnd.Develop.Python.ChStimDlg=wxMiniFrame(None, -1,title="Change Stimulus", pos=(200,100), size=(500,300), style=wxDEFAULT_FRAME_STYLE)
+ self.wnd.Develop.Python.ChStimDlg.Panel = wxPanel(self.wnd.Develop.Python.ChStimDlg, -1,pos=(0,0), size=(500,300))
+ self.wnd.Develop.Python.ChStimDlg.Panel.Browse=wxGenericDirCtrl(self.wnd.Develop.Python.ChStimDlg.Panel, -1, dir=self.CurrentPrj,size=(200,200), style=wxDIRCTRL_3D_INTERNAL|wxDIRCTRL_SHOW_FILTERS|wxMULTIPLE,filter="Python files (*.py)|*.py")
+ self.wnd.Develop.Python.ChStimDlg.Panel.Start =wxButton(self.wnd.Develop.Python.ChStimDlg.Panel, 116, "START CHANGE",pos=(250,20),size=(200,30))
+ EVT_BUTTON(self.wnd.Develop.Python.ChStimDlg.Panel.Start, 116, self.EvtChgStim)
+ self.wnd.Develop.Python.ChStimDlg.Panel.Check= wxCheckBox(self.wnd.Develop.Python.ChStimDlg.Panel, -1, "Recurse Sub-Directory", wxPoint(50, 210), wxSize(150, 20), wxNO_BORDER)
+ self.wnd.Develop.Python.ChStimDlg.Show(1)
+
+############################################################################################################
+# METHOD NAME: EvtSpilUtility
+# METHOD DESCRIPTION: Evento dei pulsanti di Utility Spil
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) event: evento legato ai pulsanti del python utility
+#
+############################################################################################################
+ def EvtSpilUtility(self, event):
+ #Invoco il Convert2Sdt per convertire il prodotto dello SPIL .txt in formato sdt .mat
+ if event.GetId() == 129:
+ #creazione frame generale
+ self.wnd.Develop.Spil.Cv2SdtDlg=wxMiniFrame(None, -1,title="Convert2Sdt", pos=(200,100), size=(500,300), style=wxDEFAULT_FRAME_STYLE)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel = wxPanel(self.wnd.Develop.Spil.Cv2SdtDlg, -1,pos=(0,0), size=(500,300))
+ #creazione text control e browse di Output.txt
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutTxtLabel=wxStaticText(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "Output.txt:",pos=(5,7), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutTxtText = wxTextCtrl(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "",pos=(100,5), size=(300, 20))
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutTxtBrowse =wxButton(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, 133, "...",pos=(405,5),size=(18,20))
+ EVT_BUTTON(self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutTxtBrowse, 133, self.OnBrowse)
+ #creazione text control e browse di DataDict.mat
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.DDLabel=wxStaticText(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "DataDict.mat:",pos=(5,47), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.DDText = wxTextCtrl(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "",pos=(100,45), size=(300, 20))
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.DDBrowse =wxButton(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, 134, "...",pos=(405,45),size=(18,20))
+ EVT_BUTTON(self.wnd.Develop.Spil.Cv2SdtDlg.Panel.DDBrowse, 134, self.OnBrowse)
+ #creazione text control e browse di Toll.m
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutNameLabel=wxStaticText(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "TOLL_xxx_GEN.m:",pos=(5,87), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutNameText = wxTextCtrl(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "",pos=(100,85), size=(300, 20))
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutNameBrowse =wxButton(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, 135, "...",pos=(405,85),size=(18,20))
+ EVT_BUTTON(self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutNameBrowse, 135, self.OnBrowse)
+ #creazione text control e browse dell'SDT di Output.mat
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.SdtNameLabel=wxStaticText(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "File da creare .mat:",pos=(5,127), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.SdtNameText = wxTextCtrl(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, -1, "",pos=(100,125), size=(300, 20))
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.SdtNameBrowse =wxButton(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, 136, "...",pos=(405,125),size=(18,20))
+ EVT_BUTTON(self.wnd.Develop.Spil.Cv2SdtDlg.Panel.SdtNameBrowse, 136, self.OnBrowse)
+ #creazione pulsante salvataggio
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.CreateSdt=wxButton(self.wnd.Develop.Spil.Cv2SdtDlg.Panel, 137,'Create SdtOut',pos=(150,200),size=(200,40))
+ EVT_BUTTON(self.wnd.Develop.Spil.Cv2SdtDlg.Panel.CreateSdt,137,self.EvtCreateSdt)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Show(1)
+ #Invoco l'apertura dello stimulus editor x SPIL
+ if event.GetId() == 139:
+ self.ThOpenStimulus=threading.Thread(target=OpenStimulus,args=(self,))
+ self.ThOpenStimulus.start()
+ #Invoco l'elaborazione delle tracce ricavate dello stimous editor x ottenere l'SDT
+ if event.GetId() == 143:
+ #creazione frame generale
+ self.wnd.Develop.Spil.Stim2SdtDlg=wxMiniFrame(None, -1,title="Sdt Generator", pos=(200,100), size=(500,200), style=wxDEFAULT_FRAME_STYLE)
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel = wxPanel(self.wnd.Develop.Spil.Stim2SdtDlg, -1,pos=(0,0), size=(500,200))
+ #creazione text control e browse x la cartella contenente gli stimoli
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.FolderStimulusLabel=wxStaticText(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, -1, "Stimulus Folder:",pos=(5,37), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.FolderStimulusText = wxTextCtrl(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, -1, "",pos=(100,35), size=(300, 20))
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.FolderStimulusBrowse =wxButton(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, 144, "...",pos=(405,35),size=(18,20))
+ EVT_BUTTON(self.wnd.Develop.Spil.Stim2SdtDlg.Panel.FolderStimulusBrowse, 144, self.OnBrowse)
+ #creazione text control per lo step dello stimolo
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.StimulusStepLabel=wxStaticText(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, -1, "Stimulus Step [sec]:",pos=(5,77), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.StimulusStepText = wxTextCtrl(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, -1, "0.001",pos=(100,75), size=(50, 20))
+ #creazione pulsante per il processing
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.CreateSdt=wxButton(self.wnd.Develop.Spil.Stim2SdtDlg.Panel, 145,'Converting in Sdt format',pos=(150,120),size=(200,40))
+ EVT_BUTTON(self.wnd.Develop.Spil.Stim2SdtDlg.Panel.CreateSdt,145,self.EvtGenerateSdt)
+ self.wnd.Develop.Spil.Stim2SdtDlg.Show(1)
+ #Invoco l'elaborazione delle tracce ricavate da STB x ottenerle in formato SDT
+ if event.GetId() == 153:
+ #creazione frame generale
+ self.wnd.Develop.Spil.Stb2SdtDlg=wxMiniFrame(None, -1,title="Sdt Generator", pos=(200,100), size=(500,200), style=wxDEFAULT_FRAME_STYLE)
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel = wxPanel(self.wnd.Develop.Spil.Stb2SdtDlg, -1,pos=(0,0), size=(500,200))
+ #creazione text control e browse x la cartella contenente gli stimoli
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel.FolderStimulusLabel=wxStaticText(self.wnd.Develop.Spil.Stb2SdtDlg.Panel, -1, "Stimulus Folder:",pos=(5,37), size=(95,20),style=wxALIGN_RIGHT)
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel.FolderStimulusText = wxTextCtrl(self.wnd.Develop.Spil.Stb2SdtDlg.Panel, -1, "",pos=(100,35), size=(300, 20))
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel.FolderStimulusBrowse =wxButton(self.wnd.Develop.Spil.Stb2SdtDlg.Panel, 154, "...",pos=(405,35),size=(18,20))
+ EVT_BUTTON(self.wnd.Develop.Spil.Stb2SdtDlg.Panel.FolderStimulusBrowse, 154, self.OnBrowse)
+ #creazione pulsante per il processing
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel.CreateSdt=wxButton(self.wnd.Develop.Spil.Stb2SdtDlg.Panel, 155,'Converting in Sdt format',pos=(150,120),size=(200,40))
+ EVT_BUTTON(self.wnd.Develop.Spil.Stb2SdtDlg.Panel.CreateSdt,155,self.EvtStb2Sdt)
+ self.wnd.Develop.Spil.Stb2SdtDlg.Show(1)
+
+
+############################################################################################################
+# FUNCTION NAME : EvtChgStim
+# FUNCTION DESCRIPTION: Chiama lo script ClearNS.py
+# - Cancella i moduli importati e le variabili
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+ def EvtChgStim(self,event):
+ self.ThChgStim=threading.Thread(target=ChgStim,args=(self,))
+ self.ThChgStim.start()
+
+
+
+############################################################################################################
+# FUNCTION NAME : EvtLog
+# FUNCTION DESCRIPTION: Apre il file di log
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+ def EvtLog(self,event):
+ os.startfile(r'log.txt')
+
+
+
+
+############################################################################################################
+# CLASS NAME: App
+# CLASS DESCRIPTION: Costrutto base per le interfaccie grafiche
+#
+# PARAMETERS: eventuali parametri da passare al creatore della classe
+# 1) wxApp
+#
+# LIST OF METHODS: OnInit
+############################################################################################################
+class App(wxApp):
+ def OnInit(self):
+ frame=TdSelectorLay()
+ frame.Show(true)
+ return true
+
+
+
+############################################################################################################
+# FUNCTION NAME : GeneralSel
+# FUNCTION DESCRIPTION:
+# E' la funzione che materialmente setta i radiobutton al valore impostato dai pulsanti NO OL CL
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+# 2) TD: stringa indicante il numero della TD su cui agire
+# 3) TipoSel: stringa indicante il tipo di settaggio da effettuare sui radiobutton
+#
+############################################################################################################
+def GeneralSel(self,TD,TipoSel):
+ str2exe="TcNum=len(self.TD_DATA["+TD+"-1][2])-1"
+ exec(str2exe)
+ for indexTC in range(TcNum):
+ str2exe="self.scmain.sc.TD"+TD+".rb"+str(indexTC+1)+"_"+TD+".SetSelection("+TipoSel+")"
+ exec(str2exe)
+
+
+
+
+############################################################################################################
+# FUNCTION NAME : ProjectPath
+# FUNCTION DESCRIPTION:
+# Setta il path per i descrittori di TD e per le librerie in funzione al progetto selezionato
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def ProjectPath(self):
+ self.CurrentPrj=r''+self.wnd.Project.GetValue() #progetto selezionato
+ lensplitPrj=len(string.split(self.CurrentPrj,'\\'))
+ splitPath=string.split(self.DescrPath,'\\')
+ #il path lo compongo partendo dal path del progetto selezionato e aggiungendo le parti del DescrPath rimanenti
+ self.CurrentDescrPath=self.CurrentPrj
+ for i in range(lensplitPrj,len(splitPath)):
+ self.CurrentDescrPath=self.CurrentDescrPath+'\\'+splitPath[i]
+ #il path lo compongo partendo dal path del progetto selezionato e aggiungendo le parti del PylibPath rimanenti
+ self.CurrentPylibPath=self.CurrentPrj
+ splitLib=string.split(self.PylibPath,'\\')
+ for i in range(lensplitPrj,len(splitLib)):
+ self.CurrentPylibPath=self.CurrentPylibPath+'\\'+splitLib[i]
+ if self.CurrentPrj=='':
+ self.CurrentDescrPath=''
+ self.CurrentPylibPath=''
+
+############################################################################################################
+# FUNCTION NAME : CompList
+# FUNCTION DESCRIPTION: Utility per le liste del Led_status e Type_List. Se è stato selezionato un TC
+# e il led corrispondente non si è acceso significa che c'è stato un errore .
+#
+# INPUT PARAMETERS:
+# 1) TL lista dei test case selezionati in un TD
+# 2) LS lista dello stato dei led relativi
+# OUTPUT:
+# 1) Ritorna 0 se c'è un'incongruenza (TC selezionato e Led spento) 1 altrimenti
+############################################################################################################
+def CompList(TL,LS):
+ if (TL!=0) and (LS==0 or LS==None):
+ return 0
+ else:
+ return 1
+
+############################################################################################################
+# FUNCTION NAME : CheckLed
+# FUNCTION DESCRIPTION: Alla fine dell'esecuzione del TD setta il colore dei led in base del risultato dei TC.
+# Funzione lanciata in thread parallelo con il RUN che controlla periodicamente lo stato del file led_status.txt.
+# L'accesso in scrittura e lettura di questo file è regolato attraverso un ulteriore file di flag chiamato
+# led.flg. Questo flag è creato dal PyTdLnc.py e, in generale, da tutti i lanciatori di strumento
+# al termine di ogni esecuzione di TD e cancellato solo alla fine del settaggio dei led della TD.
+# Grazie a questo flag si evita il contemporaneo accesso del file da parte di 2 programmi diversi
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def CheckLed(self):
+ #se per qualsiasi motivo alla partenza si ha il file di flag questo deve essere cancellato
+ if (os.path.exists(self.LauncherPath+'\\led.flg')):
+ os.remove(self.LauncherPath+'\\led.flg')
+ #Aspetto fintantochè non è finita la parte di inizializzazione del file led_status.txt fatta in
+ #RUN_TEST
+ self.MngThr2.wait()
+ self.Iconize(1) #al lancio dei test mi iconizza il launcher
+ stopflg=0 #quando 1 significa che è finita l'esecuzione di tutti i tests di tutti gli strumenti
+ #e posso quindi uscire dalla funzione
+ while not(stopflg):
+ #E' il gestore di thread che mette in wait il thread per 2 secondi
+ #lasciando più CPU per il thread RUN eseguito in parallelo .
+ self.MngThr.wait(2)
+ #lettura led solo se esiste il flag
+ if (os.path.exists(self.LauncherPath+'\\led.flg')):
+ f=open(self.LauncherPath+'\\led_status.txt','r+')
+ exec(f.readline()) #LED_STATUS=[[1,2,0,3],[],[2,1]]
+ exec(f.readline()) #stopInstr=0
+ exec(f.readline()) #stopflgHIL=0
+ exec(f.readline()) #stopflgNSI=0
+ exec(f.readline()) #stopflgSPIL=0
+ #Lo stopflg (quindi la fine del programma) si ha solo quando tutti gli strumenti hanno finito e
+ #e sono state eseguite tutte le ripetizioni indicate
+ stopflg=stopflgHIL&stopflgNSI&stopflgSPIL&(self.nrpt+1==(int(self.wnd.RptTestSpn.GetValue()))) #se 1 significa fine della sessione di tests
+ LedColor=['grey','black','green','red']
+ #setto il colore dei led in base al risultato
+ for indexTD in range(len(LED_STATUS)):
+ if LED_STATUS[indexTD].count(1) or LED_STATUS[indexTD].count(2) or LED_STATUS[indexTD].count(3): #se per un certo TD non sono stati selezionati TC, lascio in grigio
+ for indexTC in range(len(LED_STATUS[indexTD])):
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".led"+str(indexTC+1)+"_"+str(indexTD+1)+".SetBackgroundColour(LedColor["+str(LED_STATUS[indexTD][indexTC])+"])"
+ #es: self.scmain.sc.TD1.led1_1..SetBackgroundColour(LedColor["+str(LED_STATUS[indexTD][indexTC])+"])
+ exec(str2exe)
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".Refresh()" #rinfresco la pagina per vedere l'effetto del set
+ #es: self.scmain.sc.TD1.Refresh()
+ exec(str2exe)
+ #Verifico anche che i test non abbiano avuto problemi nell'esecuzione.
+ #In caso negativo coloro di rosso il pulsante di log.
+ if indexTD>0:
+ if map(CompList,self.GlobalTestList[indexTD-1],LED_STATUS[indexTD-1]).count(0)>0:
+ self.wnd.launcher.log.SetBackgroundColour(wxRED)
+ #stopInstr è il flag che dice se il test con uno degli strumenti è terminato
+ if (stopInstr==1):
+ #Verifico anche che i test non abbiano avuto problemi nell'esecuzione.
+ #In caso negativo coloro di rosso il pulsante di log.
+ #print "indexTD=",indexTD
+ if LED_STATUS!=[]: #LED_STATUS è uguale a[] in caso di debug
+ if map(CompList,self.GlobalTestList[indexTD],LED_STATUS[indexTD]).count(0)>0:
+ self.wnd.launcher.log.SetBackgroundColour(wxRED)
+ #se la sessione di uno strumento è terminata --> semaforo verde x il thread MngThr1
+ self.MngThr1.set()
+ f.seek(0)
+ tmpList=f.readlines()
+ tmpList[1]='stopInstr=0\n' #resetto il flag di fine strumento
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ os.remove(self.LauncherPath+'\\led.flg') #solo alla fine delle mie operazioni rimuovo il flag
+ #abilito i pulsanti di GO ed ENABLE disabilitati nella funzione RUN_TEST
+
+ self.wnd.GO.Enable(TRUE)
+ self.wnd.reload.Enable(TRUE)
+ self.wnd.RptTestSpn.Enable(TRUE)
+ self.wnd.RptTestTxt.Enable(TRUE)
+
+ self.Maximize(1)
+
+
+############################################################################################################
+# FUNCTION NAME : SetPath
+# FUNCTION DESCRIPTION: Chiama lo script SetPath.py
+# - Include nel pythonpath le librerie del progetto e le cartelle dei TD selezionati
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def SetPath(self):
+ #Raccolgo i TD selezionati
+ self.GlobalTestList=[]
+ for TD in range(len(self.TD_DATA)):
+ exec('TypeTestListTD'+str(TD+1)+'=[]')
+ for TC in range(len(self.TD_DATA[TD][2])-1):
+ str2exe="TypeTestListTD"+str(TD+1)+".append(self.scmain.sc.TD"+str(TD+1)+".rb"+str(TC+1)+"_"+str(TD+1)+".GetSelection())"
+ exec(str2exe)
+ str2exe="self.GlobalTestList.append(TypeTestListTD"+str(TD+1)+")"
+ exec(str2exe)
+
+ #Scrivo nel tmp.txt le informazioni sui tests selezionati, sul nome dei tests e sul path della libreria
+ f=open(self.LauncherPath+'\\tmp.txt','w+')
+ f.write('HilTestList='+str(self.GlobalTestList))
+ f.write('\nHilTD_DATA='+str(self.TD_DATA))
+ f.write('\nPylibPath=r"'+str(self.CurrentPylibPath)+'"')
+ f.write('\n')
+ f.close()
+
+ if string.lower(os.path.split(self.PythonwinPath)[1])=="idle.pyw":
+ #command=self.PythonwinPath + " " +self.LauncherPath+'\\SetPath.py'
+ command=""
+ elif string.lower(os.path.split(self.PythonwinPath)[1])=="pythonwin.exe":
+ revpath=string.replace(self.LauncherPath+'\\SetPath.py','\\','/')
+ command=self.PythonwinPath+" /run "+revpath
+ else:
+ print "NOT VALID DEBUGGER\n Change debugger program "
+
+
+
+
+
+ os.system(command)
+
+############################################################################################################
+# FUNCTION NAME : ClrNS
+# FUNCTION DESCRIPTION: Chiama lo script ClearNS.py
+# - Cancella i moduli importati e le variabili
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def ClrNS(self):
+ if string.lower(os.path.split(self.PythonwinPath)[1])=="idle.pyw":
+ #command=self.PythonwinPath +' -d -e "'+self.LauncherPath+'\\ClearNS.py"'
+ command=""
+ elif string.lower(os.path.split(self.PythonwinPath)[1])=="pythonwin.exe":
+ revpath=string.replace(self.LauncherPath+'\\ClearNS.py','\\','/')
+ command=self.PythonwinPath+" /run "+revpath
+ else:
+ print "NOT VALID DEBUGGER\n Change debugger program "
+ os.system(command)
+
+
+
+
+
+############################################################################################################
+# FUNCTION NAME : GetNS
+# FUNCTION DESCRIPTION: Chiama lo script GetNS.py
+# - Crea il file NStmp in cui vi è il NS di riferimento
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def GetNS(self):
+ revpath=string.replace(self.LauncherPath+'\\GetNS.py','\\','/')
+ command=self.PythonwinPath+" /run "+revpath
+ os.system(command)
+
+
+
+
+############################################################################################################
+# FUNCTION NAME : ChgStim
+# FUNCTION DESCRIPTION: Chiama lo script change_stim.py
+# - cambia gli script degli stimoli
+# tipo=0 cambia file
+# tipo=1 cambia contenuto cartelle
+# tipo=2 cambia contenuto cartella e sottocartelle
+#
+#
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def ChgStim(self):
+ if os.path.isdir(self.wnd.Develop.Python.ChStimDlg.Panel.Browse.GetPath()):
+ if self.wnd.Develop.Python.ChStimDlg.Panel.Check.GetValue():
+ tipo = 2
+ else:
+ tipo = 1
+ else:
+ tipo=0
+ f=open(self.LauncherPath+'\\tmpchgstim.txt','w+')
+ f.write('tipo='+str(tipo))
+ f.write('\ntop_path=r"'+self.wnd.Develop.Python.ChStimDlg.Panel.Browse.GetPath()+'"')
+ f.close()
+ revpath=string.replace(self.LauncherPath+'\\change_stim.py','\\','/')
+ command=self.PythonwinPath+" /run "+revpath
+ self.wnd.Develop.Python.ChStimDlg.Destroy()
+ os.system(command)
+
+
+############################################################################################################
+# FUNCTION NAME : CreateSdt
+# FUNCTION DESCRIPTION: Chiama la funzione matlab il matlab GetSdtOut x convertire gli output SPIL in
+# output SDT
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def CreateSdt(self):
+ #SpilMatLib='M:\\Work\\4TV_SPIL_00\\LIB\\SPILMATLIB\n'
+ SpilMatLib=os.path.dirname(glob.glob(self.CurrentPylibPath+'\\SetCalib.m')[0]) #OK generale
+
+ LaunchFile=" /r cd('"+SpilMatLib+"');GetSdtOut('"+\
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutTxtText.GetValue()+"','"+\
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.DDText.GetValue()+"','"+\
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.OutNameText.GetValue()+"','"+\
+ self.wnd.Develop.Spil.Cv2SdtDlg.Panel.SdtNameText.GetValue()+"');quit"
+ os.system(self.MtlbInstall+LaunchFile)
+ self.wnd.Develop.Spil.Cv2SdtDlg.Destroy()
+ self.wnd.Develop.Spil.Cv2SdtDlg.Show(0)
+
+############################################################################################################
+# FUNCTION NAME : OpenStimulus
+# FUNCTION DESCRIPTION: Apre lo stimulus editor x lo spil
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def OpenStimulus(self):
+ os.system(self.Stimulus)
+
+############################################################################################################
+# FUNCTION NAME : GenerateSdt
+# FUNCTION DESCRIPTION: Chiama la funzione matlab Stimulus2Sdt x convertire gli stimoli dello stimulus
+# editor in SDT
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def GenerateSdt(self):
+ #SpilMatLib='M:\\Work\\4TV_SPIL_00\\LIB\\SPILMATLIB\n'
+ SpilMatLib=os.path.dirname(glob.glob(self.CurrentPylibPath+'\\SetCalib.m')[0]) #OK generale
+
+ LaunchFile=" /r cd('"+SpilMatLib+"');Stimulus2Sdt('"+\
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.StimulusStepText.GetValue()+"','"+\
+ self.wnd.Develop.Spil.Stim2SdtDlg.Panel.FolderStimulusText.GetValue()+"');quit"
+ os.system(self.MtlbInstall+LaunchFile)
+ self.wnd.Develop.Spil.Stim2SdtDlg.Destroy()
+ self.wnd.Develop.Spil.Stim2SdtDlg.Show(0)
+
+############################################################################################################
+# FUNCTION NAME : Stb2Sdt
+# FUNCTION DESCRIPTION: Chiama la funzione matlab Stb2Sdt x convertire i pattern di STB
+# in formato SDT
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def Stb2Sdt(self):
+ #SpilMatLib='M:\\Work\\4TV_SPIL_00\\LIB\\SPILMATLIB\n'
+ SpilMatLib=os.path.dirname(glob.glob(self.CurrentPylibPath+'\\SetCalib.m')[0]) #OK generale
+
+ LaunchFile=" /r cd('"+SpilMatLib+"');Stb2Sdt('"+\
+ self.wnd.Develop.Spil.Stb2SdtDlg.Panel.FolderStimulusText.GetValue()+"');quit"
+ os.system(self.MtlbInstall+LaunchFile)
+ self.wnd.Develop.Spil.Stb2SdtDlg.Destroy()
+ self.wnd.Develop.Spil.Stb2SdtDlg.Show(0)
+
+
+############################################################################################################
+# FUNCTION NAME : ClearPyc
+# FUNCTION DESCRIPTION: Funzione che cancella i file .pyc se trova nella stessa cartella file omonimi
+# ma con estensione .py. La ricerca vieve effettuata nelle librerie e nei TD
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def ClearPyc(self):
+ print "Deleting .pyc files..."
+ # Trovo i files pyc presenti nei TD, nelle Librerie e sotto Work
+ PycList=glob.glob(self.CurrentPrj+'\\*\\*\\*.pyc')+glob.glob(os.path.split(self.ProjPath)[0]+'\\*.pyc')
+ # Solo se esiste un corrispondente .py rimuovo il .pyc
+ for Pyc in PycList:
+ if os.path.exists(os.path.splitext(Pyc)[0]+'.py'):
+ os.remove(Pyc)
+
+
+############################################################################################################
+# FUNCTION NAME : RUN_TEST
+# FUNCTION DESCRIPTION: Chiama lo script di lancio PyTdLnc x i test HIL e lancia direttamente i test x NSI e SPIL
+# in modalità RUN o DEBUGU (può chiamare qualsiasi script anche non python)
+# - Disabilita i pulsanti di GO e RELOAD
+# - Crea un file per il log
+# - Resetta lo stato dei led
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def RUN_TEST(self):
+ #Se il lancio è stato fatto in debug non considerare i repeat
+ if self.wnd.launcher.run.GetSelection():
+ self.wnd.RptTestSpn.SetValue(1)
+ #Ripeto lo scenario di test quante volte indicato dal pannello
+ for self.nrpt in range(int(self.wnd.RptTestSpn.GetValue())):
+ if int(self.wnd.RptTestSpn.GetValue())>1:
+ print "\n\n\nRIPETIZIONE SCENARIO N° ",self.nrpt+1
+ NTS=str(self.nrpt+1)+'°'
+ else:
+ NTS=''
+
+ #inizializzo il file led_status.txt con i stopflag degli strumenti = 0
+ f=open('led_status.txt','w')
+ f.writelines(['LED_STATUS=[]\n','stopInstr=0\n','stopflgHIL=0\n','stopflgNSI=0\n','stopflgSPIL=0\n'])
+ f.close()
+ #Dopo l'inizializzazione, in cui ho lavorato sul file led_status.txt, posso dare il verde alla CheckLed
+ #(Se non lo facessi ci sarebbe il rischio di una collisione sul led_status.txt)
+ self.MngThr2.set()
+
+ #Mi assicuro di essere nella directory del Launcher
+ os.chdir(self.LauncherPath)
+ #Metto il semaforo rosso a questo Thread (starò in wait finchè il singolo strumento non ha finito)
+ self.MngThr1.clear()
+ #Disabilita i pulsanti di GO, RELOAD e repeat
+ self.wnd.GO.Enable(FALSE)
+ self.wnd.reload.Enable(FALSE)
+ self.wnd.RptTestSpn.Enable(FALSE)
+ self.wnd.RptTestTxt.Enable(FALSE)
+ #Crea un file per il log a cui i singoli TD devono accedere con l'attributo append
+ #Inizialmente ha colore verde, se vi è qualche errore diventa rosso
+ self.wnd.launcher.log.SetBackgroundColour(wxGREEN)
+ if self.nrpt==0:
+ filelog=open(self.LauncherPath+'\\log.txt','w')
+ else:
+ filelog=open(self.LauncherPath+'\\log.txt','a')
+ filelog.write("\n\n\nSTART %s TESTS SESSION:%s\n"%(NTS,time.ctime(time.time())))
+ filelog.close()
+ #Resetto lo stato dei led
+ for indexTD in range(len(self.GlobalTestList)):
+ for indexTC in range(len(self.GlobalTestList[indexTD])):
+ str2exe="self.scmain.sc.TD"+str(indexTD+1)+".led"+str(indexTC+1)+"_"+str(indexTD+1)+".SetBackgroundColour('grey')"
+ exec(str2exe)
+
+ #Leggo se lanciare il test per ecu sviluippo piuttosto che ecu di produzione
+ if not(self.wnd.launcher.ECU.GetSelection()):
+ self.EcuType="EcuType='sviluppo'"
+ else:
+ self.EcuType="EcuType='produzione'"
+ #Verifico strumento x strumento se sono stati selezionati dei TC
+ InstrExec=[] #InstrExec ha tanti elementi quanti sono gli strumenti e sono settati a 1 se c'è almeno un TC selezionato
+ for nInstr in range(1,len(self.TD_NumTdXInstr)):
+ InstrExec.append(0)
+ #scandisco il GlobalTestList solo nel range dello strumento considerato
+ for TypeTestListTD in self.GlobalTestList[self.TD_NumTdXInstr[nInstr-1]:self.TD_NumTdXInstr[nInstr]]:
+ if TypeTestListTD.count(1) or TypeTestListTD.count(2):
+ InstrExec[nInstr-1]=1
+ break
+
+
+ #----------------------------LANCIO I TEST PER HIL (solo se almeno 1 TC è selezionato) ---------------------------#
+ if InstrExec[0]==1:
+ #Scrivo nel tmp.txt le informazioni sui tests selezionati, sul nome dei tests e sul path della libreria utili per il PyTdLnc.py
+ f=open(self.LauncherPath+'\\tmp.txt','w+')
+ f.write(self.EcuType)
+ f.write('\nHilTestList='+str(self.GlobalTestList[:self.TD_NumTdXInstr[1]]))
+ f.write('\nHilTD_DATA='+str(self.TD_DATA[:self.TD_NumTdXInstr[1]]))
+ f.write('\nPylibPath=r"'+str(self.CurrentPylibPath)+'"')
+ f.write('\n')
+ f.close()
+ try:
+ # Se c'è il flag di cancellatura .pyc, lancio la funzione che dalla root
+ # elimina i pyc se esiste anche il py (sia nelle lib che nei TD)
+ if self.wnd.Develop.Python.PycBox.GetValue():
+ ClearPyc(self)
+
+ #modalità RUN
+ if not(self.wnd.launcher.run.GetSelection()):
+ command=self.PythonPath+' -c "import PyTdLnc"'
+ os.system(command)
+ #modalità DEBUG
+ else:
+ if string.lower(os.path.split(self.PythonwinPath)[1])=="idle.pyw":
+ command=self.PythonwinPath +' -d -e "'+self.LauncherPath+'\\PyTdLnc.py"'
+ print"debug session..."
+ os.system(command)
+ elif string.lower(os.path.split(self.PythonwinPath)[1])=="pythonwin.exe":
+ command=self.PythonwinPath+' PyTdLnc.py'
+ print"debug session..."
+ os.system(command)
+ else:
+ print "NOT VALID DEBUGGER\n Change debugger program "
+ except:
+ #se c'è un'eccezione a questo livello coloro di rosso il pulsante di log
+ self.wnd.launcher.log.SetBackgroundColour(wxRED)
+
+ #Se la piattaforma è NT allora ferma il thread
+ if os.environ.has_key('OS'):
+ self.MngThr1.wait()
+ else:
+ #Se non c'è nessun TC del HIL allora colora di grigio i led relativi e setta lo stopflgHIL a 1
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ exec(tmpList[0])
+ for count in range(self.TD_NumTdXInstr[1]-self.TD_NumTdXInstr[0]):
+ LED_STATUS.append([])
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n' #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ tmpList[2]='stopflgHIL=1\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+
+
+
+ #---------------------------------LANCIO I TEST PER NSI ((solo se almeno 1 TC è selezionato)
+ self.MngThr1.clear()
+ if InstrExec[1]==1:
+ try:
+ #modalità RUN
+ if not(self.wnd.launcher.run.GetSelection()):
+ RUN_NSI(self)
+ #modalità DEBUG
+ else:
+ DEBUG_NSI(self)
+ finally:
+ #Se la piattaforma è NT allora ferma il thread
+ if os.environ.has_key('OS'):
+ self.MngThr1.wait()
+ else:
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ exec(tmpList[0])
+ for count in range(self.TD_NumTdXInstr[2]-self.TD_NumTdXInstr[1]):
+ LED_STATUS.append([])
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n' #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ tmpList[3]='stopflgNSI=1\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+
+ #---------------------------------LANCIO I TEST PER LO SPIL ((solo se almeno 1 TC è selezionato)
+ self.MngThr1.clear()
+ if InstrExec[2]==1:
+ try:
+ #modalità RUN
+ if not(self.wnd.launcher.run.GetSelection()):
+ RUN_SPIL(self)
+ #modalità DEBUG
+ else:
+ DEBUG_SPIL(self)
+ finally:
+ #Se la piattaforma è NT allora ferma il thread
+ if os.environ.has_key('OS'):
+ self.MngThr1.wait()
+
+
+ else:
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ exec(tmpList[0])
+ for count in range(self.TD_NumTdXInstr[3]-self.TD_NumTdXInstr[2]):
+ LED_STATUS.append([])
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n' #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ tmpList[4]='stopflgSPIL=1\n' #Se non sono stati settati test x SPIL metto il flag a 1
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+
+
+ #----------------------------------------------------------------------------------------------------------
+ #...
+ #...
+ #...
+
+
+ #Chiudo il file di log
+ filelog=open(self.LauncherPath+'\\log.txt','a+')
+ filelog.write("\nSTOP TESTS SESSION:%s"%time.ctime(time.time()))
+ filelog.close()
+
+
+
+############################################################################################################
+# FUNCTION NAME : RUN_NSI
+# FUNCTION DESCRIPTION: Lancia i TD per NSI, per ogni TD:
+# - crea compile.bat e lo lancia
+# - se compilazione Ok-->crea run.bat e lo lancia
+# - aggiorna il file led_status.txt
+# I parametri dei Tc selezionati, del tipo di ecu e del path sono scritti nel file
+# command.txt dopo la compilazione nella cartella del TD
+# Il risultato dei Tc è passato nel file result.txt creato nella cartella del TD
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def RUN_NSI(self):
+ filelog=open('log.txt','a+')
+ exec(self.EcuType) #EcuType='sviluppo'
+ NsiTestList=self.GlobalTestList[self.TD_NumTdXInstr[1]:self.TD_NumTdXInstr[2]]
+ #es: HilTestList=[[2, 2, 2, 0, 2, 1, 2, 2], [1, 2, 2, 2, 2, 1, 2, 2]]
+ NsiTD_DATA=self.TD_DATA[self.TD_NumTdXInstr[1]:self.TD_NumTdXInstr[2]]
+ #es: NsiTD_DATA=[['M:\\Work\\5sf.01\\Macro_Funzione2.0\\TD_Scot.6.5', 'td_glam', ['TD GLAM', 'Lambda OP', 'CA', 'CCGND', 'CCVCC', 'CCVBAT', 'plausibilit\xe0', 'riscaldatori', 'CC GNDriscaldatore']],
+ # ['M:\\Work\\5sf.01\\Macro_Funzione2.0\\TD_Scot.6.6', 'td_glambis', ['TD GLAMbis', 'Lambda OP', 'CA', 'CCGND', 'CCVCC', 'CCVBAT', 'plausibilit\xe0', 'riscaldatori', 'CC GNDriscaldatore']]]
+ #eseguo i TD selezionati
+ print '\n\n\n\n\n\n\nSTART NSI TESTS SESSION'
+ tmpLed=[]#inizializzo la variabile temporanea che raccoglie lo stato dei led
+ for indexTD in range(len(NsiTestList)):
+ TypeTestListTD=NsiTestList[indexTD]
+ TD_DATA=NsiTD_DATA[indexTD]
+ try:
+ if (TypeTestListTD.count(1) or TypeTestListTD.count(2)): #non eseguo se tutti i TC sono NO
+ path=TD_DATA[0] #es: path='M:\Work\5sf.01\Macro_Funzione2.0\TD_Scot.6.5'
+ #se per qualsiasi motivo alla partenza si ha il file result.txt f=open(str(path)+r'\result.txt','r+')
+ if (os.path.exists(str(path)+r'\result.txt')):
+ os.remove(str(path)+r'\result.txt')
+ #Creo il compile.bat
+ MSDevDir="set MSDevDir="+self.NSIMSDevDir
+ MSVCDir="\n\nset MSVCDir="+self.NSIMSVCDir
+ NSIDir="\n\nset NSIDir="+self.NSIDir
+ PATH="\n\nset PATH=%PATH%;%MSDevDir%\BIN;%MSVCDir%\BIN;"
+ #includo le librerie presenti nel progetto
+ IncludeLib='\n\nset INCLUDE=%INCLUDE%;%MSVCDir%\INCLUDE;%MSVCDir%\MFC\INCLUDE;%MSVCDir%\ATL\INCLUDE;%NSIDir%\INC;'
+ SetLib='\n\nset LIB=%LIB%;%MSVCDir%\LIB;%MSVCDir%\MFC\LIB;%NSIDir%\LIB;'
+ for PathLib in glob.glob(self.CurrentPylibPath):
+ IncludeLib=IncludeLib+str(PathLib)+';'
+ SetLib=SetLib+str(PathLib)+';'
+ #es: set INCLUDE=M:\Work\NSI_00\Lib\TESTLAUNCHERVS20_BOL;M:\Work\NSI_00\Lib\modello;M:\Work\NSI_00\Lib\LibFirstIni;
+
+ #mi metto nella directory della TD
+ CDTD='\n\ncd '+str(path)
+ #es: cd M:\Work\NSI_00\Macro_FunzioneNSI1\NomeTD1.5
+
+ #mi posiziono sul disco della TD
+ Drive='\n\n'+os.path.splitdrive(str(path))[0]
+ #es: M:
+
+ #lancio la compilazione fornendo in uscita nel file make.log l'esito della compilazione
+ command='\n\nmsdev '+ TD_DATA[1]+'.dsp /MAKE '+'"'+TD_DATA[1]+' - Win32 Debug"'+' /USEENV /OUT make.log'
+ #es: msdev Id_TxMsg.dsp /MAKE "Id_TxMsg - Win32 Debug" /USEENV /OUT make.log
+
+ #scrivo il .bat e lo eseguo
+ filebat=open('compile.bat','w+')
+ filebat.write(MSDevDir)
+ filebat.write(MSVCDir)
+ filebat.write(NSIDir)
+ filebat.write(PATH)
+ filebat.write(IncludeLib)
+ filebat.write(SetLib)
+ filebat.write(CDTD)
+ filebat.write(Drive)
+ filebat.write(command)
+ filebat.close()
+ #Lancio la compilazione
+ str2exe=str(self.LauncherPath)+'\compile'
+ #se per qualsiasi motivo alla partenza si ha il file result.txt f=open(str(path)+r'\result.txt','r+')
+ if (os.path.exists(str(path)+r'\make.log')):
+ os.remove(str(path)+r'\make.log')
+ os.system(str2exe) #1 se KO
+ if (os.path.exists(str(path)+r'\make.log')):
+ fileerror=open(str(path)+'\make.log','r')
+ testo=fileerror.read()
+ errorstr=testo.splitlines()[-1]
+ fileerror.close()
+ error=errorstr[string.find(errorstr,'error(s)',0)-2]
+ #In caso di esito positivo creo il file command.txt in cui passo alcuni parametri utili per il test
+ if int(error)==0:
+ commandfile=open(str(path)+'\command.txt','w+')
+ commandfile.write(str(TypeTestListTD)) #test case selezionati es: [0, 0, 0, 2, 0, 0, 0, 0, 0, 0]
+ commandfile.write('\n'+EcuType) #tipo di ecu es: sviluppo
+ commandfile.write('\n'+path) #path della TD stessa es: M:\Work\NSI_00\Macro_FunzioneNSI1\NomeTD1.5
+ commandfile.write('\n'+self.LauncherPath) #path del launcher
+ commandfile.close()
+ #sempre in caso di compilazione positiva creo il .bat per il lancio del .exe
+ #vado a cercare dov'è il file first.ini tra le librerie
+ firstiniDIR=glob.glob(self.CurrentPylibPath+r'\first.ini')
+ # In base a al tipo di ECU passo un second.ini diverso
+ if EcuType=='sviluppo':
+ secondiniDIR=glob.glob(self.CurrentPylibPath+r'\second_DEV.ini')
+ else: #se è di produzione
+ secondiniDIR=glob.glob(self.CurrentPylibPath+r'\second_PROD.ini')
+ #es:
+ command='\n\n'+str(path)+'\\Debug\\'+ TD_DATA[1]+'.exe '+'"'+firstiniDIR[0]+'"'+' 0x50 '+'"'+secondiniDIR[0]+'"'
+ filebat=open('run.bat','w+')
+ filebat.write(CDTD)
+ filebat.write(Drive)
+ #Aggiunta nella variabile d'ambiente LIB i path delle librerie del progetto
+ filebat.write(SetLib)
+ filebat.write(command)
+ filebat.close()
+ #lancio il .bat
+ str2exe=str(self.LauncherPath)+r'\run'
+ os.system(str2exe)
+
+ #Quando il test è finito leggo lo stato dei led nel file result.txt con formato es: [0,1,1,3,2,1]
+ f=open(str(path)+r'\result.txt','r+')
+ TDresult=f.readline()
+ str2exec='tmpLed.append('+TDresult+')'
+ f.close()
+ exec(str2exec)
+
+ #Verifico anche che i test non abbiano avuto problemi nell'esecuzione.
+
+ if map(CompList,TypeTestListTD,TDresult).count(0)>0:
+ filelog.write("\n TEST %s FALLITO\n"%(TD_DATA[2][0]))
+ else:
+ filelog.write("\n TEST %s ESEGUITO\n"%(TD_DATA[2][0]))
+ #Coloro i led della grafica
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines() #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ exec(tmpList[0])
+ LED_STATUS=LED_STATUS+tmpLed
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ #una volta scritto l'esito dei TC nel LED_STATUS resetto la var temporanea
+ tmpLed=[]
+ f=open('led.flg','w+');f.close()
+ else:
+ filelog.write("\n**********\nTD %s FALLITA: compilazione fallita\n %s"%(TD_DATA[2][0],testo))
+ filelog.write("\n**********\n")
+## self.wnd.launcher.log.SetBackgroundColour(wxRED)
+ tmpLed.append([])
+ else:
+ filelog.write("\n**********\nTD %s FALLITA: compilazione non possibile\n Controllare l'installazione NSI"%(TD_DATA[2][0]))
+ filelog.write("\n**********\n")
+## self.wnd.launcher.log.SetBackgroundColour(wxRED)
+ tmpLed.append([])
+ else:
+ tmpLed.append([])
+
+ except:
+ tmpLed.append([])
+ (ErrorType,ErrorValue,ErrorTB)=sys.exc_info()
+ filelog.write("\n**********\nTD %s FALLITA:\nTIPO:%s\nTRACE:\n"%(TD_DATA[2][0],ErrorValue))
+ traceback.print_exc(None,filelog)
+ filelog.write("**********\n")
+ filelog.close()
+ print ("TD %s FALLITA"%TD_DATA[2][0])
+## self.wnd.launcher.log.SetBackgroundColour(wxRED)
+ #Finita la sessione di test per questo strumento setto a 1 i flag di stopInstr e stopflgNSI
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ exec(tmpList[0])
+ LED_STATUS=LED_STATUS+tmpLed
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n' #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ tmpList[1]='stopInstr=1\n'
+ tmpList[3]='stopflgNSI=1\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+ filelog.close()
+
+############################################################################################################
+# FUNCTION NAME : DEBUG_NSI
+# FUNCTION DESCRIPTION: Lancia il primo TD selezionato per NSI in modalità debug
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def DEBUG_NSI(self):
+ exec(self.EcuType) #EcuType='sviluppo'
+ NsiTestList=self.GlobalTestList[self.TD_NumTdXInstr[1]:self.TD_NumTdXInstr[2]]
+ NsiTD_DATA=self.TD_DATA[self.TD_NumTdXInstr[1]:self.TD_NumTdXInstr[2]]
+ try:
+ print"\n\n\n\n\n\n\nNSI debug session..."
+ if len(NsiTestList)!=0:
+ #vado in debug sul primo TD selezionato
+ for indexTD in range(len(NsiTestList)):
+ if (NsiTestList[indexTD].count(1) or NsiTestList[indexTD].count(2)): #non considero se tutti i TC sono NO
+ break
+ TypeTestListTD=NsiTestList[indexTD]
+ TD_DATA=NsiTD_DATA[indexTD]
+ if (TypeTestListTD.count(1) or TypeTestListTD.count(2)): #non eseguo se tutti i TC sono NO
+ path=TD_DATA[0] #es: path='M:\Work\5sf.01\Macro_Funzione2.0\TD_Scot.6.5'
+
+ #Creo il compile.bat
+ MSDevDir="set MSDevDir="+self.NSIMSDevDir
+ MSVCDir="\n\nset MSVCDir="+self.NSIMSVCDir
+ NSIDir="\n\nset NSIDir="+self.NSIDir
+ PATH="\n\nset PATH=%PATH%;%MSDevDir%\BIN;%MSVCDir%\BIN;"
+ #includo le librerie presenti nel progetto
+ IncludeLib='\n\nset INCLUDE=%INCLUDE%;%MSVCDir%\INCLUDE;%MSVCDir%\MFC\INCLUDE;%MSVCDir%\ATL\INCLUDE;%NSIDir%\INC;'
+ SetLib='\n\nset LIB=%LIB%;%MSVCDir%\LIB;%MSVCDir%\MFC\LIB;%NSIDir%\LIB;'
+ for PathLib in glob.glob(self.CurrentPylibPath):
+ IncludeLib=IncludeLib+str(PathLib)+';'
+ SetLib=SetLib+str(PathLib)+';'
+ CDTD='\n\ncd '+str(path)
+ command='\n\nmsdev '+ TD_DATA[1]+'.dsw /USEENV'
+ Drive='\n\n'+os.path.splitdrive(str(path))[0]
+ commandfile=open(str(path)+'\command.txt','w+')
+ commandfile.write(str(TypeTestListTD))
+ commandfile.write('\n'+EcuType)
+ commandfile.write('\n'+path)
+ commandfile.write('\n'+self.LauncherPath) #path del launcher
+ commandfile.close()
+ filebat=open('run.bat','w+')
+ filebat.write(MSDevDir)
+ filebat.write(MSVCDir)
+ filebat.write(NSIDir)
+ filebat.write(PATH)
+ filebat.write(IncludeLib)
+ filebat.write(SetLib)
+ filebat.write(CDTD) #es: cd M:\Work\NSI_00\Macro_FunzioneNSI1\NomeTD1.5
+ filebat.write(Drive) #es: M:
+ filebat.write(command) #es: msdev Id_TxMsg.dsw /USEENV
+ filebat.close()
+ str2exe=str(self.LauncherPath)+r'\run'
+ if os.system(str2exe):
+ filelog=open('log.txt','a+')
+ filelog.write("\n**********\nTD %s FALLITA: debug non possibile,\n Controllare l'installazione NSI"%(TD_DATA[2][0]))
+ filelog.write("\n**********\n")
+ filelog.close()
+## self.wnd.launcher.log.SetBackgroundColour(wxRED)
+
+ except:
+ (ErrorType,ErrorValue,ErrorTB)=sys.exc_info()
+ filelog.write("\n**********\nTD %s FALLITA:\nTIPO:%s\nTRACE:\n"%(TD_DATA[2][0],ErrorValue))
+ traceback.print_exc(None,filelog)
+ filelog.write("**********\n")
+ filelog.close()
+ print ("TD %s FALLITA"%TD_DATA[2][0])
+## self.wnd.launcher.log.SetBackgroundColour(wxRED)
+
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ tmpList[1]='stopInstr=1\n'
+ tmpList[2]='stopflgHIL=1\n'
+ tmpList[3]='stopflgNSI=1\n'
+ tmpList[4]='stopflgSPIL=1\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+
+
+############################################################################################################
+# FUNCTION NAME : RUN_SPIL
+# FUNCTION DESCRIPTION: Lancia i TD per SPIL, per ogni TD:
+# - xxxcrea compile.bat e lo lancia
+# - xxxse compilazione Ok-->crea run.bat e lo lancia
+# - xxxxaggiorna il file led_status.txt
+# xxxI parametri dei Tc selezionati, del tipo di ecu e del path sono scritti nel file
+# xxxcommand.txt dopo la compilazione nella cartella del TD
+# xxxIl risultato dei Tc è passato nel file result.txt creato nella cartella del TD
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambienter
+#
+############################################################################################################
+def RUN_SPIL(self):
+
+ filelog=open('log.txt','a+')
+ filelog.close()
+ try:
+ tmpLed=[]#inizializzo la variabile temporanea che raccoglie lo stato dei led
+ exec(self.EcuType) #EcuType='sviluppo'
+ #DIrectory di installazione dell'ISS
+ StartUpIssPath=os.path.dirname(self.IssInstall)
+ SpilTestList=self.GlobalTestList[self.TD_NumTdXInstr[2]:self.TD_NumTdXInstr[3]]
+ #es: SpilTestList=[[2, 2, 2, 0, 2, 1, 2, 2], [1, 2, 2, 2, 2, 1, 2, 2]]
+ SpilTD_DATA=self.TD_DATA[self.TD_NumTdXInstr[2]:self.TD_NumTdXInstr[3]]
+ #Inizializzazione: utile solo per la exception in caso di errore prima di entrare nel for dei TD
+ TD_DATA=SpilTD_DATA[0]
+ #es: SpilTD_DATA=[['M:\\Work\\5sf.01\\Macro_Funzione2.0\\TD_Scot.6.5', 'td_glam', ['TD GLAM', 'Lambda OP', 'CA', 'CCGND', 'CCVCC', 'CCVBAT', 'plausibilit\xe0', 'riscaldatori', 'CC GNDriscaldatore']],
+ # ['M:\\Work\\5sf.01\\Macro_Funzione2.0\\TD_Scot.6.6', 'td_glambis', ['TD GLAMbis', 'Lambda OP', 'CA', 'CCGND', 'CCVCC', 'CCVBAT', 'plausibilit\xe0', 'riscaldatori', 'CC GNDriscaldatore']]]
+ #eseguo i TD selezionati
+ print '\n\n\n\n\n\n\nSTART SPIL TESTS SESSION'
+
+ #Definizioni generali per la costruzione del file MatStrtp.m che lancerà la pre- elaborazione
+ #Ricavo il path del DD dal file load.cmm presente in M:\work\load.cmm, es:DD='Z:\\cdm\\meb\\4TV.dd'
+ f=open(os.path.split(self.ProjPath)[0]+"\\load.cmm",'r+')
+ testo=f.read()
+ f.close()
+ DD_start=string.find(testo,"DD='")
+ if DD_start>=0 :
+ DD_stop=string.find(testo,"\n",DD_start)
+ line=testo[DD_start:DD_stop]
+ exec(line)
+ #Ricavo il path del DD es:ProjectSyncPath='Z:\\'
+ Prj_start=string.find(testo,"ProjectSyncPath='")
+ if Prj_start>=0 :
+ Prj_stop=string.find(testo,"\n",Prj_start)
+ line=testo[Prj_start:Prj_stop]
+ exec(line)
+ #Mi serve la data dell'ultima modifica del DD in quanto
+ #se il .dd a cui ha puntato il DataDict.mat presente è cambiato allora devo ricreare il DataDict.mate
+ DDLastChangeInSec=str(os.stat(DD)[stat.ST_MTIME])
+
+
+ #SpilMatLib='M:\\Work\\4TV_SPIL_00\\LIB\\SPILMATLIB\n'
+ SpilMatLib=os.path.dirname(glob.glob(self.CurrentPrj+'\\Lib\\*\\SetCalib.m')[0]) #OK generale
+
+ DataDictPath=self.LauncherPath+'\\SpilTmp\\DD\\DataDict.mat' #con ricerca se il load.cmm è cambiato
+
+ CalibPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\calibfile.txt' #OK general
+ InputPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\varfile.txt' #OK general
+ EventPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\eventfile.txt' #OK general
+ EventVectorPath=self.LauncherPath+'\\SpilTmp\\Result\\EvtVectAll' #OK general
+ OutputNamePathSpil=self.LauncherPath+'\\SpilTmp\\Result\\outname.txt' #OK general
+ PowerOnPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\PowerOn.txt' #OK general
+ #IRPath='M:\\Work\\4TV_SPIL_00\\LIB\\SPIL4TVST280\\IRlist' #ricerca del file IRlist
+ if glob.glob(self.CurrentPrj+'\\Lib\\*\\IRlist.m')!=[]:
+ IRPath=os.path.splitext(glob.glob(self.CurrentPrj+'\\Lib\\*\\IRlist.m')[0])[0] #OK generale
+ else:
+ IRPath=''
+ IRlistCkdPath=self.LauncherPath+'\\SpilTmp\\Result\\IRlistCkd' #OK generale
+
+ #OutputPathSpil='M:\\SPILLAUNCHER\\SpilTmp\\Result\\output.txt'
+ OutputPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\output.txt'
+ #Dir2Zip="M:\\SPILLAUNCHER\\SpilTmp"
+ Dir2Zip=self.LauncherPath+'\\SpilTmp'
+
+
+ #Lista della START di ISS
+ #Rinomino l'eventuale T32.cmm originale in T32orig.cmm
+ if os.path.exists(StartUpIssPath+'\\T32.cmm'):
+ if not(os.path.exists(StartUpIssPath+'\\T32orig.cmm')):
+ shutil.copy(StartUpIssPath+'\\T32.cmm',StartUpIssPath+'\\T32orig.cmm')
+ StartUpIssFile=['do '+self.LauncherPath+'\\SpilTmp\\Result\\IssStrtp.cmm\n']
+ f=open(StartUpIssPath+'\\T32.cmm','w+')
+ f.writelines(StartUpIssFile)
+ f.close()
+
+ #ProjectPath="C:\\SPIL\\WORK\\SET4TV,02_24"
+ ProjectLibPath=os.path.dirname(glob.glob(self.CurrentPrj+'\\Lib\\*\\Init.cmm')[0])
+ #LibPath="C:\\SPIL\\WORK\\PROGETTO_4TV\\LIB\\SPILSCRIPT"
+ LibPath=os.path.dirname(glob.glob(self.CurrentPrj+'\\Lib\\*\\SPIL.cmm')[0])
+ #Leggo il settaggio del coverage
+ CovFlg=str(self.wnd.Develop.Spil.CovBox.GetValue())
+
+ for indexTD in range(len(SpilTestList)):
+ TypeTestListTD=SpilTestList[indexTD]
+ TD_DATA=SpilTD_DATA[indexTD]
+ #Inizializzo il LED_STATUS
+ TdLed=[]
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines() #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ exec(tmpList[0])
+ LED_STATUS.append(TdLed)
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+
+ if (TypeTestListTD.count(1) or TypeTestListTD.count(2)): #non eseguo se tutti i TC sono NO
+ TimeStartTest = time.time() #Tempo inizio test
+ path=TD_DATA[0] #es: path='M:\Work\5sf.01\Macro_Funzione2.0\TD_Scot.6.5'
+
+ #Definizioni particolari del TD per la costruzione del file MatStrtp.m che lancerà la pre- elaborazione
+ #CalibGenPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_CAL_GEN.mat'
+ CalibGenPathSdt=path+'\\'+TD_DATA[2][0]+'_CAL_GEN.mat'#OK td
+ #TollPath='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\TOLL_SM06_GEN.m' #da script
+ TollPath=path+'\\TOLL_'+TD_DATA[2][0]+'_GEN.m'#OK tc
+ #ReportPath='M:\\WORK\\REPORTS\\report.txt'
+ #ExtName è l'estensione da aggiungere alla cartella del report per individuare il gg hh mm ss del test
+ ExtName="("+str(time.localtime()[2])+"gg)("+str(time.localtime()[3])+"hh)("+str(time.localtime()[4])+"mm)("+str(time.localtime()[5])+"ss)"
+ ReportPath=self.ReportSpil+'\\'+TD_DATA[2][0]+ExtName+'\\report.txt'
+ #Apro il file di report
+ os.makedirs(os.path.dirname(ReportPath))
+ f=open(ReportPath,'w')
+ f.close()
+
+ PrimoTc=1
+ for nTC in range(len(TypeTestListTD)):
+ if TypeTestListTD[nTC]!=0:
+ #Se esiste il file result.txt allora lo cancello
+ if os.path.exists(self.LauncherPath+'\\result.txt'):
+ os.remove(self.LauncherPath+'\\result.txt')
+ #FILE IssStrtp
+ SaveCov=''
+ LoadCov=''
+ CovView=''
+ #se è abilitato il flag del coverage salvo il contenuto del cov nella cartella del report
+ #e a partire dal 2° TC lanciato carico il TC precedente
+ if CovFlg=="1":
+ SaveCov='a.coverage.save '+self.ReportSpil+'\\'+TD_DATA[2][0]+ExtName+'\\cov'
+ CovView='a.coverage.listfunc\n'
+ if PrimoTc==0:
+ LoadCov='a.coverage.load '+self.ReportSpil+'\\'+TD_DATA[2][0]+ExtName+'\\cov\n'
+ IssStrtp=[
+ 'on error goto exception\n',\
+ '&ProjectLibPath="'+ProjectLibPath+'"\n',\
+ '&LauncherPath="'+self.LauncherPath+'\\SpilTmp\\Result'+'"\n',\
+ '&LibPath="'+LibPath+'"\n',\
+ 'cd &ProjectLibPath\n',\
+ '&StopDebugTime=0\n',\
+ '&CovFlg='+CovFlg+'\n',\
+ '&exec="&ProjectLibPath"+"\\t32.cmm"\n',\
+ 'do &exec\n',\
+ LoadCov,\
+ CovView,\
+ 'cd '+ProjectSyncPath+'\n',\
+ '&exec="'+LibPath+'\\SPIL.cmm"\n',\
+ 'do &exec\n',\
+ SaveCov,\
+ '\nquit\n',\
+ 'exception:\n',
+ 'OPEN #10 '+self.LauncherPath+'\\result.txt /Create\n',\
+ 'WRITE #10 %CONTINUE "0"\n',\
+ 'CLOSE #10\n',\
+ 'quit\n']
+
+ #individuo il nome
+ TCname=TD_DATA[2][nTC+1]
+ indexTC=TCname[string.find(TCname,"_TP_")+4:string.find(TCname,"_TP_")+6]
+ #Solo se è il primo Tc devo aggiungere 3 righe allo MatStop.m
+ if PrimoTc:
+ MatStop2=[" IssPath='"+StartUpIssPath+"';\n",\
+ ' GeneralReport(LauncherPath,IssPath,ReportPath)\n']
+ PrimoTc=0
+ else:
+ MatStop2=[]
+
+ #CalibTpPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_CAL_TP_01.mat'
+ CalibTpPathSdt=path+'\\'+TD_DATA[2][0]+'_CAL_TP_'+indexTC+'.mat'#OK tc
+ if not(os.path.exists(CalibTpPathSdt)):
+ CalibTpPathSdt=''
+
+ #InputPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_TP_02_in.mat'
+ InputPathSdt=path+'\\'+TD_DATA[2][0]+'_TP_'+indexTC+'_in.mat'#OK tc
+
+ #OutputPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_TP_02_ou.mat'
+ OutputPathSdt=path+'\\'+TD_DATA[2][0]+'_TP_'+indexTC+'_ou.mat'#OK tc
+
+ #TestpointPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_TP_02_tx.mat' #da script
+ TestpointPathSdt=path+'\\'+TD_DATA[2][0]+'_TP_'+indexTC+'_tx.mat'#OK tc
+ if not(os.path.exists(TestpointPathSdt)):
+ TestpointPathSdt=''
+
+ #Dove andare a salvare lo zip dei risultati
+ ZipNamePath=os.path.dirname(ReportPath)+'\\'+TD_DATA[2][0]+'_TP'+indexTC+'.zip'
+ #Dove andare a salvare le figure dei risultati
+ FigPath=os.path.dirname(ReportPath)+'\\TP_'+indexTC;
+ #Tipo di Test 1-->OL,2-->CL
+ if TypeTestListTD[nTC]==2:
+ TIPOTEST='CL'
+ else:
+ TIPOTEST='OL'
+ #Creazione della lista che poi sarà stampata
+ MatStrtp=["DD='"+DD+"';\n",\
+ "DataDictPath='"+DataDictPath+"';\n",\
+ "CalibGenPathSdt='"+CalibGenPathSdt+"';\n",\
+ "CalibTpPathSdt='"+CalibTpPathSdt+"';\n",\
+ "CalibPathSpil='"+CalibPathSpil+"';\n",\
+ "InputPathSdt='"+InputPathSdt+"';\n",\
+ "InputPathSpil='"+InputPathSpil+"';\n",\
+ "EventPathSpil='"+EventPathSpil+"';\n",\
+ "EventVectorPath='"+EventVectorPath+"';\n",\
+ "OutputPathSdt='"+OutputPathSdt+"';\n",\
+ "TestpointPathSdt='"+TestpointPathSdt+"';\n",\
+ "OutputNamePathSpil='"+OutputNamePathSpil+"';\n",\
+ "IRPath='"+IRPath+"';\n",\
+ "IRlistCkdPath='"+IRlistCkdPath+"';\n",\
+ "TollPath='"+TollPath+"';\n",\
+ "PowerOnPathSpil='"+PowerOnPathSpil+"';\n",\
+ "ProjectLibPath='"+ProjectLibPath+"';\n",\
+ "LauncherPath='"+self.LauncherPath+"';\n",\
+ "DDTime="+DDLastChangeInSec+";\n",\
+ "IOCerr='';\n",\
+ "try\n",\
+ ' cd '+SpilMatLib+'\n',\
+ ' fid=fopen(DataDictPath);\n',' if fid==-1\n',' DDparser(DD,DataDictPath,DDTime);\n',' else\n'," load(DataDictPath,'DDGenTime');\n",' if DDGenTime==DDTime\n'," fprintf('\\nUtilizzo il Data Dictionary già esistente DataDict.mat');\n",' else\n'," fprintf('\\nCreo DataDict.mat nuovo perchè l''esistente non è aggiornato...');\n",' DDparser(DD,DataDictPath,DDTime);\n',' end\n',' end\n',\
+ ' IOCerr=IOCdiag(DataDictPath,CalibGenPathSdt,CalibTpPathSdt,InputPathSdt,OutputPathSdt,TestpointPathSdt,TollPath);\n',' if ~isempty(IOCerr)\n'," error(' SDT NON VALIDA: ');\n"," end\n",\
+ ' SetCalib(CalibGenPathSdt,CalibTpPathSdt,CalibPathSpil,DataDictPath,IRPath,IRlistCkdPath);\n',\
+ ' SetVar(InputPathSdt,InputPathSpil,DataDictPath,EventPathSpil,EventVectorPath,IRlistCkdPath,PowerOnPathSpil,ProjectLibPath);\n',\
+ ' NameOut(OutputNamePathSpil,TollPath,DataDictPath);\n',\
+ "catch\n",\
+ " ResPath=[LauncherPath '\\result.txt'];\n",\
+ " fid = fopen(ResPath,'w+');\n",\
+ " fprintf(fid,'0');\n",\
+ " fclose(fid);\n\n",\
+ " LogPath=[LauncherPath '\log.txt'];\n",\
+ " ErrorLog=[' ' lasterr];\n",\
+ " ErrorLog = strrep(ErrorLog,'\\','\\\\');\n",\
+ " fid = fopen(LogPath,'a');\n",\
+ " fprintf(fid,'\\n Pre-processing error:\\n');\n",\
+ " fprintf(fid,ErrorLog);\n",\
+ " fprintf(fid,IOCerr);\n",\
+ " fclose(fid);\n",\
+ "end\n",\
+ 'clear all\n', "fprintf('\\n\\nFINE PRE-ELABORAZIONE');\n", 'quit\n']
+
+ MatStop1=["OutputPathSdt='"+OutputPathSdt+"';\n",\
+ "TestpointPathSdt='"+TestpointPathSdt+"';\n",\
+ "DataDictPath='"+DataDictPath+"';\n",\
+ "OutputPathSpil='"+OutputPathSpil+"';\n",\
+ "EventVectorPath='"+EventVectorPath+"';\n",\
+ "TollPath='"+TollPath+"';\n",\
+ "ReportPath='"+ReportPath+"';\n",\
+ "ZipNamePath='"+ZipNamePath+"';\n",\
+ "Dir2Zip='"+Dir2Zip+"';\n",\
+ "FigPath='"+FigPath+"';\n",\
+ "TIPOTEST='"+TIPOTEST+"';\n",\
+ "ResPath='"+self.LauncherPath+"\\result.txt';\n",\
+ "LauncherPath='"+self.LauncherPath+"';\n",\
+ "try\n",\
+ ' cd '+SpilMatLib+'\n']
+
+ MatStop3=[ 'FilterOut(OutputPathSdt,TestpointPathSdt,OutputPathSpil,DataDictPath,EventVectorPath,TollPath,ReportPath,ZipNamePath,Dir2Zip,FigPath,ResPath,TIPOTEST);\n',\
+ " fprintf('\\n\\nFINE POST-ELABORAZIONE');\n",\
+ "catch\n",\
+ " ResPath=[LauncherPath '\\result.txt'];\n",\
+ " fid = fopen(ResPath,'w+');\n",\
+ " fprintf(fid,'0');\n",\
+ " fclose(fid);\n\n",\
+ " LogPath=[LauncherPath '\log.txt'];\n",\
+ " ErrorLog=[' ' lasterr];\n",\
+ " ErrorLog = strrep(ErrorLog,'\\','\\\\');\n",\
+ " fid = fopen(LogPath,'a');\n",\
+ " fprintf(fid,'\\n Post-processing error:\\n');\n",\
+ " fprintf(fid,ErrorLog);\n",\
+ " fclose(fid);\n",\
+ "end\n",\
+ 'quit\n']
+ MatStop=MatStop1+MatStop2+MatStop3
+
+
+ #Se esistente ripulisco la cartella temporanea SpilTmp, altrimento la creo nuova
+ if os.path.exists(self.LauncherPath+'\\SpilTmp\\Result'):
+ for file in glob.glob(self.LauncherPath+'\\SpilTmp\\Result\\*.*'):
+ os.remove(file)
+ else:
+ os.makedirs(self.LauncherPath+'\\SpilTmp\\Result')
+
+ #Se non esistente creo nuova cartella DD
+ if not(os.path.exists(self.LauncherPath+'\\SpilTmp\\DD')):
+ os.makedirs(self.LauncherPath+'\\SpilTmp\\DD')
+
+
+ #Riga di lancio del MatStrtp.m
+ StartUpFile=" /r cd('"+self.LauncherPath+"\SpilTmp\Result');MatStrtp"
+ #Stampa del file MatStrtp.m
+ f=open(self.LauncherPath+'\\SpilTmp\\Result\\MatStrtp.m','w+')
+ f.writelines(MatStrtp)
+ f.close()
+ os.system(self.MtlbInstall+StartUpFile)
+ SPILcomment=""
+ # Se non c'è stato nessun problema nell'esecuzione dello MatStrtp. continua
+ if not(os.path.exists(self.LauncherPath+'\\result.txt')):
+
+ #Stampa del file IssStrtp.m
+ f=open(self.LauncherPath+'\\SpilTmp\\Result\\IssStrtp.cmm','w+')
+ f.writelines(IssStrtp)
+ f.close()
+ #Creo il RunIss.bat per lanciare l'ISS
+ CDTD='\ncd '+StartUpIssPath+'\n'+os.path.splitdrive(StartUpIssPath)[0]
+ command='\n'+self.IssInstall
+ #scrivo il .bat e lo eseguo
+ filebat=open(self.LauncherPath+'\\RunIss.bat','w+')
+ filebat.write(CDTD)
+ filebat.write(command)
+ filebat.close()
+ os.system(self.LauncherPath+'\\RunIss.bat')
+ if not(os.path.exists(self.LauncherPath+'\\result.txt')):
+
+ #Stampa del file startup.m
+ StartUpFile=" /r cd('"+self.LauncherPath+"\SpilTmp\Result');MatStop"
+ #Stampa del file MatStop.m
+ os.makedirs(FigPath)
+ f=open(self.LauncherPath+'\\SpilTmp\\Result\\MatStop.m','w+')
+ f.writelines(MatStop)
+ f.close()
+ #se per qualsiasi motivo alla partenza si ha il file result.txt cancellalo
+ if (os.path.exists(self.LauncherPath+r'\result.txt')):
+ os.remove(self.LauncherPath+r'\result.txt')
+ os.system(self.MtlbInstall+StartUpFile)
+ else:
+ SPILcomment=" Errore PRACTICE, rilancia il test in modalità debug per maggiori info\n"
+ #Quando il test è finito leggo lo stato dei led nel file result.txt con formato es: [0,1,1,3,2,1]
+ f=open(self.LauncherPath+r'\result.txt','r+')
+ TcRes=f.readline()
+ f.close()
+
+ str2exec='TdLed.append('+TcRes+')'
+ exec(str2exec)
+ filelog=open('log.txt','a+')
+ if TcRes=='0':
+ filelog.write("\n TEST %s FALLITO\n%s"%(TCname,SPILcomment))
+ else:
+ filelog.write("\n TEST %s ESEGUITO\n"%(TCname))
+ filelog.close()
+ #Coloro i led della grafica
+ while (os.path.exists('led.flg')):
+ pass
+ f=open(self.LauncherPath+r'\led_status.txt','r+')
+ tmpList=f.readlines() #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ exec(tmpList[0])
+# TdLed.append(2)
+ LED_STATUS[-1]=TdLed
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ #una volta scritto l'esito dei TC nel LED_STATUS resetto la var temporanea
+ f=open('led.flg','w+');f.close()
+
+ #Aggiungo nello zip del TC il coverage cumulativo raggiunto col TC stesso
+ if CovFlg=="1":
+ myzip=zipfile.ZipFile(ZipNamePath,'a')
+ myzip.write(self.ReportSpil+'\\'+TD_DATA[2][0]+ExtName+'\\cov.acd')
+ myzip.close()
+
+
+ #Apro il file di report e compilo i campi NOT_DONE per i test case non eseguiti
+ else:
+ TdLed.append(0)
+ f=open(ReportPath,'a+')
+ NotDoneStr=['$TEST_CASE_RESULT_BEGIN\n',\
+ 'NOT_DONE\n',\
+ '$TEST_CASE_RESULT_END\n\n',\
+ '$ATTACHED_FILE_LIST_BEGIN\n',\
+ '$ATTACHED_FILE_LIST_END\n\n',\
+ '$TEST_CASE_RESULT_BEGIN\n',\
+ '$TEST_CASE_RESULT_END\n\n']
+ f.writelines(NotDoneStr)
+ f.close()
+ #Aggiungo al report i tag dei METRICS
+ # Calcolo tempo esecuzione test
+ TimeStopTest = time.time()
+ TimeEsecTest = '%.4f'%((TimeStopTest - TimeStartTest)/3600)
+ f=open(ReportPath,'a+')
+ MetricsStr=['$TEST_REPORT_METRICS_BEGIN\n',\
+ TimeEsecTest+'\n',\
+ '$TEST_REPORT_METRICS_END\n\n']
+ f.writelines(MetricsStr)
+ #Aggiungo al report i tag dei SETUP
+ if (os.path.exists(path+'\\LibraryList.txt')):
+ f=open(path+'\\LibraryList.txt','r+')
+ LibList=f.readlines()
+ f.close()
+ else:
+ LibList=['\nLibraryList.txt non trovata\n']
+ f=open(os.path.split(self.ProjPath)[0]+"\\load.cmm",'r+')
+ LoadList=f.readlines()
+ f.close()
+ f=open(ReportPath,'a+')
+ Setup=['$TEST_SETUP_BEGIN\n']+LibList+LoadList+['\n$TEST_SETUP_END\n\n']
+ f.writelines(Setup)
+ f.close()
+ except:
+ tmpLed.append([])
+ (ErrorType,ErrorValue,ErrorTB)=sys.exc_info()
+ filelog=open('log.txt','a+')
+ filelog.write("\n**********\nTD %s FALLITA:\nTIPO:%s\nTRACE:\n"%(TD_DATA[2][0],ErrorValue))
+ traceback.print_exc(None,filelog)
+ filelog.write("**********\n")
+ filelog.close()
+ print ("TD %s FALLITA"%TD_DATA[2][0])
+ self.wnd.launcher.log.SetBackgroundColour(wxRED)
+
+ #Finita la sessione di test per questo strumento setto a 1 i flag di stopInstr e stopflgSPIL
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ exec(tmpList[0])
+ LED_STATUS=LED_STATUS+tmpLed
+ tmpList[0]='LED_STATUS='+str(LED_STATUS)+'\n' #es: LED_STATUS=[[2, 2, 3, 3, 2, 3, 2, 2],[...]]
+ tmpList[1]='stopInstr=1\n'
+ tmpList[4]='stopflgSPIL=1\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+ filelog.close()
+ #Riporto gli startup originali
+ if (os.path.exists(StartUpIssPath+'\\T32orig.cmm')):
+ shutil.copy(StartUpIssPath+'\\T32orig.cmm',StartUpIssPath+'\\T32.cmm')
+ os.remove(StartUpIssPath+'\\T32orig.cmm')
+ else:
+ if (os.path.exists(StartUpIssPath+'\\T32.cmm')):
+ os.remove(StartUpIssPath+'\\T32.cmm')
+
+
+############################################################################################################
+# FUNCTION NAME : DEBUG_SPIL
+# FUNCTION DESCRIPTION: Lancia il primo TD selezionato per SPIL in modalità debug
+#
+# INPUT PARAMETERS:
+# 1) self: oggetto che contiene le proprietà di tutto l'ambiente
+#
+############################################################################################################
+def DEBUG_SPIL(self):
+ filelog=open('log.txt','a+')
+ try:
+ SpilTestList=self.GlobalTestList[self.TD_NumTdXInstr[2]:self.TD_NumTdXInstr[3]]
+ SpilTD_DATA=self.TD_DATA[self.TD_NumTdXInstr[2]:self.TD_NumTdXInstr[3]]
+ #Leggo tempo settato per fermarsi e rimetto il default a 0
+ Time2Stop=self.wnd.Develop.Spil.DebugTimeText.GetValue()
+ self.wnd.Develop.Spil.DebugTimeText.SetValue('0')
+ #Default del flag di coverage
+ self.wnd.Develop.Spil.CovBox.SetValue(False)
+ print"\n\n\n\n\n\n\nSpil debug session..."
+ if len(SpilTestList)!=0:
+ #vado in debug sul primo TD selezionato
+ for indexTD in range(len(SpilTestList)):
+ if (SpilTestList[indexTD].count(1) or SpilTestList[indexTD].count(2)): #non considero se tutti i TC sono NO
+ break
+ TypeTestListTD=SpilTestList[indexTD]
+ TD_DATA=SpilTD_DATA[indexTD]
+ if (TypeTestListTD.count(1) or TypeTestListTD.count(2)): #non eseguo se tutti i TC sono NO
+ path=TD_DATA[0] #es: path='M:\Work\5sf.01\Macro_Funzione2.0\TD_Scot.6.5'
+
+ #Ricavo il path del DD dal file load.cmm presente in M:\work\load.cmm, es:DD='Z:\\cdm\\meb\\4TV.dd'
+ f=open(os.path.split(self.ProjPath)[0]+"\\load.cmm",'r+')
+ testo=f.read()
+ f.close()
+ DD_start=string.find(testo,"DD='")
+ if DD_start>=0 :
+ DD_stop=string.find(testo,"\n",DD_start)
+ line=testo[DD_start:DD_stop]
+ exec(line)
+ #Ricavo il path del DD es:ProjectSyncPath='Z:\\'
+ Prj_start=string.find(testo,"ProjectSyncPath='")
+ if Prj_start>=0 :
+ Prj_stop=string.find(testo,"\n",Prj_start)
+ line=testo[Prj_start:Prj_stop]
+ exec(line)
+ #Mi serve la data dell'ultima modifica del DD in quanto
+ #se il .dd a cui ha puntato il DataDict.mat presente è cambiato allora devo ricreare il DataDict.mate
+ DDLastChangeInSec=str(os.stat(DD)[stat.ST_MTIME])
+
+ tmpLed=[]#inizializzo la variabile temporanea che raccoglie lo stato dei led
+
+ #Definizioni generali per la costruzione del file MatStrtp.m che lancerà la pre- elaborazione
+
+ #SpilMatLib='M:\\Work\\4TV_SPIL_00\\LIB\\SPILMATLIB\n'
+ SpilMatLib=os.path.dirname(glob.glob(self.CurrentPrj+'\\Lib\\*\\SetCalib.m')[0]) #OK generale
+
+ DataDictPath=self.LauncherPath+'\\SpilTmp\\DD\\DataDict.mat' #con ricerca se il load.cmm è cambiato
+
+ CalibPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\calibfile.txt' #OK general
+ InputPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\varfile.txt' #OK general
+ EventPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\eventfile.txt' #OK general
+ EventVectorPath=self.LauncherPath+'\\SpilTmp\\Result\\EvtVectAll.mat' #OK general
+ OutputNamePathSpil=self.LauncherPath+'\\SpilTmp\\Result\\outname.txt' #OK general
+ PowerOnPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\PowerOn.txt' #OK general
+ #OutputPathSpil='M:\\SPILLAUNCHER\\SpilTmp\\Result\\output.txt'
+ OutputPathSpil=self.LauncherPath+'\\SpilTmp\\Result\\output.txt'
+ #Dir2Zip="M:\\SPILLAUNCHER\\SpilTmp"
+ Dir2Zip=self.LauncherPath+'\\SpilTmp'
+ StartUpIssPath=os.path.dirname(self.IssInstall)
+ #IRPath='M:\\Work\\4TV_SPIL_00\\LIB\\SPIL4TVST280\\IRlist' #ricerca del file IRlist
+ if glob.glob(self.CurrentPrj+'\\Lib\\*\\IRlist.m')!=[]:
+ IRPath=os.path.splitext(glob.glob(self.CurrentPrj+'\\Lib\\*\\IRlist.m')[0])[0] #OK generale
+ else:
+ IRPath=''
+ IRlistCkdPath=self.LauncherPath+'\\SpilTmp\\Result\\IRlistCkd' #OK generale
+
+ #ProjectPath="C:\\SPIL\\WORK\\SET4TV,02_24"
+ ProjectLibPath=os.path.dirname(glob.glob(self.CurrentPrj+'\\Lib\\*\\Init.cmm')[0])
+ #LibPath="C:\\SPIL\\WORK\\PROGETTO_4TV\\LIB\\SPILSCRIPT"
+ LibPath=os.path.dirname(glob.glob(self.CurrentPrj+'\\Lib\\*\\SPIL.cmm')[0])
+ IssStrtp=['&ProjectLibPath="'+ProjectLibPath+'"\n',\
+ '&LauncherPath="'+self.LauncherPath+'\\SpilTmp\\Result'+'"\n',\
+ '&LibPath="'+LibPath+'"\n',\
+ 'cd &ProjectLibPath\n',\
+ '&StopDebugTime='+Time2Stop+'.\n',\
+ '&CovFlg=0\n',\
+ '&exec="&ProjectLibPath"+"\\t32.cmm"\n',\
+ 'do &exec\n',\
+ 'cd '+ProjectSyncPath+'\n',\
+ '&exec="'+LibPath+'\\SPIL.cmm"\n',\
+ 'do &exec\n']
+ #Definizioni particolari del TD per la costruzione del file MatStrtp.m che lancerà la pre- elaborazione
+ #CalibGenPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_CAL_GEN.mat'
+ CalibGenPathSdt=path+'\\'+TD_DATA[2][0]+'_CAL_GEN.mat'#OK td
+ #TollPath='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\TOLL_SM06_GEN.m' #da script
+ TollPath=path+'\\TOLL_'+TD_DATA[2][0]+'_GEN.m'#OK tc
+
+
+ #ReportPath='M:\\WORK\\REPORTS\\SM06_16143550\\report.txt'
+ #ExtName è l'estensione da aggiungere alla cartella del report per individuare il gg hh mm ss del test
+ ExtName="("+str(time.localtime()[2])+"gg)("+str(time.localtime()[3])+"hh)("+str(time.localtime()[4])+"mm)("+str(time.localtime()[5])+"ss)"
+ ReportPath=self.ReportSpil+'\\'+TD_DATA[2][0]+ExtName+'\\report.txt'
+ #Apro il file di report
+ os.makedirs(os.path.dirname(ReportPath))
+
+ #creo il file di report e appendo i tag dei SETUP
+ if (os.path.exists(path+'\\LibraryList.txt')):
+ f=open(path+'\\LibraryList.txt','r+')
+ LibList=f.readlines()
+ f.close()
+ else:
+ LibList=['\nLibraryList.txt non trovata\n']
+ f=open(os.path.split(self.ProjPath)[0]+"\\load.cmm",'r+')
+ LoadList=f.readlines()
+ f.close()
+ f=open(ReportPath,'w')
+ Setup=['$TEST_SETUP_BEGIN\n']+LibList+LoadList+['\n$TEST_SETUP_END\n\n']
+ f.writelines(Setup)
+ f.close()
+
+ for nTC in range(len(TypeTestListTD)):
+ if TypeTestListTD[nTC]!=0:
+ TCname=TD_DATA[2][nTC+1]
+ indexTC=TCname[string.find(TCname,"_TP_")+4:string.find(TCname,"_TP_")+6]
+
+ #CalibTpPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_CAL_TP_01.mat'
+ CalibTpPathSdt=path+'\\'+TD_DATA[2][0]+'_CAL_TP_'+indexTC+'.mat'#OK tc
+ if not(os.path.exists(CalibTpPathSdt)):
+ CalibTpPathSdt=''
+
+ #InputPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_TP_02_in.mat'
+ InputPathSdt=path+'\\'+TD_DATA[2][0]+'_TP_'+indexTC+'_in.mat'#OK tc
+
+ #OutputPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_TP_02_ou.mat'
+ OutputPathSdt=path+'\\'+TD_DATA[2][0]+'_TP_'+indexTC+'_ou.mat'#OK tc
+
+ #TestpointPathSdt='M:\\Work\\4TV_SPIL_00\\MACRO_SFTM\\TD_SM06_4TV\\SM06_TP_02_tx.mat' #da script
+ TestpointPathSdt=path+'\\'+TD_DATA[2][0]+'_TP_'+indexTC+'_tx.mat'#OK tc
+ if not(os.path.exists(TestpointPathSdt)):
+ TestpointPathSdt=''
+
+ #Dove andare a salvare lo zip dei risultati
+ ZipNamePath=os.path.dirname(ReportPath)+'\\'+TD_DATA[2][0]+'_TP'+indexTC+'.zip'
+ #Dove andare a salvare le figure dei risultati
+ FigPath=os.path.dirname(ReportPath)+'\\TP_'+indexTC;
+ #Tipo di Test 1-->OL,2-->CL
+ if TypeTestListTD[nTC]==2:
+ TIPOTEST='CL'
+ else:
+ TIPOTEST='OL'
+ #Creazione della lista che poi sarà stampata
+ MatStrtp=['cd '+SpilMatLib+'\n',\
+ "DD='"+DD+"';\n",\
+ "DataDictPath='"+DataDictPath+"';\n",\
+ "CalibGenPathSdt='"+CalibGenPathSdt+"';\n",\
+ "CalibTpPathSdt='"+CalibTpPathSdt+"';\n",\
+ "CalibPathSpil='"+CalibPathSpil+"';\n",\
+ "InputPathSdt='"+InputPathSdt+"';\n",\
+ "InputPathSpil='"+InputPathSpil+"';\n",\
+ "EventPathSpil='"+EventPathSpil+"';\n",\
+ "EventVectorPath='"+EventVectorPath+"';\n",\
+ "OutputPathSdt='"+OutputPathSdt+"';\n",\
+ "TestpointPathSdt='"+TestpointPathSdt+"';\n",\
+ "OutputNamePathSpil='"+OutputNamePathSpil+"';\n",\
+ "IRPath='"+IRPath+"';\n",\
+ "IRlistCkdPath='"+IRlistCkdPath+"';\n",\
+ "TollPath='"+TollPath+"';\n",\
+ "PowerOnPathSpil='"+PowerOnPathSpil+"';\n",\
+ "ProjectLibPath='"+ProjectLibPath+"';\n",\
+ "DDTime="+DDLastChangeInSec+";\n",\
+ 'fid=fopen(DataDictPath);\n','if fid==-1\n',' DDparser(DD,DataDictPath,DDTime);\n','else\n'," load(DataDictPath,'DDGenTime');\n",' if DDGenTime==DDTime\n'," fprintf('\\nUtilizzo il Data Dictionary già esistente DataDict.mat');\n",' else\n'," fprintf('\\nCreo DataDict.mat nuovo perchè l''esistente non è aggiornato...');\n",' DDparser(DD,DataDictPath,DDTime);\n',' end\n','end\n',\
+ 'SetCalib(CalibGenPathSdt,CalibTpPathSdt,CalibPathSpil,DataDictPath,IRPath,IRlistCkdPath);\n',\
+ 'SetVar(InputPathSdt,InputPathSpil,DataDictPath,EventPathSpil,EventVectorPath,IRlistCkdPath,PowerOnPathSpil,ProjectLibPath);\n',\
+ 'NameOut(OutputNamePathSpil,TollPath,DataDictPath);\n',\
+ 'clear all\n', "fprintf('\\n\\nFINE PRE-ELABORAZIONE');\n", '%quit\n']
+
+
+ MatStop1=['cd '+SpilMatLib+'\n',\
+ "OutputPathSdt='"+OutputPathSdt+"';\n",\
+ "TestpointPathSdt='"+TestpointPathSdt+"';\n",\
+ "DataDictPath='"+DataDictPath+"';\n",\
+ "OutputPathSpil='"+OutputPathSpil+"';\n",\
+ "EventVectorPath='"+EventVectorPath+"';\n",\
+ "TollPath='"+TollPath+"';\n",\
+ "ReportPath='"+ReportPath+"';\n",\
+ "ZipNamePath='"+ZipNamePath+"';\n",\
+ "Dir2Zip='"+Dir2Zip+"';\n",\
+ "FigPath='"+FigPath+"';\n",\
+ "TIPOTEST='"+TIPOTEST+"';\n",\
+ "ResPath='"+self.LauncherPath+"\\result.txt';\n"]
+
+ MatStop2=["LauncherPath='"+self.LauncherPath+"';\n",\
+ "IssPath='"+StartUpIssPath+"';\n",\
+ 'GeneralReport(LauncherPath,IssPath,ReportPath)\n']
+
+ MatStop3=['FilterOut(OutputPathSdt,TestpointPathSdt,OutputPathSpil,DataDictPath,EventVectorPath,TollPath,ReportPath,ZipNamePath,Dir2Zip,FigPath,ResPath,TIPOTEST);\n',\
+ "fprintf('\\n\\nFINE POST-ELABORAZIONE');\n",\
+ '%quit\n']
+ MatStop=MatStop1+MatStop2+MatStop3
+
+ #Se esistente ripulisco la cartella temporanea SpilTmp, altrimento la creo nuova
+ if os.path.exists(self.LauncherPath+'\\SpilTmp\\Result'):
+ for file in glob.glob(self.LauncherPath+'\\SpilTmp\\Result\\*.*'):
+ os.remove(file)
+ else:
+ os.makedirs(self.LauncherPath+'\\SpilTmp\\Result')
+
+ #Se non esistente creo nuova cartella DD
+ if not(os.path.exists(self.LauncherPath+'\\SpilTmp\\DD')):
+ os.makedirs(self.LauncherPath+'\\SpilTmp\\DD')
+
+
+ #Stampa del file MatStrtp.m
+ f=open(self.LauncherPath+'\\SpilTmp\\Result\\MatStrtp.m','w+')
+ f.writelines(MatStrtp)
+ f.close()
+ #Stampa del file IssStrtp.m
+ f=open(self.LauncherPath+'\\SpilTmp\\Result\\IssStrtp.cmm','w+')
+ f.writelines(IssStrtp)
+ f.close()
+ #Stampa del file MatStop.m
+ os.makedirs(FigPath)
+ f=open(self.LauncherPath+'\\SpilTmp\\Result\\MatStop.m','w+')
+ f.writelines(MatStop)
+ f.close()
+ # Scrivo solo x il primo dei TC selezionati
+
+ break
+
+ except:
+ (ErrorType,ErrorValue,ErrorTB)=sys.exc_info()
+ filelog.write("\n**********\nTD %s FALLITA:\nTIPO:%s\nTRACE:\n"%(TD_DATA[2][0],ErrorValue))
+ traceback.print_exc(None,filelog)
+ filelog.write("**********\n")
+ print ("TD %s FALLITA"%TD_DATA[2][0])
+ self.wnd.launcher.log.SetBackgroundColour(wxRED)
+ #Finita la sessione di test per questo strumento setto a 1 i flag di stopInstr e stopflgSPIL
+ while (os.path.exists('led.flg')):
+ pass
+ f=open('led_status.txt','r+')
+ tmpList=f.readlines()
+ tmpList[0]='LED_STATUS=[[]]\n'
+ tmpList[1]='stopInstr=0\n' #lascio a 0 altrimenti si colora il log di rosso
+ tmpList[4]='stopflgSPIL=1\n'
+ f.seek(0)
+ f.writelines(tmpList)
+ f.close()
+ f=open('led.flg','w+');f.close()
+ filelog.close()
+ #Riporto gli startup originali
+ if (os.path.exists(StartUpIssPath+'\\T32orig.cmm')):
+ shutil.copy(StartUpIssPath+'\\T32orig.cmm',StartUpIssPath+'\\T32.cmm')
+ os.remove(StartUpIssPath+'\\T32orig.cmm')
+ else:
+ if (os.path.exists(StartUpIssPath+'\\T32.cmm')):
+ os.remove(StartUpIssPath+'\\T32.cmm')
+
+
+
+
+
+app=App(0)
+app.MainLoop()
+
diff --git a/pypers/marelli/modulo2/maketable.py b/pypers/marelli/modulo2/maketable.py
new file mode 100755
index 0000000..d4730d1
--- /dev/null
+++ b/pypers/marelli/modulo2/maketable.py
@@ -0,0 +1,60 @@
+# maketable.py
+
+# non graphic
+N = 10
+for i in range(1, N+1):
+ for j in range(1, N+1):
+ print "%4d" % (i*j),
+ print
+
+# HTML
+def maketable(iterable, N):
+ iterable = iter(iterable)
+ print "<table border='1'>"
+ stop = False
+ while not stop:
+ print "<tr>"
+ for j in range(1, N+1):
+ try:
+ print "<td>%s</td>" % iterable.next(),
+ except StopIteration:
+ print "<td></td>"
+ stop = True
+ print "</tr>"
+ print "</table>"
+
+import tempfile, webbrowser, os, sys
+
+def showtable(iterable, N):
+ stdout = sys.stdout
+ fd, name = tempfile.mkstemp(suffix=".html")
+ sys.stdout = os.fdopen(fd, "w")
+ maketable(iterable, N)
+ webbrowser.open(name)
+ sys.stdout = stdout
+
+showtable((i*j for j in range(1, N+1) for i in range(1, N+1)), N)
+
+
+
+def get_files_with_ext(ext_set, d):
+ if not isinstance(ext_set, set):
+ ext_set = set([ext_set])
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ if ext.lower() in ext_set:
+ yield os.path.join(cwd, f)
+
+class Picture(object):
+ def __init__(self, pathname):
+ self.pathname = pathname
+ self.name = os.path.basename(pathname)
+ def __str__(self):
+ return "<img src=%r width=100>" % self.pathname
+
+if sys.platform == 'win32': drive = "C:\\"
+else: drive = "/"
+showtable(map(Picture, get_files_with_ext(".jpg", drive)), N)
+
+
diff --git a/pypers/marelli/modulo2/mutable_immutable.py b/pypers/marelli/modulo2/mutable_immutable.py
new file mode 100755
index 0000000..8a11466
--- /dev/null
+++ b/pypers/marelli/modulo2/mutable_immutable.py
@@ -0,0 +1,12 @@
+a = 1
+b = a
+
+a += 1
+
+print a, b
+
+a = [1]
+b = a
+a.append(1)
+
+print a, b
diff --git a/pypers/marelli/modulo2/prova.py b/pypers/marelli/modulo2/prova.py
new file mode 100755
index 0000000..ae4b0f6
--- /dev/null
+++ b/pypers/marelli/modulo2/prova.py
@@ -0,0 +1 @@
+while 1:pass
diff --git a/pypers/marelli/modulo2/questionario-in-sol.txt b/pypers/marelli/modulo2/questionario-in-sol.txt
new file mode 100755
index 0000000..983fb8a
--- /dev/null
+++ b/pypers/marelli/modulo2/questionario-in-sol.txt
@@ -0,0 +1,139 @@
+# -*- coding: latin1 -*-
+Soluzioni al questionario
+======================================================================
+
+1. Scrivere un programma che testa se una stringa rappresenta un numero.
+
+try:
+ int(x)
+except ValueError:
+ print "This is not a number!"
+
+from tkSimpleDialog import askfloat
+askfloat("Enter a number", "Number:")
+
+2. Scrivere un programma che lista tutti i files nella directory corrente.
+
+for f in os.listdir("."):
+ print f
+
+3. Come al punto 2, ma il programma deve anche listare tutti i files nelle
+ sottodirectories ricorsivamente.
+
+for cwd, dirs, files in os.walk("."):
+ for f in files:
+ print f
+
+4. Calcolare lo spazio occupato da tutti i files di tipo .txt contenuti in
+ una directory.
+
+import os
+
+def get_text_files(d):
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ if f.lower().endswith(".txt"):
+ fullname = os.path.join(cwd, f)
+ size = os.path.getsize(fullname)
+ yield fullname, size
+
+from operator import itemgetter
+print sum(map(itemgetter(1), get_text_files(".")))
+
+5. Listare i files a seconda delle dimensioni (dal più piccolo al più grande,
+in bytes).
+
+print sorted(get_text_files("."), key=itemgetter(1))
+
+6. Scrivere un test per verificate che una directory sia vuota.
+
+def is_empty(d):
+ if os.listdir(d): return False
+ else: return True
+
+7. Aprire una finestrella contenente la scritta "hello, world!".
+
+# hellotk.pyw
+import Tkinter as t
+root = t.Tk()
+l = t.Label(text="hello")
+l.pack()
+root.mainloop()
+
+# alternativamente
+from tkMessageBox import showinfo
+showinfo(message="hello")
+
+8. Scaricare la pagina Web http://www.example.com da Internet usando Python.
+
+>>> from urllib2 import urlopen
+>>> print urlopen("http://www.example.com").read()
+
+9. Stampare a schermo una tavola delle moltiplicazioni.
+
+ #<maketable.py>
+
+ # non graphic
+ N = 10
+ for i in range(1, N+1):
+ for j in range(1, N+1):
+ print "%4d" % (i*j),
+ print
+
+ # HTML
+ def maketable(iterable, N):
+ iterable = iter(iterable)
+ print "<table border='1'>"
+ stop = False
+ while not stop:
+ print "<tr>"
+ for j in range(1, N+1):
+ try:
+ print "<td>%s</td>" % iterable.next(),
+ except StopIteration:
+ print "<td></td>"
+ stop = True
+ print "</tr>"
+ print "</table>"
+
+ import tempfile, webbrowser, os, sys
+
+ def showtable(iterable, N):
+ stdout = sys.stdout
+ fd, name = tempfile.mkstemp(suffix=".html")
+ sys.stdout = os.fdopen(fd, "w")
+ maketable(iterable, N)
+ webbrowser.open(name)
+ sys.stdout = stdout
+
+ showtable((i*j for j in range(1, N+1) for i in range(1, N+1)), N)
+
+ #</maketable.py>
+
+10. Trovare tutte le immagini .jpg nel vostro hard disk e mostrarle a schermo
+ in formato ridotto (thumbnails).
+
+ #<maketable.py>
+
+ def get_files_with_ext(ext_set, d):
+ if not isinstance(ext_set, set):
+ ext_set = set([ext_set])
+ for cwd, dirs, files in os.walk(d):
+ for f in files:
+ name, ext = os.path.splitext(f)
+ if ext.lower() in ext_set:
+ yield os.path.join(cwd, f)
+
+ class Picture(object):
+ def __init__(self, pathname):
+ self.pathname = pathname
+ self.name = os.path.basename(pathname)
+ def __str__(self):
+ return "<img src=%r width=100>" % self.pathname
+
+ if sys.platform == 'win32': drive = "C:\\"
+ else: drive = "/"
+ showtable(map(Picture, get_files_with_ext(".jpg", drive)), N)
+
+ #</maketable.py>
+
diff --git a/pypers/marelli/modulo2/questionario-iniziale.txt b/pypers/marelli/modulo2/questionario-iniziale.txt
new file mode 100755
index 0000000..2e545ba
--- /dev/null
+++ b/pypers/marelli/modulo2/questionario-iniziale.txt
@@ -0,0 +1,23 @@
+Domande di conoscenza generale di Python, giusto per avere un'idea della vostra preparazione di base.
+========================================================================================================
+
+1. Scrivere un programma che testa se una stringa rappresenta un numero.
+
+2. Scrivere un programma che lista tutti i files nella directory corrente.
+
+3. Come al punto 2, ma il programma deve anche listare tutti i files nelle sottodirectories ricorsivamente.
+
+4. Calcolare lo spazio occupato da tutti i files di tipo .txt contenuti in una directory.
+
+5. Listare i files a seconda delle dimensioni (dal più piccolo al più grande, in bytes).
+
+6. Scrivere un test per verificate che una directory sia vuota.
+
+7. Aprire una finestrella contenente la scritta "hello, world!".
+
+8. Scaricare la pagina Web http://www.example.com da Internet usando Python.
+
+9. Stampare a schermo una tavola delle moltiplicazioni.
+
+10. Trovare tutte le immagini .jpg nel vostro hard disk e mostrarle a schermo in formato ridotto (thumbnails).
+
diff --git a/pypers/marelli/modulo2/sort_ci.py b/pypers/marelli/modulo2/sort_ci.py
new file mode 100755
index 0000000..8751ea5
--- /dev/null
+++ b/pypers/marelli/modulo2/sort_ci.py
@@ -0,0 +1,25 @@
+
+from operator import attrgetter
+
+class CI_name(object):
+ def __init__(self, name):
+ self.name = name
+ self.ci_name = name.lower()
+
+def sorted_ci(iterable):
+ ls = map(CI_name, iterable)
+ ls.sort(key=attrgetter("ci_name"))
+ return [el.name for el in ls]
+
+## second implementation:
+
+def sorted_ci(iterable):
+ ls = [(name.lower(), name) for name in iterable]
+ ls.sort()
+ return [el[1] for el in ls]
+
+if __name__ == "__main__": # test
+ ls = "ciao Nina come Va?".split()
+ print sorted(ls)
+ print sorted_ci(ls)
+
diff --git a/pypers/marelli/modulo3/config.py b/pypers/marelli/modulo3/config.py
new file mode 100755
index 0000000..d62928c
--- /dev/null
+++ b/pypers/marelli/modulo3/config.py
@@ -0,0 +1,6 @@
+import sys
+if sys.platform == "win32":
+ root = "C:/"
+else:
+ root = "/mnt/hda2/"
+MUSICDIR = root + "Documents and Settings/micheles/Desktop/Music"
diff --git a/pypers/marelli/modulo3/disaccoppiamento.txt b/pypers/marelli/modulo3/disaccoppiamento.txt
new file mode 100755
index 0000000..d1899d3
--- /dev/null
+++ b/pypers/marelli/modulo3/disaccoppiamento.txt
@@ -0,0 +1 @@
+- vantaggi delle interfaccie di tipo testo
diff --git a/pypers/marelli/modulo3/launcher_with_exec.py b/pypers/marelli/modulo3/launcher_with_exec.py
new file mode 100755
index 0000000..58c383c
--- /dev/null
+++ b/pypers/marelli/modulo3/launcher_with_exec.py
@@ -0,0 +1,5 @@
+script = "script_with_error.py"
+
+#exec file(script).read()
+
+__import__(script[:-3])
diff --git a/pypers/marelli/modulo3/lineinterpreter.py b/pypers/marelli/modulo3/lineinterpreter.py
new file mode 100755
index 0000000..8bc192d
--- /dev/null
+++ b/pypers/marelli/modulo3/lineinterpreter.py
@@ -0,0 +1,55 @@
+## NOTE: THE UNBUFFERED BIT IS ESSENTIAL!
+
+import sys, time
+from twisted.internet import reactor, protocol
+from twisted.protocols import basic
+from ms.concurrency import Popen, PIPE
+
+PORT = 8000
+
+class LineInterpreter(basic.LineReceiver):
+ #from os import sep as delimiter
+
+ def connectionMade(self):
+ self.interpreter = Popen(self.factory.cmd, stdin=PIPE, stdout=PIPE)
+ self.inp = self.interpreter.stdin
+ self.out = self.interpreter.stdout
+ self.transport.write("\r\n%s\r\n" % " ".join(self.factory.cmd))
+ time.sleep(.1)
+ print "".join(self.read_output())
+
+ def connectionLost(self, reason):
+ print >> self.inp, "quit"
+
+ def lineReceived(self, line):
+ print line
+ if line == "quit":
+ self.transport.loseConnection()
+ else:
+ print >> self.inp, line
+ self.transport.write("\r\n%s" % "\r".join(self.read_output()))
+
+ def read_output(self):
+ while True:
+ outline = self.out.readline()
+ yield outline
+ if outline.startswith("(Cmd) "):
+ #yield outline[6:]
+ break
+
+
+if __name__== "__main__":
+ # cmd = sys.argv[1:]
+ cmd = sys.executable, "-u", "tester.py"
+ if cmd:
+ factory = protocol.ServerFactory()
+ factory.protocol = LineInterpreter
+ factory.cmd = cmd
+ reactor.listenTCP(PORT, factory)
+ try:
+ reactor.run()
+ except Exception, e:
+ print e
+ reactor.stop()
+ else:
+ print "usage: %prog line-interpreter-command"
diff --git a/pypers/marelli/modulo3/runsongs.py b/pypers/marelli/modulo3/runsongs.py
new file mode 100755
index 0000000..743bd33
--- /dev/null
+++ b/pypers/marelli/modulo3/runsongs.py
@@ -0,0 +1,31 @@
+import os, random, threading
+from ms.file_utils import ifiles
+from ms.concurrency import Popen, locked
+
+PLAYER = "mplay32 /play /close".split()
+MUSICDIR = os.environ.get("HOMEPATH", os.environ["HOME"]) + "/Desktop/Music"
+
+songs = list(ifiles(MUSICDIR, lambda f : f.endswith(".mp3")))
+
+def run(func, *args, **kw):
+ threading.Thread(None, func, args=args, kwargs=kw).start()
+
+def gen_songs():
+ for i in range(2):
+ yield random.choice(songs)
+
+def play(song):
+ return Popen(PLAYER + [song])
+
+@locked
+def play_many(user):
+ for song in gen_songs():
+ print user, song
+ player = play(song)
+ player.wait()
+
+if __name__ == "__main__":
+ run(play_many, "user1")
+ run(play_many, "user2")
+ run(play_many, "user3")
+
diff --git a/pypers/marelli/modulo3/script_with_error.py b/pypers/marelli/modulo3/script_with_error.py
new file mode 100755
index 0000000..6e2e746
--- /dev/null
+++ b/pypers/marelli/modulo3/script_with_error.py
@@ -0,0 +1 @@
+print 1/0
diff --git a/pypers/marelli/modulo3/tester.py b/pypers/marelli/modulo3/tester.py
new file mode 100755
index 0000000..f99b477
--- /dev/null
+++ b/pypers/marelli/modulo3/tester.py
@@ -0,0 +1,119 @@
+import os, cmd, config
+from ms.file_utils import ifiles
+from ms.concurrency import Popen
+from operator import attrgetter
+import sys, re
+
+def strip_number(song, rx=re.compile(r"\s*\d\d?\. ")):
+ return rx.sub("", os.path.basename(song))
+
+class TestProcess(object):
+ def __init__(self, number, name, popencmd):
+ self.name = name
+ self.number = number
+ self.popencmd = popencmd
+ def start(self):
+ self.proc = Popen(self.popencmd)
+ def stop(self):
+ if self.is_running():
+ self.proc.kill()
+ def is_running(self):
+ return hasattr(self, "proc") and self.proc.is_running()
+
+def popencmd(song):
+ if sys.platform == "win32":
+ return "mplay32", "/play", "/close", song
+ else:
+ return "xterm", "-geometry", "70x14", "-e", "mpg123", song
+
+def str2int(args):
+ for arg in args.split():
+ try:
+ i = int(arg)
+ except ValueError:
+ print "Warning: argument %s is not an integer, ignored" % arg
+ else:
+ yield i
+
+class Tester(cmd.Cmd):
+ use_rawinput = False
+ prompt = ">>" + chr(0)
+ def preloop(self):
+ self.songs = list(ifiles(config.MUSICDIR,
+ lambda f: f.endswith(".mp3")))
+ self.tests = dict(
+ [i, TestProcess(i, strip_number(song), popencmd(song))]
+ for i, song in enumerate(self.songs))
+ self.started_tests = set()
+ self.do_show()
+
+ def running_tests(self):
+ for test in self.started_tests:
+ if test.is_running():
+ yield test
+
+ def run_test(self, testnumber):
+ if testnumber in self.tests:
+ test = self.tests[testnumber]
+ if test.is_running():
+ print "Test #%s is already running!" % test.number
+ else:
+ test.start()
+ self.started_tests.add(test)
+ print "test #%s started" % test.number
+ else:
+ print "There is no test #%s" % testnumber
+
+ def stop_test(self, testnumber):
+ if testnumber in (test.number for test in self.running_tests()):
+ self.tests[testnumber].stop()
+ print "Test #%s stopped." % testnumber
+ else:
+ print "There is no process #%s running" % testnumber
+
+ def do_show(self, arg=""):
+ if arg == "runnable":
+ self.show_runnable()
+ elif arg == "already_run":
+ self.show_already_run()
+ elif arg is "":
+ self.show_already_run()
+ self.show_runnable()
+ else:
+ print "Unknown argument %s" % arg
+
+ def show_runnable(self):
+ print "Runnable tests:"
+ if set(self.tests.itervalues()) != self.started_tests:
+ for test in self.tests.itervalues():
+ if not test in self.started_tests:
+ print test.number, test.name
+ else: # all tests have been started
+ print "None"
+
+ def show_already_run(self):
+ print "Already run tests:"
+ if not self.started_tests:
+ print "None"
+ else:
+ for test in sorted(self.started_tests, key=attrgetter("number")):
+ print test.number, test.name
+
+ def do_run(self, args):
+ run = map(self.run_test, str2int(args))
+ if not run: map(self.run_test, range(len(self.tests))) # run all
+
+ def do_stop(self, args):
+ stop = map(self.stop_test, str2int(args))
+ if not stop: self.postloop() # stop all
+
+ def do_quit(self, arg):
+ print "exiting ..."
+ return True
+
+ def postloop(self):
+ for test in self.running_tests():
+ self.stop_test(test.number)
+
+if __name__ == "__main__":
+ Tester().cmdloop()
diff --git a/pypers/marelli/modulo3/tester_server.py b/pypers/marelli/modulo3/tester_server.py
new file mode 100755
index 0000000..245089f
--- /dev/null
+++ b/pypers/marelli/modulo3/tester_server.py
@@ -0,0 +1,6 @@
+import sys
+from ms.twisted_utils import run
+
+if __name__ == "__main__":
+ print "Listening on localhost 1025 ..."
+ run([sys.executable, "tester.py"], 1025)
diff --git a/pypers/marelli/modulo3/tester_server0.py b/pypers/marelli/modulo3/tester_server0.py
new file mode 100755
index 0000000..ec79542
--- /dev/null
+++ b/pypers/marelli/modulo3/tester_server0.py
@@ -0,0 +1,60 @@
+"""
+Portable twisted server for pythonic command interpreters. Multiple clients
+can connect to it with
+
+$ telnet localhost 1025
+
+The interpreter prompt is expected to end with chr(0).
+"""
+
+import sys
+from twisted.protocols import basic
+from twisted.internet import protocol, reactor
+from subprocess import Popen, PIPE
+
+def read(inp, sep=chr(0), fix_nl=True):
+ """Read data from ``inp`` until a separator ``sep`` is found. If
+ ``fix_nl`` is True, it converts newlines in \r\n, the standard for
+ Internet line protocols."""
+ out = []
+ while True:
+ char = inp.read(1)
+ if char == sep:
+ break
+ elif char == "\n" and fix_nl:
+ out.append("\r\n")
+ else:
+ out.append(char)
+ return "".join(out) + " "
+
+# Poor man using Popen, not ProcessProtocol as in ptyserv
+class InterpreterProtocol(basic.LineReceiver):
+ def connectionMade(self):
+ print "Got new client!"
+ self.cli = Popen([sys.executable, "-u", self.factory.cmd_interpreter],
+ stdin=PIPE, stdout=PIPE)
+ self.inp = self.cli.stdin
+ self.out = self.cli.stdout
+ self.transport.write(read(self.out))
+
+ def connectionLost(self, reason):
+ print "Lost a client!"
+ print >> self.inp, "quit"
+
+ def lineReceived(self, line):
+ print "received", repr(line)
+ if line == "quit":
+ self.transport.loseConnection()
+ else:
+ print >> self.inp, line
+ self.transport.write(read(self.out))
+
+def run(py_cmd_interpr, port=1025):
+ factory = protocol.ServerFactory()
+ factory.protocol = InterpreterProtocol
+ factory.cmd_interpreter = py_cmd_interpr
+ reactor.listenTCP(port, factory)
+ reactor.run()
+
+if __name__ == "__main__":
+ run("tester.py", 1025)
diff --git a/pypers/marelli/modulo4/_main.py b/pypers/marelli/modulo4/_main.py
new file mode 100755
index 0000000..7d252b1
--- /dev/null
+++ b/pypers/marelli/modulo4/_main.py
@@ -0,0 +1,9 @@
+# _main.py
+
+class C(object):
+ pass
+
+def f(x):
+ return x
+
+
diff --git a/pypers/marelli/modulo4/code2utest.py b/pypers/marelli/modulo4/code2utest.py
new file mode 100755
index 0000000..32e7335
--- /dev/null
+++ b/pypers/marelli/modulo4/code2utest.py
@@ -0,0 +1,32 @@
+"""
+Convert tests from modules into test cases.
+"""
+
+import sys, unittest, time
+from ms.misc_utils import import_
+
+def makeSuite(name, code):
+ dic = {}
+ exec compile(code, name, 'exec') in dic
+ tests = []
+ for name, test in dic.iteritems():
+ if name.startswith("test"):
+ tests.append([name, test])
+ TC = type(name, (unittest.TestCase,), dict(tests))
+ return unittest.makeSuite(TC)
+
+class Printer(object):
+ def write(self, text):
+ sys.stdout.write(text)
+
+def run(modulenames, stream=Printer(), descriptions=1, verbosity=1):
+ runner = unittest.TextTestRunner(stream, descriptions, verbosity)
+ suites = [makeSuite(name, code) for name, code in modulenames]
+ return runner.run(unittest.TestSuite(suites))
+
+def fnames2list(fnames):
+ return [(fname[:-3], file(fname).read()) for fname in fnames]
+
+if __name__ == "__main__": # example
+ print run(fnames2list('utest_1.py utest_2.py'.split()))
+
diff --git a/pypers/marelli/modulo4/ex1.txt b/pypers/marelli/modulo4/ex1.txt
new file mode 100755
index 0000000..dec7913
--- /dev/null
+++ b/pypers/marelli/modulo4/ex1.txt
@@ -0,0 +1,15 @@
+ #<_main.py>
+
+ class C(object):
+ pass
+
+ def f(x):
+ return x
+
+ #</_main.py>
+
+>>> f(1) == 1
+True
+
+>>> C
+<class '_main.C'>
diff --git a/pypers/marelli/modulo4/ex2.txt b/pypers/marelli/modulo4/ex2.txt
new file mode 100755
index 0000000..9e003a9
--- /dev/null
+++ b/pypers/marelli/modulo4/ex2.txt
@@ -0,0 +1,5 @@
+>>> class C(object): pass
+...
+
+>>> C
+<class '__main__.C'>
diff --git a/pypers/marelli/modulo4/iter2thread.py b/pypers/marelli/modulo4/iter2thread.py
new file mode 100755
index 0000000..0a7c1ed
--- /dev/null
+++ b/pypers/marelli/modulo4/iter2thread.py
@@ -0,0 +1,15 @@
+import time
+from ms.concurrency import gen2thread
+
+@gen2thread
+def genNumbers(self, N):
+ for i in range(N):
+ time.sleep(.2)
+ print i
+ yield None
+
+
+t = genNumbers(10)
+t.start()
+time.sleep(1)
+t.stop()
diff --git a/pypers/marelli/modulo4/multi_iter.py b/pypers/marelli/modulo4/multi_iter.py
new file mode 100755
index 0000000..d3a5ac2
--- /dev/null
+++ b/pypers/marelli/modulo4/multi_iter.py
@@ -0,0 +1,22 @@
+from ms.file_utils import ifiles
+import os
+
+def gen(fname):
+ for line in file(fname):
+ yield line
+
+def multi_iter(iters):
+ iters = list(iters) # to avoid side effects
+ while iters:
+ for it in iters:
+ try:
+ yield it.next()
+ except StopIteration:
+ iters.remove(it)
+
+ci =multi_iter(gen(f) for f in
+ ifiles("/home/micheles/md/python/Timing",
+ lambda f: f.endswith(".txt")))
+
+for line in ci:
+ print line,
diff --git a/pypers/marelli/modulo4/remote_tester_client.py b/pypers/marelli/modulo4/remote_tester_client.py
new file mode 100755
index 0000000..b991019
--- /dev/null
+++ b/pypers/marelli/modulo4/remote_tester_client.py
@@ -0,0 +1,46 @@
+"""Read code from a file, send it to the server and display the result.
+
+usage: %prog testfile [options]
+
+"""
+
+import os, sys
+
+from twisted.protocols.basic import LineReceiver
+from twisted.internet import reactor, protocol
+
+from remote_tester_server import PORT
+
+class ClientFactory(protocol.ClientFactory):
+ class protocol(LineReceiver):
+ def connectionMade(self):
+ print "Sending data to server ..."
+ send(self.factory.name_code, self.transport)
+ def connectionLost(self, arg):
+ print "Connection lost!", arg
+ def lineReceived(self, line):
+ print line
+ if line == "bye":
+ pass
+ #self.transport.loseConnection("regular exit")
+ #reactor.stop()
+ def __init__(self, name, lines):
+ self.name_code = name, lines
+
+def send((name, rfile), transport):
+ transport.write("BEGIN %s\r\n" % name)
+ for line in rfile:
+ transport.write(line.rstrip() + "\r\n")
+ transport.write("END\r\n")
+
+def send_and_wait(fname, lines):
+ reactor.connectTCP("localhost", PORT, ClientFactory(fname, lines))
+ reactor.run()
+
+if __name__ == "__main__":
+ try:
+ testfile = sys.argv[1]
+ except IndexError:
+ print __doc__
+ else:
+ send_and_wait(os.path.basename(testfile), file(testfile, "U"))
diff --git a/pypers/marelli/modulo4/remote_tester_server.py b/pypers/marelli/modulo4/remote_tester_server.py
new file mode 100755
index 0000000..c03edfb
--- /dev/null
+++ b/pypers/marelli/modulo4/remote_tester_server.py
@@ -0,0 +1,59 @@
+"""Get test code from the client, run it and return the result."""
+
+import sys, unittest, time, threading
+
+from twisted.protocols.basic import LineReceiver
+from twisted.internet import reactor, protocol
+from twisted.internet.threads import deferToThread
+
+from ms.misc_utils import import_
+
+PORT = 1025
+
+class Wrapper(object): # it seems buffered :-(
+ def __init__(self, obj):
+ self._obj = obj
+ def write(self, text):
+ self._obj.write(text.replace("\n", "\r\n"))
+ #sys.stdout.write(text)
+
+# NOTE: different protocols for different clients, but same factory
+# transport is an instance of twisted.internet.tcp.Server, which a
+# subclass of Connection
+class ServerFactory(protocol.ServerFactory):
+ class protocol(LineReceiver):
+ def connectionMade(self):
+ print "Test case got from client %s" % self
+ def connectionLost(self, reason):
+ print "Connection lost!"
+ def lineReceived(self, line):
+ print line # good for debugging
+ if line.startswith("BEGIN"): # open test file
+ fname = "server_" + line.split()[1]
+ self.name = fname[:-3]
+ self.f = file(fname, "w")
+ elif line == "END": # close test file, run tests
+ self.f.close()
+ de = run([self.name], Wrapper(self.transport))
+ de.addErrback(sys.stdout.write)
+ de.addCallback(lambda _: self.transport.write("bye\r\n"))
+ else: # build test file
+ print >> self.f, line # possibile race or not?
+
+def makeSuite(module):
+ tests = []
+ for name, test in module.__dict__.iteritems():
+ if name.startswith("test"):
+ tests.append([name, test])
+ TC = type(module.__name__, (unittest.TestCase,), dict(tests))
+ return unittest.makeSuite(TC)
+
+@deferToThread.__get__ # make asynchronous
+def run(modulenames, stream=sys.stdout, descriptions=1, verbosity=1):
+ runner = unittest.TextTestRunner(stream, descriptions, verbosity)
+ suites = [makeSuite(import_(module)) for module in modulenames]
+ return runner.run(unittest.TestSuite(suites))
+
+if __name__ == "__main__":
+ reactor.listenTCP(PORT, ServerFactory())
+ reactor.run()
diff --git a/pypers/marelli/modulo4/server_utest_1.py b/pypers/marelli/modulo4/server_utest_1.py
new file mode 100755
index 0000000..5c354b8
--- /dev/null
+++ b/pypers/marelli/modulo4/server_utest_1.py
@@ -0,0 +1,6 @@
+
+def test_1(self):
+ self.assertEqual(1, 1)
+
+def test_2(self):
+ self.assertEqual(1, 2)
diff --git a/pypers/marelli/modulo4/server_utest_2.py b/pypers/marelli/modulo4/server_utest_2.py
new file mode 100755
index 0000000..e25fc94
--- /dev/null
+++ b/pypers/marelli/modulo4/server_utest_2.py
@@ -0,0 +1,8 @@
+import time
+
+def test_1(self):
+ self.assertEqual(1, 1)
+
+def test_2(self):
+ time.sleep(1)
+ self.assertEqual(1, 2)
diff --git a/pypers/marelli/modulo4/test2utest.py b/pypers/marelli/modulo4/test2utest.py
new file mode 100755
index 0000000..458bf32
--- /dev/null
+++ b/pypers/marelli/modulo4/test2utest.py
@@ -0,0 +1,27 @@
+"""
+Convert tests from modules into test cases.
+"""
+
+import sys, unittest, time
+from ms.misc_utils import import_
+
+def makeSuite(module):
+ tests = []
+ for name, test in module.__dict__.iteritems():
+ if name.startswith("test"):
+ tests.append([name, test])
+ TC = type(module.__name__, (unittest.TestCase,), dict(tests))
+ return unittest.makeSuite(TC)
+
+class Printer(object):
+ def write(self, text):
+ sys.stdout.write(text)
+
+def run(modulenames, stream=Printer(), descriptions=1, verbosity=1):
+ runner = unittest.TextTestRunner(stream, descriptions, verbosity)
+ suites = [makeSuite(import_(module)) for module in modulenames]
+ return runner.run(unittest.TestSuite(suites))
+
+if __name__ == "__main__": # example
+ print run(['utest_1', 'utest_2'])
+
diff --git a/pypers/marelli/modulo4/test_1.py b/pypers/marelli/modulo4/test_1.py
new file mode 100755
index 0000000..3a0b1c8
--- /dev/null
+++ b/pypers/marelli/modulo4/test_1.py
@@ -0,0 +1,5 @@
+def test1(a=42, b=43):
+ assert a==b
+
+def test2(a=42, b=42):
+ assert a==b
diff --git a/pypers/marelli/modulo4/test_2.py b/pypers/marelli/modulo4/test_2.py
new file mode 100755
index 0000000..52bf590
--- /dev/null
+++ b/pypers/marelli/modulo4/test_2.py
@@ -0,0 +1,10 @@
+"""
+Generative tests: generators returning check functions and their parameters
+"""
+def isequal(x, y):
+ assert x == y
+
+def test_gen():
+ for i, j in (1, 1), (2, 3), (4, 5):
+ yield isequal, i, j
+
diff --git a/pypers/marelli/modulo4/test_3.py b/pypers/marelli/modulo4/test_3.py
new file mode 100755
index 0000000..c376083
--- /dev/null
+++ b/pypers/marelli/modulo4/test_3.py
@@ -0,0 +1,12 @@
+from tkMessageBox import showinfo
+
+class Test1(object):
+ def setup_class(cls):
+ pass
+ #showinfo("setup", "setup")
+ def teardown_class(cls):
+ print "teardown"
+ def test_m1(self):
+ assert 1==0
+ def test_m2(self):
+ assert 1==0
diff --git a/pypers/marelli/modulo4/test_parent_child/child.py b/pypers/marelli/modulo4/test_parent_child/child.py
new file mode 100755
index 0000000..098ed4b
--- /dev/null
+++ b/pypers/marelli/modulo4/test_parent_child/child.py
@@ -0,0 +1,4 @@
+import time
+for i in range(10):
+ print "%s I am the child!" % i
+ time.sleep(1)
diff --git a/pypers/marelli/modulo4/test_parent_child/parent.py b/pypers/marelli/modulo4/test_parent_child/parent.py
new file mode 100755
index 0000000..0dcc172
--- /dev/null
+++ b/pypers/marelli/modulo4/test_parent_child/parent.py
@@ -0,0 +1,9 @@
+from subprocess import Popen
+from time import sleep
+from os import getpid
+
+print >> file("parent.pid", "w"), getpid()
+child = Popen(["python", "child.py"])
+print "Parent id: %s" % getpid()
+print "Child id: %s" % child.pid
+sleep(60)
diff --git a/pypers/marelli/modulo4/test_parent_child/test_kill_parent.sh b/pypers/marelli/modulo4/test_parent_child/test_kill_parent.sh
new file mode 100755
index 0000000..4d026a4
--- /dev/null
+++ b/pypers/marelli/modulo4/test_parent_child/test_kill_parent.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# test that killing the parent does NOT kill the child
+python parent.py&
+sleep 3
+kill `cat parent.pid`
+sleep 1
+ps aux | grep python
diff --git a/pypers/marelli/modulo4/threads.txt b/pypers/marelli/modulo4/threads.txt
new file mode 100755
index 0000000..a70350b
--- /dev/null
+++ b/pypers/marelli/modulo4/threads.txt
@@ -0,0 +1,22 @@
+Programming with threads
+=====================================
+
+Issues with threads
+---------------------------------
+
+1. You cannot kill a thread.
+2. Exceptions are harder.
+3. There is always the risk of race conditions and deadlocks.
+4. Threads are not scalable.
+
+Partial solution:
+
+- use Twisted threads.
+
+Use case for threads
+--------------------------------------
+
+1. Exchanging info is easier.
+2. Applications with a mainloop (GUI, WEB)
+3. Threads as observers.
+4. Simulations (ex. simulating many users) \ No newline at end of file
diff --git a/pypers/marelli/modulo4/threads_ex.py b/pypers/marelli/modulo4/threads_ex.py
new file mode 100755
index 0000000..eb2f3dd
--- /dev/null
+++ b/pypers/marelli/modulo4/threads_ex.py
@@ -0,0 +1,26 @@
+from ms.concurrency import ThreadFactory
+import time
+
+@ThreadFactory
+def do_nothing(thread, err=False):
+ if err: raise RuntimeError()
+ for i in range(10):
+ if not thread.running: break
+ time.sleep(.5)
+ print thread.getName()
+ return i
+
+d1 = do_nothing(err=True)
+print do_nothing
+d2 = do_nothing()
+
+d1.start()
+d2.start()
+print d1.getResult()
+d1.finish()
+time.sleep(1)
+d2.finish()
+print d1.isAlive()
+print d2.isAlive()
+print d1.getResult()
+print d2.getResult()
diff --git a/pypers/marelli/modulo4/threads_twisted.py b/pypers/marelli/modulo4/threads_twisted.py
new file mode 100755
index 0000000..8bdefb3
--- /dev/null
+++ b/pypers/marelli/modulo4/threads_twisted.py
@@ -0,0 +1,36 @@
+from twisted.internet.threads import deferToThread
+from twisted.internet import reactor
+from twisted.python import threadable; threadable.init(True)
+import time
+
+def print_(x):
+ print x
+
+@deferToThread.__get__
+def do_nothing(err=False):
+ if err: raise RuntimeError()
+ for i in range(10):
+ #if not thread.running: break
+ time.sleep(.5)
+ return i
+
+d1 = do_nothing()
+d1.addBoth(print_)
+d2 = do_nothing(err=False)
+d2.addBoth(print_)
+
+## print do_nothing
+## d2 = do_nothing()
+
+## d1.start()
+## d2.start()
+## print d1.getResult()
+## d1.finish()
+## time.sleep(1)
+## d2.finish()
+## print d1.isAlive()
+## print d2.isAlive()
+## print d1.getResult()
+## print d2.getResult()
+
+reactor.run()
diff --git a/pypers/marelli/modulo4/utest_1.py b/pypers/marelli/modulo4/utest_1.py
new file mode 100755
index 0000000..5c354b8
--- /dev/null
+++ b/pypers/marelli/modulo4/utest_1.py
@@ -0,0 +1,6 @@
+
+def test_1(self):
+ self.assertEqual(1, 1)
+
+def test_2(self):
+ self.assertEqual(1, 2)
diff --git a/pypers/marelli/modulo4/utest_2.py b/pypers/marelli/modulo4/utest_2.py
new file mode 100755
index 0000000..e25fc94
--- /dev/null
+++ b/pypers/marelli/modulo4/utest_2.py
@@ -0,0 +1,8 @@
+import time
+
+def test_1(self):
+ self.assertEqual(1, 1)
+
+def test_2(self):
+ time.sleep(1)
+ self.assertEqual(1, 2)
diff --git a/pypers/marelli/modulo4/x.py b/pypers/marelli/modulo4/x.py
new file mode 100755
index 0000000..973fab9
--- /dev/null
+++ b/pypers/marelli/modulo4/x.py
@@ -0,0 +1,3 @@
+print __file__
+while 1:
+ pass
diff --git a/pypers/marelli/modulo5/fix-server.py b/pypers/marelli/modulo5/fix-server.py
new file mode 100755
index 0000000..6749058
--- /dev/null
+++ b/pypers/marelli/modulo5/fix-server.py
@@ -0,0 +1,48 @@
+
+############ FIX A MISSING FEATURE IN HTTPServer ################
+
+from BaseHTTPServer import HTTPServer
+
+# The only exception that can propagate here is SystemExit
+def handle_exit(self, request, client_address):
+ raise SystemExit("Server is shutting down")
+
+HTTPServer.handle_error = handle_exit
+
+############ FIX A MISSING FEATURE IN Publisher ################
+
+import time
+from quixote.publish import PublishError
+
+def process_request(self, request):
+ """(request : HTTPRequest) -> HTTPResponse
+
+ Process a single request, given an HTTPRequest object. The
+ try_publish() method will be called to do the work and
+ exceptions will be handled here.
+ """
+ self._set_request(request)
+ start_time = time.time()
+ try:
+ self.parse_request(request)
+ output = self.try_publish(request)
+ except PublishError, exc:
+ # Exit the publishing loop and return a result right away.
+ output = self.finish_interrupted_request(exc)
+ except SystemExit: # <==== THIS IS
+ raise # <==== THE FIX
+ except:
+ # Some other exception, generate error messages to the logs, etc.
+ output = self.finish_failed_request()
+ output = self.filter_output(request, output)
+ self.logger.log_request(request, start_time)
+ if output:
+ if self.config.compress_pages and request.get_encoding(["gzip"]):
+ compress = True
+ else:
+ compress = False
+ request.response.set_body(output, compress)
+ self._clear_request()
+ return request.response
+
+Publisher.process_request = process_request
diff --git a/pypers/marelli/modulo5/protected.py b/pypers/marelli/modulo5/protected.py
new file mode 100755
index 0000000..0398ad5
--- /dev/null
+++ b/pypers/marelli/modulo5/protected.py
@@ -0,0 +1,30 @@
+"""An example of protected methods."""
+
+class B(object):
+ def __init__(self):
+ self.hello()
+ def hello(self):
+ print "hello!"
+
+class C(B):
+ def hello(self):
+ print "cucu!"
+
+b = B()
+c = C()
+
+##
+
+class B(object):
+ def __init__(self): # guaranteed to call the 'hello' method in THIS class
+ self.__hello()
+ def __hello(self):
+ print "hello!"
+
+class C(B):
+ def __hello(self): # won't be called by B.__init__
+ print "cucu!"
+
+b = B()
+c = C()
+
diff --git a/pypers/marelli/modulo5/protected2.py b/pypers/marelli/modulo5/protected2.py
new file mode 100755
index 0000000..fbbb1f3
--- /dev/null
+++ b/pypers/marelli/modulo5/protected2.py
@@ -0,0 +1,11 @@
+class B(object):
+ def __p(self):
+ print "hello!"
+ def __init__(self):
+ self.__p()
+
+class C(B):
+ def __init__(self):
+ self.__p()
+
+c = C()
diff --git a/pypers/marelli/modulo5/threads_vs_gen.py b/pypers/marelli/modulo5/threads_vs_gen.py
new file mode 100755
index 0000000..f1a0a3d
--- /dev/null
+++ b/pypers/marelli/modulo5/threads_vs_gen.py
@@ -0,0 +1,37 @@
+import threading
+from ms.file_utils import ifiles
+
+def count(it):
+ n = 0
+ for line in it:
+ n += len(line)
+ return n
+
+#print count(ifiles("/home/micheles", lambda f: f.endswith(".txt"))) # 4610
+
+def synchronous():
+ for f in ifiles("/home/micheles", lambda f: f.endswith(".txt")):
+ #print f, count(file(f))
+ count(file(f))
+
+# python -mtimeit -n 1 -s "from threads_vs_gen import synchronous" "synchronous()"
+def threaded():
+ for f in ifiles("/home/micheles", lambda f: f.endswith(".txt")):
+ threading.Thread(None, count, args=(file(f),)).start()
+
+
+
+# python -mtimeit -n 1 -s "from threads_vs_gen import threaded" "threaded()"
+
+def count_gen(f):
+ n = 0
+ for _ in file(f):
+ n += 1
+ yield n
+
+def asynchronous():
+ iters = map(count_gen, ifiles("/home/micheles",
+ lambda f: f.endswith(".txt")))
+ for it in iters: # do not iterate on exhausted iterators
+ it.next()
+
diff --git a/pypers/marelli/programma-svolto.html b/pypers/marelli/programma-svolto.html
new file mode 100755
index 0000000..104798c
--- /dev/null
+++ b/pypers/marelli/programma-svolto.html
@@ -0,0 +1,409 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.3.10: http://docutils.sourceforge.net/" />
+<title>Corso Python Magneti Marelli</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date: 2005-06-06 15:09:07 +0200 (Mon, 06 Jun 2005) $
+:Version: $Revision: 3442 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+ ``margin-bottom`` styles that are later in the stylesheet or
+ more specific. See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left {
+ clear: left }
+
+img.align-right {
+ clear: right }
+
+img.borderless {
+ border: 0 }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.line-block {
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid thin gray }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+tt.docutils {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="corso-python-magneti-marelli">
+<h1 class="title">Corso Python Magneti Marelli</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr class="field"><th class="docinfo-name">Data:</th><td class="field-body">19-23 Settembre</td>
+</tr>
+<tr class="field"><th class="docinfo-name">Docente:</th><td class="field-body">Michele Simionato</td>
+</tr>
+</tbody>
+</table>
+<div class="section" id="programma">
+<h1><a name="programma">Programma</a></h1>
+<p>Si tratta di un corso di 20 ore suddiviso in 5 moduli di 4 ore ciascuno.</p>
+<div class="section" id="modulo-1-programmazione-di-base-in-python">
+<h2><a name="modulo-1-programmazione-di-base-in-python">Modulo 1: Programmazione di base in Python.</a></h2>
+<p><em>In questo modulo si ripasseranno molto brevemente le basi di Python e
+si discuteranno le soluzioni al questionario di ammissione. Lo scopo
+piu' che altro e' quello di conoscersi e di chiarire il livello medio
+dei partecipanti e coprire eventuali buchi nella preparazione di base.</em></p>
+<ul class="simple">
+<li>correzione esercizi ... OK</li>
+<li>gestione processi ... OK</li>
+<li>iteratori e generatori ... *</li>
+<li>differenza mutabili/immutabili ... *</li>
+<li>python -m &lt;nome module&gt; ... OK</li>
+<li>set ... OK</li>
+</ul>
+</div>
+<div class="section" id="modulo-2-strumenti-di-sviluppo-debugging-e-introspezione">
+<h2><a name="modulo-2-strumenti-di-sviluppo-debugging-e-introspezione">Modulo 2: Strumenti di sviluppo, debugging e introspezione.</a></h2>
+<p><a href="#id1" name="id2"><span class="problematic" id="id2">*</span></a>In questo modulo discutero' gli strumenti da me utilizzati per sviluppare
+in Python sotto Windows. Parlero' di Cygwin come ambiente di lavoro,
+di Python e di IPython come interpreti interattivi, di Idle e di PythonWin
+come IDE, di pydoc e minidoc come tools di introspezione. Inoltre discutero'
+alcune utili librerie e frameworks per Python (Numeric, matplotlib, gnuplot,
+etc.).</p>
+<div class="system-message" id="id1">
+<p class="system-message-title">System Message: <a name="id1">WARNING/2</a> (<tt class="docutils">programma-svolto.txt</tt>, line 31); <em><a href="#id2">backlink</a></em></p>
+Inline emphasis start-string without end-string.</div>
+<ul class="simple">
+<li>cygwin ... OK</li>
+<li>Idle ... OK</li>
+<li>PythonWin ... OK</li>
+<li>WingIDE, Eric/Qt Designer, Komodo, Boa Constructor ...</li>
+<li>Emacs/Vi ... OK</li>
+<li>help in linea ... OK</li>
+<li>pydoc ... OK</li>
+<li>ActiveState help ... OK</li>
+<li>ipython ... *</li>
+<li>matplotlib ... *</li>
+<li>numarray ... *</li>
+</ul>
+</div>
+<div class="section" id="modulo-3-tipici-errori-di-programmazione-e-gestione-delle-eccezioni">
+<h2><a name="modulo-3-tipici-errori-di-programmazione-e-gestione-delle-eccezioni">Modulo 3. Tipici errori di programmazione e gestione delle eccezioni.</a></h2>
+<p><em>Si discuteranno buoni e cattivi esempi di programmazione presi da software
+reale scritto alla Magneti Marelli. Si discuteranno alcune tecniche
+per interpretare i tracebacks di Python e per identificare l'origine dei
+problemi.</em></p>
+<ul class="simple">
+<li>uso di 'assert' ... OK</li>
+<li>come scrivere le proprie classi di eccezioni ... OK</li>
+<li>evitare blocchi try grossi ... OK</li>
+<li>possibilita' di multiple except clause ... OK</li>
+<li>evitare except nudi .. OK</li>
+<li>evitare eccezioni di tipo stringa ... OK</li>
+<li>problemi delle eccezioni con i threads ... OK</li>
+<li>segreti del try/finally ... OK</li>
+<li>problemi con exec ... OK</li>
+<li>__import__ e execfile ... OK</li>
+<li>analisi del Launcher ... OK</li>
+</ul>
+</div>
+<div class="section" id="modulo-4-sviluppo-orientato-ai-test">
+<h2><a name="modulo-4-sviluppo-orientato-ai-test">Modulo 4. Sviluppo orientato ai test</a></h2>
+<p><em>Come scrivere software con tecnologie agili, con lo scopo di ridurre e
+tenere sotto controllo i bugs. Discussione di doctest, py.test e unittest.
+Esempi di programmazione test driven.</em></p>
+<ul class="simple">
+<li>doctest ... OK</li>
+<li>unittest ... *</li>
+</ul>
+</div>
+<div class="section" id="modulo-5-design-documentazione-e-manutenzione-di-librarie">
+<h2><a name="modulo-5-design-documentazione-e-manutenzione-di-librarie">Modulo 5: Design, documentazione e manutenzione di librarie</a></h2>
+<p><em>Pratiche di programmazione &quot;in the large&quot;. Moduli, packages, strumenti di
+documentazione e di installazione. Applicazioni pratiche di principi generali
+quali disaccoppiamento, modularità, non duplicazione del codice.</em></p>
+<ul class="simple">
+<li>README.txt, HISTORY.txt, ... OK</li>
+<li>zipimport ... OK</li>
+<li>moduli, paths ...</li>
+<li>packages, .pth ...</li>
+<li>docutils ... OK</li>
+<li>distutils ...</li>
+<li>come fissare moduli di terze parti ... *</li>
+<li>evitare l'ereditarieta' multipla ... *</li>
+<li>interfacce grafiche/testuali ... *</li>
+<li>variabili dummies &quot;_&quot; ... OK</li>
+<li>a volte la docstring puo' rimpiazzare il commento ... OK</li>
+</ul>
+</div>
+<div class="section" id="modulo-6-domande-estemporanee">
+<h2><a name="modulo-6-domande-estemporanee">Modulo 6: Domande estemporanee</a></h2>
+<p><em>Rispondero' alle domande dell'audience, anche al di fuori dal programma,
+se di interesse generale</em>.</p>
+<ul class="simple">
+<li>come faccio a trovare le informazioni ... OK
++ newsgroups!
++ Python Cookbook
++ Libri</li>
+<li>dove posso trovare esempi di buon codice Python ... OK</li>
+<li>come funziona 'del' ... OK</li>
+<li>come funziona 'import', 'reload' ... OK</li>
+<li>comunicazione tra processi ... *</li>
+</ul>
+</div>
+</div>
+</div>
+</body>
+</html>
diff --git a/pypers/marelli/programma-svolto.txt b/pypers/marelli/programma-svolto.txt
new file mode 100755
index 0000000..f00bd87
--- /dev/null
+++ b/pypers/marelli/programma-svolto.txt
@@ -0,0 +1,141 @@
+Corso Python Magneti Marelli
+======================================================
+
+:Data: 19-23 Settembre
+:Docente: Michele Simionato
+
+
+Programma
+---------------------------------------
+
+Si tratta di un corso di 20 ore suddiviso in 5 moduli di 4 ore ciascuno.
+
+Modulo 1: Programmazione di base in Python.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*In questo modulo si ripasseranno molto brevemente le basi di Python e
+si discuteranno le soluzioni al questionario di ammissione. Lo scopo
+piu' che altro e' quello di conoscersi e di chiarire il livello medio
+dei partecipanti e coprire eventuali buchi nella preparazione di base.*
+
+- correzione esercizi ... OK
+- gestione processi ... OK
+- iteratori e generatori ... OK
+- differenza mutabili/immutabili ... OK
+- python -m <nome module> ... OK
+- set ... OK
+
+Modulo 2: Strumenti di sviluppo, debugging e introspezione.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*In questo modulo discutero' gli strumenti da me utilizzati per sviluppare
+in Python sotto Windows. Parlero' di Cygwin come ambiente di lavoro,
+di Python e di IPython come interpreti interattivi, di Idle e di PythonWin
+come IDE, di pydoc e minidoc come tools di introspezione. Inoltre discutero'
+alcune utili librerie e frameworks per Python (Numeric, matplotlib, gnuplot,
+etc.).*
+
+- cygwin ... OK
+- Idle ... OK
+- PythonWin ... OK
+- WingIDE, Eric/Qt Designer, Komodo, Boa Constructor ... OK
+- Emacs/Vi ... OK
+- help in linea ... OK
+- pydoc ... OK
+- ActiveState help ... OK
+- ipython ... OK
+- matplotlib ... OK
+
+Modulo 3. Tipici errori di programmazione e gestione delle eccezioni.
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Si discuteranno buoni e cattivi esempi di programmazione presi da software
+reale scritto alla Magneti Marelli. Si discuteranno alcune tecniche
+per interpretare i tracebacks di Python e per identificare l'origine dei
+problemi.*
+
+- uso di 'assert' ... OK
+- come scrivere le proprie classi di eccezioni ... OK
+- evitare blocchi try grossi ... OK
+- possibilita' di multiple except clause ... OK
+- evitare except nudi .. OK
+- evitare eccezioni di tipo stringa ... OK
+- problemi delle eccezioni con i threads ... OK
+- segreti del try/finally ... OK
+- problemi con exec ... OK
+- __import__ e execfile ... OK
+- analisi del Launcher ... OK
+
+Modulo 4. Sviluppo orientato ai test
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Come scrivere software con tecnologie agili, con lo scopo di ridurre e
+tenere sotto controllo i bugs. Discussione di doctest, py.test e unittest.
+Esempi di programmazione test driven.*
+
+- unittest
+ + setUp/tearDown ... OK
+ + expected exceptions ... OK
+
+- doctest
+ + doctest in un file separato ... OK
+ + doctest convertiti in unittest ... OK
+ + expected exceptions ... OK
+
+
+Modulo 5: Design, documentazione e manutenzione di librarie
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Pratiche di programmazione "in the large". Moduli, packages, strumenti di
+documentazione e di installazione. Applicazioni pratiche di principi generali
+quali disaccoppiamento, modularità, non duplicazione del codice.*
+
+- README.txt, HISTORY.txt, ... OK
+- zipimport ... OK
+- docutils ... OK
+- distutils ...
+- variabili dummies "_" ... OK
+- a volte la docstring puo' rimpiazzare il commento ... OK
+
+- disaccoppiamento (divide et impera)
+ + problemi degli ambienti integrati ... OK
+ + rimuovere o cambiare componenti ... OK
+ + core + estensioni (interfacce grafiche/testuali) ... OK
+ + threads vs. process ... OK
+ + evitare l'ereditarieta' multipla (singola) ... OK
+
+- modularita' (divide et impera)
+ + moduli, paths ... OK
+ + packages, .pth ... OK
+ + divisione delle responsabilita' ... OK
+
+- non-duplicazione del codice
+ + come fissare moduli di terze parti ... OK
+ + scriversi funzioni di utilita' riutilizzabili ... OK
+
+- KISS (keep it simple, stupid!) ... OK
+ (non facciamoci del male)
+
+- farsi un prototipo ... OK
+ + ?? do I need it ?? (eliminare l'inessenziale)
+ + il prototipo vi puo' diventare il core
+
+- "andare avanti a lavoro finito" ... OK
+ + scrivi una riga e la testi SUBITO!
+
+Modulo 6: Domande estemporanee
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Rispondero' alle domande dell'audience, anche al di fuori dal programma,
+se di interesse generale*.
+
+- come faccio a trovare le informazioni ... OK
+ + newsgroups!
+ + Python Cookbook
+ + Libri
+
+- dove posso trovare esempi di buon codice Python ... OK
+- come funziona 'del' ... OK
+- come funziona 'import', 'reload' ... OK
+- comunicazione tra processi ... OK
+- come funzionano le variabili "__" ... OK
diff --git a/pypers/marelli/questionario-fin.txt b/pypers/marelli/questionario-fin.txt
new file mode 100755
index 0000000..ef4fbb1
--- /dev/null
+++ b/pypers/marelli/questionario-fin.txt
@@ -0,0 +1,6 @@
+Questionario finale
+------------------------------------
+
+- ordinare in maniera case-insensitive;
+- print a nested list with indentation;
+- define chop;
diff --git a/pypers/marelli/questionario-iniziale.html b/pypers/marelli/questionario-iniziale.html
new file mode 100755
index 0000000..eef63aa
--- /dev/null
+++ b/pypers/marelli/questionario-iniziale.html
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.3.10: http://docutils.sourceforge.net/" />
+<title>Domande di conoscenza generale di Python, giusto per avere un'idea della vostra preparazione di base.</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date: 2005-06-06 15:09:07 +0200 (Mon, 06 Jun 2005) $
+:Version: $Revision: 3442 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+ ``margin-bottom`` styles that are later in the stylesheet or
+ more specific. See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left {
+ clear: left }
+
+img.align-right {
+ clear: right }
+
+img.borderless {
+ border: 0 }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.line-block {
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid thin gray }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+tt.docutils {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="domande-di-conoscenza-generale-di-python-giusto-per-avere-un-idea-della-vostra-preparazione-di-base">
+<h1 class="title">Domande di conoscenza generale di Python, giusto per avere un'idea della vostra preparazione di base.</h1>
+<ol class="arabic simple">
+<li>Scrivere un programma che testa se una stringa rappresenta un numero.</li>
+<li>Scrivere un programma che lista tutti i files nella directory corrente.</li>
+<li>Come al punto 2, ma il programma deve anche listare tutti i files nelle sottodirectories ricorsivamente.</li>
+<li>Calcolare lo spazio occupato da tutti i files di tipo .txt contenuti in una directory.</li>
+<li>Listare i files a seconda delle dimensioni (dal più piccolo al più grande, in bytes).</li>
+<li>Scrivere un test per verificate che una directory sia vuota.</li>
+<li>Aprire una finestrella contenente la scritta &quot;hello, world!&quot;.</li>
+<li>Scaricare la pagina Web <a class="reference" href="http://www.example.com">http://www.example.com</a> da Internet usando Python.</li>
+<li>Stampare a schermo una tavola delle moltiplicazioni.</li>
+<li>Trovare tutte le immagini .jpg nel vostro hard disk e mostrarle a schermo in formato ridotto (thumbnails).</li>
+</ol>
+</div>
+</body>
+</html>
diff --git a/pypers/marelli/scaletta.txt b/pypers/marelli/scaletta.txt
new file mode 100755
index 0000000..dd5d5b2
--- /dev/null
+++ b/pypers/marelli/scaletta.txt
@@ -0,0 +1,55 @@
+- cygwin
+- pythonwin doc
+- pydoc
+- minidoc
+- python help
+- ipython
+- dot and dot_utils
+- matplotlib
+- gnuplot
+
+- python as glue language: subprocess and Popen
+- show tkplayer and microplayer
+
+
+- solutions to the questionary
+- sort_ci exercise
+- mutable-immutable
+
+- style guide
+- launcher with exec
+- pdb
+- exc_debugger.py
+- try .. finally
+- Graphics/stderr.py
+- logging to an HTTP server
+
+
+- mostrare doctest, le lezioni di Oxford, e il modulo dei decoratori
+. mostrare il doctester
+- mostrare py.test
+- qualche cenno su unittest
+- come scrivere un interprete di comandi per gestire i tests
+- simulatori di molti utenti di un'applicazione Web (?)
+
+USE SHORT FUNCTIONS (less comments needed, simplify a posteriori fixes)
+
+- example of OptionParser
+
+DO NOT CHANGE THE SOURCE CODE!!
+
+- how to fix bugs with dynamic overriding (example in quixote_utils)
+
+DECOUPLE LOGIC FROM USER INTERFACE
+
+- example of OptionParser
+
+COMPOSITION IS OFTEN BETTER THAN INHERITANCE
+
+- example of OptionParser
+
+###########
+
+ADVANCED OOP TIPS AND TRICKS
+
+- protected variables