2010-10-07 17 views
6

Il mio progetto si rivolge a un dispositivo embedded a basso costo e con risorse limitate. Sono dipendente da una base di codice Python relativamente ampia e ampia, di cui il mio uso delle sue API è piuttosto specifico.Utilizzo dello strumento di copertura del codice Python per la comprensione e l'eliminazione del codice sorgente di una grande libreria

Sono pronto a potare il codice di questa libreria al suo minimo indispensabile, eseguendo la mia suite di test nel giro di strumenti di copertura come Ned Batchelder copertura o foglia di fico, quindi scripting rimozione di codice non utilizzato all'interno della vari moduli/file. Ciò aiuterà non solo a comprendere le parti interne delle librerie, ma anche a rendere più facile la scrittura di eventuali patch. Ned in realtà si riferisce all'uso di strumenti di copertura per "decodificare" codice complesso in uno dei suoi discorsi online.

La mia domanda alla comunità SO è se le persone hanno l'esperienza di utilizzare gli strumenti di copertura in questo modo che a loro non dispiacerebbe condividere? Quali sono le eventuali insidie? Lo strumento di copertura è una buona scelta? O sarebbe meglio investire il mio tempo con figleaf?

Il fine del gioco è quello di essere in grado di generare automaticamente un nuovo albero dei sorgenti per la libreria, sulla base del albero originale, ma solo compreso il codice effettivamente utilizzato quando corro nosetests.

Se qualcuno ha sviluppato uno strumento che svolge un lavoro simile per le proprie applicazioni e librerie Python, sarebbe fantastico ottenere una base da cui iniziare lo sviluppo.

Spero che la mia descrizione ha un senso per i lettori ...

+1

È necessario disporre di serie di test davvero completa, o si rischia di sfoltire l'unica funzione che i test non hanno chiamato, ma è necessaria in alcune circostanze esotiche ma reali. Mi preoccuperei * duramente * di questo, perché è molto difficile raggiungere il 100% di copertura del test. Sei sicuro che i tuoi test siano completi? Sistema integrato: stai testando "memoria insufficiente"? –

+0

.... Ned potrebbe avere referenziato la copertura di test per "capire", ad esempio, trovare il codice relativo a una specifica funzionalità, e va bene, ma non è la stessa cosa che trovare * tutti * pezzi di funzionalità-supporto codice. –

risposta

8

Quello che vuoi non è "copertura di prova", è la chiusura transitiva di "può chiamare" dalla radice del calcolo. (Nelle applicazioni con thread, è necessario includere "può fork").

Si desidera designare un piccolo set (forse solo 1) di funzioni che costituiscono i punti di ingresso della propria applicazione e si desidera tracciare tutti i possibili calle (condizionali o incondizionati) di quel piccolo insieme. Questo è l'insieme di funzioni che deve avere.

Python rende questo molto difficile in generale (IIRC, non sono un esperto di Python profondo) a causa di dispatch dinamico e soprattutto a causa di "eval". Ragionare su quale funzione può essere chiamata può essere piuttosto complicata per un analizzatore statico applicato a linguaggi altamente dinamici.

Si potrebbe usare la copertura di test come modo per seminare la relazione "può chiamare" con specifici fatti "fatti chiamare"; questo potrebbe catturare molte spedizioni dinamiche (dipende dalla copertura della tua suite di test). Quindi il risultato che vuoi è la chiusura transitiva della chiamata "can o did". Questo può ancora essere errato, ma probabilmente lo sarà meno.

Una volta ottenuto un set di funzioni "necessarie", il problema successivo sarà rimozione di le funzioni non necessarie dai file di origine che si hanno.Se il numero di file con cui inizi è grande, lo sforzo manuale per rimuovere le cose morte potrebbe essere piuttosto elevato. Peggio ancora, è probabile che rivedrai la tua domanda, e poi la risposta su cosa mantenere i cambiamenti. Quindi per ogni cambiamento (rilascio), è necessario ricalcolare in modo affidabile questa risposta.

La mia azienda crea uno strumento che esegue questa analisi per pacchetti Java (con avvertimenti appropriati relativi a carichi dinamici e riflessione): l'input è un insieme di file Java e (come sopra) un insieme designato di funzioni root. Lo strumento calcola il grafo delle chiamate e trova anche tutte le variabili dei membri morti e produce due output: a) l'elenco di metodi e membri presumibilmente morti, e b) un insieme di file revisionati con tutte le cose "morte" rimosse. Se credi a), allora usi b). Se pensi che a) sia sbagliato, allora aggiungi gli elementi elencati in a) all'insieme di radici e ripeti l'analisi finché pensi che a) sia giusto. Per fare ciò, è necessario uno strumento di analisi statico che analizzi Java, calcoli il grafico delle chiamate e quindi rivedi i moduli di codice per rimuovere le voci morte. L'idea di base si applica a qualsiasi lingua.

Avresti bisogno di uno strumento simile per Python, mi aspetterei.

Forse si può limitarsi a lasciare solo i file che sono completamente inutilizzati, anche se potrebbe essere ancora molto lavoro.

+1

+1 buona analisi del problema. – bstpierre

+0

In teoria, per la mia applicazione le unittest saranno un'approssimazione molto vicina alla chiusura transitiva a cui si fa riferimento - anche se come si indica correttamente, non potrò mai essere assolutamente sicuro senza un'analisi più rigorosa, con un'ulteriore considerazione delle possibilità di uscita (Eccezioni , infine-blocchi ecc ...). Essere in grado di potare interi rami, con lo scopo ortogonale dai bit di nucleo che sto usando sarebbe un utile filtro. Ci sono chiaramente rischi con questo che ho bisogno di considerare più profondamente. – codeasone

+0

Anche se non distribuisco l'albero potato, si concentrerà sicuramente la mia attenzione quando si tratta di eseguire il debug della logica all'interno della libreria o di sviluppare patch, che è un obiettivo secondario. – codeasone

0

Non ho usato la copertura per la potatura fuori, ma sembra che dovrebbe fare bene. Ho usato la combinazione di nosetests + copertura e ha funzionato meglio di figleaf. In particolare, ho trovato utile il report html di nosetests +: questo dovrebbe essere utile per capire dove sono le porzioni inutilizzate della libreria.

+0

Grazie per il feedback sulla figleaf. Darò entrambi uno sparo, ma concentrerò la mia attenzione iniziale sulla copertura. – codeasone

1

Come altri hanno sottolineato, la copertura può indicare quale codice è stato eseguito. Il trucco per te è essere sicuri che la tua suite di test eserciti veramente il codice completamente. Il caso di errore qui è l'eccesso di potatura perché i test hanno saltato del codice che sarà veramente necessario nella produzione.

Assicurati di ottenere l'ultima versione di coverage.py (v3.4): aggiunge una nuova funzionalità per indicare i file che non vengono mai eseguiti.

BTW :: per una prugna di primo taglio, Python fornisce un trucco chiaro: rimuovere tutti i file .pyc nell'albero dei sorgenti, quindi eseguire i test. I file che non hanno ancora file .pyc non sono stati chiaramente eseguiti!

+0

Grazie per questi suggerimenti Ned. – codeasone

Problemi correlati