Lawrence

Twist again
posts - 73, comments - 168, trackbacks - 37

domenica 18 gennaio 2009

IronPython in Action, considerazioni finali

Sono finalmente giunto alla fine del PDF beta del libro e devo dire che l'ho trovato davvero pieno di contenuti interessanti. È sicuramente uno splendido esempio di interazioni tra mondi che fino a non molto tempo fa si pensava completamente disconnessi.

Ci sono vantaggi e svantaggi sia nel mondo dei linguaggi statici che in quello dei linguaggi dinamici (io preferisco questi ultimi) e non è questa la sede per affrontare questo discorso ma sicuramente questo libro mostra una serie di scenari non tradizionalmente contemplati che possono tornare molto utili soprattutto nella programmazione Windows lato desktop.

I post di questa serie, oltre al preambolo, sono:
  1. introduzione
  2. introduzione a Python
  3. oggetti .NET e IronPython
  4. applicazioni e design pattern
  5. first class function e XML
  6. proprietà, dialog e Visual Studio
  7. testing
  8. protocolli e metaprogrammazione
  9. Windows Presentation Foundation
  10. system administration
  11. ASP.NET
  12. accesso ai dati e web service
  13. Silverlight
  14. estendere IronPython
  15. embedding dell'engine di IronPython
Update: ho pubblicato una recensione sul mio blog in inglese.

posted @ domenica 18 gennaio 2009 16.28 | Feedback (2) | Filed Under [ ironpython ]

IronPython in Action, embedding dell'IronPython engine

L’ultimo capitolo, il 15, riguarda l’embedding del runtime di IronPython all’interno di applicazioni C#/VB.NET e l’interazione con esso.

I post precedenti sono: estendere IronPython, Silverlight, accesso ai dati e web services, ASP.NET, system administration, WPF, protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

L’embedding di IronPython è sicuramente un comodo modo per fornire un ambiente di scripting ad una applicazione esistente, estenderla con plugin o aumentare l’integrazione fra vari linguaggi.

Ci sono vari modi per fare l’embedding di IronPython.

Eseguibile custom

È possibile distribuire una applicazione Python all’interno di un exe. L’engine di IronPython si crea usando il suo motore di hosting:

using IronPython.Hosting;
ScriptEngine engine = Python.CreateEngine();
ScriptSource source;
source = engine.CreateScriptSourceFromFile(programPath);
ScriptScope scope = enginsource.Execute(scope);

Il DLR supporta la creazione di engine multipli, per i dettagli rimando alle specifiche sull’hosting del DLR.

ScriptSource e ScriptCode permettono di eseguire codice Python da file o stringa. È anche possibile catturare eccezioni lanciate dal sorgente Python.

IronPython come motore di scripting

Una cosa veramente esoterica è la possibilità di infilare oggetti nello scope Python (ScriptScope) da C#, allo stesso modo si possono richiamare oggetti da tale scope. Usando CompiledCode si possono riusare i code objects senza doverli compilare ogni volta.

L’autore precisa come ScriptScope non sia legato a Python, in tal modo è potenzialmente possibile mischiare pezzi di codice in Python, Ruby e altri linguaggi del DLR nella stessa applicazione facendoli interagire!

L’esempio che mostra fa uso di varie tecniche compreso l’embedding del sorgente Python in una risorsa per evitarne la modifica dopo il deploy.

Plugin Python per applicazioni .NET

L’autore sviluppa un lungo esempio per mostrare come scrivere plugin per una applicazione .NET mostrando caratteristiche come: l’auto discovery dei plugin, il caricamento a runtime, la redirezione dello standard output ed error dell’hosted runtime e la gestione di specifiche eccezioni da codice Python.

Usare oggetti DLR da altri linguaggi .NET

Le possibilità di avere codice modificabile a runtime senza ricompilazione sono davvero infinite. L’esempio di questa sezione mostra come valutare a runtime pezzi di codice Python e interagire con gli oggetti risultanti da queste valutazioni.

L’autore fa anche notare come con C# 4 l’interazione con i linguaggi dinamici diventerà sicuramente meno verbosa e più potente.

posted @ domenica 18 gennaio 2009 16.09 | Feedback (0) | Filed Under [ ironpython ]

IronPython in Action, estendere IronPython

Con il capitolo 14 comincia la quarta e ultima parte del libro che va nei dettagli dell’interazione tra IronPython e il resto di .NET.

Questo capitolo tratta l’estensione di IronPython tramite linguaggi come C# e VB.NET.

I post precedenti sono: Silverlight, accesso ai dati e web services, ASP.NET, system administration, WPF, protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

IronPython è facilmente estendibile da C# e ci sono tecniche per esporre API Python friendly.

Tecnicamente qualsiasi linguaggio della piattaforma .NET è utilizzabile per estendere IronPython, l’autore si limita ai due principali: C# e VB.NET.

Vari idiomi C# si mappano automaticamente ad IronPython, come l’implementazione di IEnumerable, IDictionary, IList, l’operator overloading e gli indexers. È ovviamente possibile sfruttare la capacità di chiamare codice nativo (unmanaged) di C# da IronPython o addirittura chiamare IronPython da JavaScript in applicazioni Silverlight.

Di base le classi C# non sono mutabili dinamicamente come tutte le classi Python. Per ovviare a questa cosa e abilitare l’accesso dinamico agli attributi si possono usare metodi speciali come GetCustomMember, SetAfterMember, DeleteMember e GetMemberNames.

.NET supporta metodi con un numero variabile di argomenti, ma non supporta i comodissimi keyword argument emulabili tramite System.Runtime.InteropServices.DefaultParamValueAttribute oppure OptionalAttribute.

Trovo davvero interessante la possibilità di compilare e generare assembly a runtime tramite System.CodeDom.Compiler. L’autore mostra un esempio di funzione Generate che permette di farlo attraverso code provider per C# o VB.NET, compilando l’assembly in memoria o salvandola su disco. Questo permette anche di referenziarle a runtime:

import clr
assembly = Generate(source, 'WindowUtils', inMemory=True)
clr.AddReference(assembly)
from WindowUtils import WindowUtils

Davvero interessante :-)

posted @ domenica 18 gennaio 2009 13.45 | Feedback (0) | Filed Under [ ironpython ]

IronPython in Action, Silverlight

Il capitolo 13 mostra come usare IronPython nel browser attraverso Silverlight.

I post precedenti sono: accesso ai dati e web services, ASP.NET, system administration, WPF, protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

Le feature di Silverlight sono tutte utilizzabili da IronPython, l’unica cosa di cui si ha bisogno è il Silverlight Dynamic Languages SDK. All’interno dei package xap è possibile accedere ad altri moduli Python ed usare file() per caricare le risorse. Grazie al manifest file si può evitare di includere nel pacchetto anche le librerie di IronPython e caricarle remotamente, magari condividendole con altre applicazioni Silverlight e avvalendosi del caching HTTP.

Il libro poi mostra un esempio di client Twitter in circa 600 linee di codice spiegando: cross domain policies, come fare il debug, la struttura delle UI, come fare richieste web a terze parti interfacciandosi con la Twitter API, il threading, il supporto asincrono, il client side storage e altro ancora.

Per ovvie ragioni il sandboxing model di JavaScript impedisce le richieste HTTP a domini che non siano quello dell’applicazione, Silverlight invece è leggermente più lasco e permette richieste a domini di terze parti che esplicitamente, tramite una sorta di manifeste, permettono tali richieste. Twitter non è uno di questi quindi l’autore sviluppa un proxy server per ovviare a questo problema.

Le print di Python non funzionano in Silverlight, ma si può sempre redirezionare lo standard output ad un oggetto che scrive un div sul browser, ad esempio.

WebClient viene usato per fare le richieste HTTP, in maniera sincrona ed asincrona. L’autore aggiunge degli ID numerici per evitare le policy di caching di questa classe.

XmlReader ovviamente viene usato per parsare l’XML ritornato dall’API e DispatcherTimer viene usato per aggiornare la UI.

La classe System.IO.IsolatedStorage implementa il client side storage salvando 100kb (che a richiesta possono essere aumentati) nella cache del browser.

Gli ultimi esempi mostrano l’uso di video e video brush e l’uso di HtmlPage per aver completo accesso al DOM, interagire con il JavaScript e XMLHTTPRequest.

Potete usare il Silverlight IronPython Web IDE per sperimentare con Silverlight e IronPython.

posted @ domenica 18 gennaio 2009 12.46 | Feedback (1) | Filed Under [ ironpython ]

lunedì 12 gennaio 2009

IronPython In Action, accesso ai dati e webservice

Il capitolo 12 affronta l’accesso ai dati ed i web services (sia SOAP style che REST).

I post precedenti sono: ASP.NET, system administration, WPF, protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

L’esempio sviluppato dal libro in questo capitolo sfrutta ADO.NET, il database opensource PostgreSQL e il data provider Npgsql.

Personalmente mi sento di consigliarvi PostgreSQL che non ha nulla da invidiare a SQL Server e se lavorate con GIS è decisamente una figata. Quì dove lavoor io lo usiamo felicemente per applicazioni di produzione (usiamo anche SQL Server 2000, SQL Server 2005, SQLite e credo anche MySQL).

L’esempio è, prevedibilmente, un programma che sfrutta il provider per fare query, usare bind variables, transazioni e sfruttare i data adapters.

La parte sui web services invece comincia mostrando un esempio che consuma un feed Atom per poi buttarsi sul consumo di un servizio SOAP, MathService.

Sfrutta tool come wsdl.exe per creare una dll proxy del servizio remoto e la usa da Python normalmente:

>>> import clr
>>> clr.AddReference('MathService.dll')
>>> from MathService import MathService
>>> service = MathService()
>>> service.Add(3, 4)
7.0

Data la dinamicità di Python i proxy possono essere creati anche a runtime, ovviamente. Purtroppo però, dato che IronPython non supporta direttamente gli attributi, non è possibile creare un webservice SOAP.

Fortuna vuole che per REST e HTTP le cose siano più semplici. L’autore a questo punto sviluppa un intero servizio REST in IronPython per gestire delle note (composte da titolo, corpo e id). Sostanzialmente oltre ai vari verbi HTTP fa uso di WebRequest, HttpListener, HttpUtility e un po’ di XML.

Una delle applicazioni che abbiamo sviluppato è una web application che espone anche un REST web service consumabile in vari linguaggi in maniera molto intuitiva. Purtroppo, secondo la mia esperienza, devo dare ragione a chi si lamenta della poca interoperabilità di SOAP tra vari ambienti. Mi è capitato di sputare parecchio sangue per interfacciarmi a web service esposti da Java che si comportano in modo diverso da quelli SOAP esposti da .NET (direttamente da SQL Server).

posted @ lunedì 12 gennaio 2009 17.40 | Feedback (1) | Filed Under [ ironpython ]

IronPython In Action, ASP.NET

Il capitolo 11 comincia con una introduzione ad ASP.NET per poi buttarsi nello sviluppo di un clone web dell’applicazione MultiDoc realizzata precedentemente sul framework Windows.Forms.

I post precedenti sono: system administration, WPF, protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

Per usare IronPython con ASP.NET oltre Visual Web Developer Express o Visual Studio si ha bisogno anche di IronPython for ASP.NET disponibile sia per la versione classica (quella usata dal libro) che per la versione MVC di ASP.NET. I dettagli dell’integrazioen sono specificati in un apposito whitepaper: The New Dynamic Language Extensibility Model for ASP.NET.

La cosa interessante è che IronPython è perfettamente integrato nel debugger visuale, per cui non si perde niente in questa fase.

Dopo aver installato il pacchetto di integrazione il libro comincia a sviluppare l’applicazione MultiDoc sfruttando alcune feature, il Global.py, per avere a disposizione tutta la libreria standard di Python da ASP.NET.

Il primo esempio è sostanzialmente un excursus su controlli quali il Repeater ed eventi come Page_Load e Page_Prender.

Dopo aver introdotto il concetto di viewstate fa notare come la personalizzazione della serializzazione dello stesso non sia disponibile direttamente da IronPython. In pratica SaveViewState e LoadViewState non sono direttamente accessibili, alché usa una classe C# (evviva l’ambiente multi linguaggio!) per ovviare al problema.

In seguito, necessitando di serializzare oggetti Python, evidenzia come questi ultimi non siano direttamente gestibili dalla machinery del viewstate. Il trucco sta nell’usare la classe System.Web.UI.Pair e la serializzazione Python (pickling) abbinando i due nello stato del viewstate. Un trucco davvero carino, perché in tal modo si può serializare qualunque cosa ;-)

Il capitolo termina con la trasformazione della parte di editing dei MultiDoc in uno user control di ASP.NET.

L’autore fa notare come l’integrazione non sia appunto ancora totale, speriamo in futuro.

posted @ lunedì 12 gennaio 2009 17.17 | Feedback (1) | Filed Under [ ironpython ]

domenica 11 gennaio 2009

IronPython In Action, windows system administration

Il capitolo 10 fa notare come IronPython possa essere usato nelle attività di amministrazione di Windows giornalmente.

I post precedenti sono: WPF, protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

L’autore si butta nell’interfacciamento a WMI e PowerShell. Personalmente non immaginavo nemmeno che si potesse integrare PowerShell dentro IronPython e viceversa. Stellare :-)

La forza di Python nell’amministrazione di sistema sta nella versatilità, nella possibilità di usare il paradigma che si preferisce e nel fatto di avere tutta la ricchissima libreria a disposizione anche per i semplici script. È usato giornalmente per interfacciarsi agli ambienti Unix, a Win32 e per qualsiasi tipo di automazione nel sistema operativo.

Python ha un sacco di moduli per l’amministrazione di sistema: os per la gestione del sistema operativo (compresa la gestione di processi), os.path per i path, sys per le informazioni del sistema e gli standard input, output ed error, stat per gestire gli attributi dei file, shutil per operazioni di copy, move e delete ad alto livello e altri ancora.

Per mostrare tutto ciò l’autore crea un sottoinsieme dell’utility find di Unix (utilissa se volete trovare dei file in un albero di directory). Questo gli permette di dimostrare il parsing della linea di comando, la lettura di file INI, la navigazione delle directory ricorsivamente (usando generatori) e il pattern matching sui nomi dei file.

Un’altra tecnologia utilissima è WMI per ricavare informazioni dal sistema operativo sui processi, sulle macchine, sulla rete ecc. ecc. Usando System.Management e WQL si possono fare cose davvero interessanti ;-)

Il capitolo si conclude con una serie di esempi davvero esoterici dove si mostrano le interazioni tra PowerShell e IronPython in entrambi i sensi. Addirittura si possono usare i blocchi di PowerShell come event handler da IronPython!!

Ah, IronPython, ovviamente, può interagire anche con COM.

posted @ domenica 11 gennaio 2009 15.09 | Feedback (1) |

IronPython In Action, WPF e IronPython

La terza parte del libro si butta intensamente sull’uso di IronPython negli scenari più disparati di .NET. Da WPF a PowerShell a ASP.NET a praticamente qualsiasi cosa sia usabile in .NET.

Il capitolo 9 tratta Windows Presentation Foundation.

I post precedenti sono: protocolli e metaprogrammazione, testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

Il capitolo parte con una introduzione a WPF e continua presentando un esempio di UI sviluppata in WPF via codice e un altro esempio sviluppato usando XAML (caricato via codice tramite la classe System.Windows.Markup.XamlReader).

Fa riferimento ai vari tool per progettare UI visualmente: IronPython Studio, Visual Studio ed Expression Blend. Insomma, ce ne sono parecchi di modi :-)

Il secondo esempio in cui si butta l’autore è una UI più ricca che fa uso di varie controlli tra cui: Grid, ComboBox, CheckBox, Image, Expander, ScrollViewer, TextBlock.

Altri esempi includono l’uso della classe XamlWriter per serializzare le UI in XAML e la visualizzazione di documenti XPS dentro una applicazione WPF.

Come potete immaginare c’è un sacco di materiale in questo libro.

posted @ domenica 11 gennaio 2009 14.38 | Feedback (1) | Filed Under [ ironpython ]

venerdì 9 gennaio 2009

IronPython In Action, protocolli, metaprogrammazione e altro

Il capitolo 8 si butta in profondità sui concetti di protocollo, metaprogrammazione e spiega l’interfacciamento di IronPython con .NET nei casi meno ovvi.

I post precedenti sono: testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

Personalmente direi che arrivati al capitolo 8 (approfondendo con la documentazione di Python) si possiede una buona base per essere autonomi.

I protocolli, comunque, sono interfacce soft che funzionano tramite il duck typing senza alcun tipo di forzatura a compile time.

Esistono dei pacchetti, come zope.interface, che aiutano a formalizzare le cose nel caso di un sistema a componenti.

Personalmente mi era sfuggito ma l’autore fa notare come esista almeno un caso di duck typing in C#, attraverso il funzionamento dell’interfaccia IEnumerable e il foreach.

Ci sono tonnellate di esempi in Python sul funzionamento dei protocolli (dopotutto sono uno dei concetti fondamentali), tipo la determinazione della lunghezza di un contenitore:

>>> lst = [1, 2, 3, 4]
>>> d = {1: 'a', 'b': 'c'}
>>> class Container(object):
...     def __len__(self):
...         return 3
... 
>>> len(lst)
4
>>> len(d)
2
>>> len(Container())
3

La classe custom Container si adatta al protocollo __len__ proprio tramite duck typing.

Ad esempio esistono anche __str__ (chiamato da str(), %s e print) per la rappresentazione in stringa di un oggetto oppure __nonzero__ per determinare il valore booleano di verità di un oggetto.

Python supporta anche l’overloading degli operatori, implementato anch’esso tramite protocolli:

>>> class Three(object): 
...     def __add__(self, other):
...         return other + 3 
... 
>>> t = Three() 
>>> t + 2 
5

__add__ è soltanto uno dei tanti metodi speciali per implementare l’overloading, altri sono: __sub__, __div__, __mul__, __or__ ecc. ecc.

Per restare in tema anche il concetto di iterazione che la generazione sono protocolli. Il generator protocol usa l’espressione yield valore per sospendere l’esecuzione di una funzione, salvarne lo stato e permettere la ripresa dal punto di salvataggio.

Grazie alla possibilità di inviare valori o lanciare eccezioni all’interno di un generatore è possibile implementare delle coroutine anche in Python. Questo apre la porta a concetti come il green threading (thread in user space) o i thread cooperativi senza pre-emption.

Sempre grazie al concetto di protocollo è possibile customizzare l’accesso agli attributi di un oggetto usando metodi speciali come __getattr__, __setattr__, __delattr__ e le funzioni hasattr(), getattr(), setattr(), delattr(). Tra l’altro gli attributi (metodi compresi) sono memorizzati in un attributo speciale chiamato __dict__.

Una volta introdotto e spiegato il concetto di protocollo si passa alla metaprogrammazione avanzando la parola metaclasse.

Le metaclasse non sono altro che il tipo delle classi. Le classi in Python sono oggetti normalissimi come gli altri, quindi hanno un tipo, il loro tipo è la loro metaclasse.

La metaclasse di default in Python è type:

>>> type(type) is type
True

Usando l’attributo __metaclass__ è possibile modificare il comportamento di default:

>>> class PointlessMetaclass(type):
...     def __new__(meta, name, bases, classDict):
...         return type.__new__(meta, name, bases, classDict)
... 
>>> class SomeClass(object): 
...     __metaclass__ = PointlessMetaclass

Lo scopo delle metaclassi è semplice: introdurre modifiche prima dell’istanziazione di una classe. Non sono tremendamente usate in Python (per fortuna), ma sono utili per registrazioni di classi, creazione di DSL, ispezioni di classi, decorazioni, mixin e altro ancora.

Il libro a questo punto mostra un estensivo esempio di profiling di una classe attraverso una metaclasse che decora tutti i suoi metodi misurandone il tempo di esecuzione.

Dettagli a parte (per cui rimando al libro) il capitolo si conclude con una serie di differenze tra IronPython e la CLR per far capire come si affrontano in IronPython le cose che non hanno un corrispettivo chiaro.

Menziona: array .NET, generics, overloading di metodi esplicito, out, ref, params, puntatori, value e reference types, chiamata di metodi di una interfaccia, attributi .NET (che non sono supportati direttamente se non tramite classi stub).

Conclude mostrando come creare assembly usando la compilazione statica (anche a runtime) attraverso il metodo clr.CompileModules.

Il capitolo 8 è la fine della seconda parte del libro. La terza parte si butta sulle parti avanzate di .NET e il loro uso da IronPython (.NET 3, SilverLight, ASP.NET e altro ancora).

posted @ venerdì 9 gennaio 2009 14.13 | Feedback (1) | Filed Under [ ironpython ]

domenica 4 gennaio 2009

IronPython In Action, testing dinamico

Il capitolo 7 parla sostanzialmente di testing. L’autore, come ho già detto nel preambolo ha contribuito allo sviluppo di una applicazione IronPython che ha circa 40.000 righe e circa 150.000 di test…

I post precedenti sono: proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

Il default nel mondo Python per il testing unitario è il modulo unittest, modello sul framework JUnit che tutti conosciamo. Il suo funzionamento in parole povere: il runner identifica i metodi che cominciano con ‘test’, li esegue e si segna i fallimenti e gli errori. Esempio:

>>> import unittest
>>> class TCase(unittest.TestCase):
...     def setUp(self): pass
...     def tearDown(self): pass
...     def testSomething(self):
...         self.assertEquals(2, 2, "two it's not two")
... 
>>> unittest.main()
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

unittest.main() esegue il runner, i metodi setUp e tearDown vengono rispettivamente eseguiti prima e dopo i metodi di test. Si possono avere anche metodi di setup e teardown a livello di modulo volendo. Le asserzioni si verificano con i vari metodi assertXYZ. La linea di comando mostra un punto per i test passati, una ‘F’ per quelli falliti e una ‘E’ per quelli in errore. Ovviamente esiste anche più di una interfaccia grafica per il modulo unittest (più o meno integrate con i vari IDE).

Personalmente penso che ci siano framework più comodi e versatili di unittest. Alcuni come nose che sono basati su discovery e una architettura a plugin (facilmente estensibili), altri come py.test che di particolare hanno la possibilità di distribuire i test su N macchine.

Infine esistono tool come pyFIT per il fitnesse testing, e altri ancora.

A questo punto l’autore introduce l’uso dei mock objects per testare l’applicazione Windows Forms che sta sviluppando nei vari capitoli.

Apro una parentesi dicendo che a me è personalmente capitato di dover fare TDD sviluppando una applicazione GUI facendo anche uso di mock objects e devo dire che è davvero interessante. Come mi è anche capitato di usare tool come Selenium per fare test funzionali di applicazioni web. Sono tool che probabilmente poca gente usa ma che meritano un po’ di investimento.

Il libro ora comincia a creare un oggetto mock per testare l’applicazione MultiDoc riorganizzando nel frattempo anche il codice in maniera più organica, separando i test dal resto del codice.

Tra le molteplici librerie disponibili per Python l’autore sceglie quella che si è scritto da solo (che tra l’altro è anche la più diffusa credo, e quella che vi consiglio nel caso siate interessati): Mock.

Un altra caratteristica molto usata nel testing, prerogativa dei linguaggi dinamici, è il monkey patching ovvero la possibilità di patchare a runtime gli oggetti. È talmente importante che personalmente mi ha “salvato il culo” due o tre volte quando ho trovato bug in librerie e non c’era tempo per aspettare la versione successiva.

Per comprendere appieno il monkey patching di un metodo in Python bisogna comprendere le regole di lookup di un metodo. In breve: una istruzione come obj.method() cerca il metodo prima nell’istanza, obj, poi nella classe e poi in tutti gli antenati di quella classe. Se si aggiunge un metodo a runtime ad una classe questa modifica è riflessa su tutte le istanze di tale classe, se invece il metodo viene aggiunto ad una singola istanza la modifica non si riflette affatto:

>>> class Foo(object): pass
... 
>>> f = Foo()
>>> g = Foo()
>>> def method(self): return 'method called'
... 
>>> Foo.method = method # add a method at runtime
>>> f.method() # both the instances have it
'method called'
>>> g.method()
'method called'
>>> del Foo.method # remove the method at runtime
>>> def method2(): return 'method called'
... 
>>> f.method = method2 # add a method to the instance
>>> f.method() # f has it
'method called'
>>> g.method() # g doesn't
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'method'
>>>

Notare che method ha self come argomento, mentre method2 non ha nessun argomento. Questo perché il lookup in una classe crea un oggetto metodo bound a cui passare self. In una istanza è semplicemente una funzione unbound.

Il libro dopo aver introdotto il concetto di monkey patching e le regole di lookup usa il primo concetto per patchare a runtime un metodo facendo in modo che ritorni un oggetto mock invece che l’oggetto reale. Molto semplice, una volta capito cosa c’è dietro. È una pratica molto comune.

Dopodiché l’autore introduce la dependency injection per diminuire l’accoppiamento tra il comportamento dei test e quello delle classi.

Il capitolo termina con una introduzione al testing funzionale e le user story. Per testare in maniera black box alcune feature dell’applicazione, come la creazione di un nuovo tab per una pagina, usa il multithreading e Invoke per creare un mini framework per inviare pressioni di tasti, movimenti di mouse e pressione di bottoni all’applicazione da testare.

posted @ domenica 4 gennaio 2009 21.54 | Feedback (1) | Filed Under [ ironpython ]

Powered by: