diff options
Diffstat (limited to 'pypers/marelli')
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@gmail.com">michele.simionato@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 "__"</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 "hello, world!"</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 "gracefull exit" 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 "buone", 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 "How to +ask smart questions" e ricordatevi sempre che "Google is you friend".</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"> +>>> print 'documenti\nonna' # \n interpretato come newline +documenti +onna +</pre> +<p>La soluzione e' usare raw strings:</p> +<pre class="doctest-block"> +>>> print r'documenti\nonna' +documenti\nonna +</pre> +<p>Alternativamente, in versioni recenti di Windows, avreste potuto usare +anche "/" come separatore:</p> +<pre class="doctest-block"> +>>> import os +>>> os.path.exists(r'C:\Python24\python.exe') +True +>>> 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"> +>>> s = set('pippo') +>>> s +set(['i', 'p', 'o']) +>>> 'i' in s +True +>>> 'p' in s +True +>>> 'o' in s +True +>>> 'z' in s +False +</pre> +<p>E' possibile calcolare l'unione e l'intersezione di insiemi:</p> +<pre class="doctest-block"> +>>> t = set('aglio') +>>> s | t +set(['a', 'g', 'i', 'l', 'o', 'p']) +>>> s & 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"> +>>> a = 1 # i numeri sono immutabili +>>> b = a +>>> a += 1 +>>> a +2 +>>> b +1 +</pre> +<pre class="doctest-block"> +>>> a = [1] # le liste sono mutabili +>>> b = a +>>> a += [1] +>>> a +[1, 1] +>>> 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"> +#<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> +</pre> +<p><em>Non usate exec quando getattr basterebbe!</em></p> +<pre class="doctest-block"> +>>> method = 'm1' +>>> exec 'c.%s()' % method # funziona ma è brutto +chiamato m1 +>>> 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 ="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") +</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"> +#<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> +</pre> +<p>Processo 1a:</p> +<pre class="literal-block"> +#<proc1a.py> + +import time + +def main(): + for i in range(10): + print "hello" + time.sleep(1) + +if __name__ == "__main__": + main() + +#</proc1a.py> +</pre> +<p>Processo 1b:</p> +<pre class="literal-block"> +#<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> +</pre> +<p>Ho anche illustrato brevemente come si possono gestire i processi da +Twisted:</p> +<pre class="literal-block"> +#<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> +</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 "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":</p> +<pre class="doctest-block"> +>>> 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 +</pre> +<p>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:</p> +<pre class="doctest-block"> +>>> it = gen123() +>>> 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"> +>>> 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 +</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"> +>>> 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 +</pre> +<p>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.</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("myscript.py").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 "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 è:</p> +<pre class="literal-block"> +dic = {} +execfile("myscript.py", 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"> +#<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> +</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"> +#<example.py> +import exc_debug +a = 1 +b = 0 +a/b +#</example.py> +</pre> +<p>fa partire il debugger:</p> +<pre class="literal-block"> +$ 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 +</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"> +#<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> +</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 "/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 +</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 "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() +</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"> +"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() +</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"> +#<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> +</pre> +<p>dal file di test, che convenzionalmente ha un nome che inizia per "test":</p> +<pre class="literal-block"> +#<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> +</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"> +#<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 +</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"> +#<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> +</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"> +#<doctest_runner.py> + +import doctest + +if __name__== "__main__": + doctest.testfile("test_isnumber.txt") + +#</doctest_runner.py> +</pre> +<p>Contenuto di 'test_isnumber.txt':</p> +<pre class="literal-block"> +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 +</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("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. +</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__== "__main__": + 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 = "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() +</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 < 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 "in the large". 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"> +>>> 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 "self-documenting" 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"> +>>> a = 1 +>>> del a +</pre> +<p>vi cancella il nome dal namespace:</p> +<pre class="doctest-block"> +>>> a +Traceback (most recent call last): + File "<stdin>", 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"> +>>> class C(object): +... def __del__(self): +... print 'Hai usato del' +... +>>> c = C() +>>> 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"> +>>> class C(object): +... def __del__(self): +... print 'Hai usato del' +... +>>> c = C() +>>> <CTRL-Z> 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"> +#<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 +</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"> +>>> 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"> +>>> c1 = C() +>>> c2 = C() +>>> c1.pippo +'sono una variabile di classe' +>>> 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"> +>>> C.pippo = 'adesso la cambio' +>>> c1.pippo +'adesso la cambio' +>>> 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"> +>>> 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' +</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 "__"</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 "hello!" + +class C(B): # figlio + def hello(self): + print "cucu!" + +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 "hello!" + +class C(B): + def __hello(self): # won't be called by B.__init__ + print "cucu!" + +b = B() # stampa 'hello!' +c = C() # stampe 'hello!' +</pre> +<p>I metodi protetti di tipo <tt class="docutils literal"><span class="pre">__<nome</span> <span class="pre">metodo></span></tt> non vanno confusi con i metodi +privati di tipo <tt class="docutils literal"><span class="pre">_<nome</span> <span class="pre">metodo></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 "Python in a Nutshell" +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 "This is not a number!" +</pre> +<p>Soluzione usando tkSimpleDialog:</p> +<pre class="literal-block"> +from tkSimpleDialog import askfloat +askfloat("Enter a number", "Number:") +</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("."): + 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("."): + 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(".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("."))) +</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("."), 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 "False".</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 "hello, world!"</a></h2> +<p>[In maniera portabile]</p> +<p>Soluzione più semplice:</p> +<pre class="literal-block"> +# hellotk.pyw +from tkMessageBox import showinfo +showinfo(message="hello") +</pre> +<p>Soluzione alternativa:</p> +<pre class="literal-block"> +# hellotk.pyw +import Tkinter as t +root = t.Tk() +l = t.Label(text="hello") +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"> +>>> from urllib2 import urlopen +>>> 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"> +#<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> +</pre> +<p>Soluzione usando i generatori, non HTML:</p> +<pre class="literal-block"> +#<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> +</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 "<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") +</pre> +<p>Soluzione più sofisticata, per darvi qualcosa su cui pensare:</p> +<pre class="literal-block"> +#<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> +</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 <BLANKLINE> : +<pre> +>>> print 'foo\n\nbar\n' +foo +<BLANKLINE> +bar +<BLANKLINE> + +</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 "," and ";". +This is an example of usage:</p> +<pre class="doctest-block"> +>>> from split import split +>>> split("hello, world!; welcome to the Italian Code Jam!") +['hello', 'world!', 'welcome to the Italian Code Jam!'] +</pre> +<p>Notice that 'split' eats whitespaces:</p> +<pre class="doctest-block"> +>>> split("hello , world") +['hello', 'world'] +</pre> +<pre class="doctest-block"> +>>> split("hello , ; world") +['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 <BLANKLINE> : +<pre> +>>> print 'foo\n\nbar\n' +foo +<BLANKLINE> +bar +<BLANKLINE> + +</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 <nome module> ... 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 "in the large". 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 "_" ... 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 "hello, world!".</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
|