2010-10-07 17 views
6

Mi proyecto está dirigido a un dispositivo incrustado de bajo costo y bajo recurso. Depende de una base de código Python relativamente grande y extenso, de la cual mi uso de sus API es bastante específico.Uso de la herramienta de cobertura de código Python para comprender y reducir el código fuente de una biblioteca grande

Estoy dispuesto a podar el código de esta biblioteca de nuevo a su mínima expresión, mediante la ejecución de mi banco de pruebas dentro de las herramientas de cobertura como de Ned Batchelder cobertura o hoja de parra, a continuación, las secuencias de comandos eliminación de código no utilizado dentro del varios módulos/archivos. Esto ayudará no solo a comprender las partes internas de las bibliotecas, sino también a facilitar la escritura de los parches. Ned en realidad se refiere al uso de herramientas de cobertura para "codificar el código complejo" en una de sus conversaciones en línea.

Mi pregunta a la comunidad SO es si la gente tiene experiencia de usar herramientas de cobertura de esta manera que no les importaría compartir? ¿Cuáles son los peligros si es que hay alguno? ¿Es la herramienta de cobertura una buena elección? ¿O sería mejor invertir mi tiempo con figleaf?

El final del juego es ser capaz de generar automáticamente un nuevo árbol de código fuente para la biblioteca, basado en el árbol original, pero sólo con el código de realmente utilizado cuando corro nosetests.

Si alguien ha desarrollado una herramienta que hace un trabajo similar para sus aplicaciones y bibliotecas de Python, sería fantástico obtener una línea de base desde la cual comenzar el desarrollo.

Con suerte mi descripción tiene sentido para los lectores ...

+1

Necesita tener un conjunto realmente exhaustivo de pruebas, o corre el riesgo de eliminar la única función que sus pruebas no llamaron, pero que es necesaria en algunas circunstancias exóticas pero reales. Me preocuparía * mucho * acerca de esto, porque es muy difícil obtener una cobertura de prueba del 100%. ¿Qué tan seguro está de que sus pruebas sean exhaustivas? Sistema integrado: ¿está probando "falta de memoria"? –

+0

.... Ned puede haber hecho referencia a la cobertura de prueba para "entender", por ejemplo, encontrar el código relacionado con una pieza específica de funcionalidad, y eso está bien, pero no es lo mismo que encontrar * todas * piezas de funcionalidad, que código. –

Respuesta

8

Lo que quiere no es "cobertura de prueba", es el cierre transitivo de "puede llamar" desde la raíz del cálculo. (En las aplicaciones con subprocesos, debe incluir "puede tenedor").

Desea designar un conjunto pequeño (quizás solo 1) de las funciones que componen los puntos de entrada de su aplicación, y desea rastrear a través de todas las calles posibles (condicional o incondicional) de ese conjunto pequeño. Este es el conjunto de funciones que debe tener.

Python hace esto muy difícil en general (IIRC, no soy un experto profundo de Python) debido al despacho dinámico y especialmente debido a "eval". Razonar acerca de qué función se puede llamar puede ser bastante complicado para un analizador estático aplicado a lenguajes altamente dinámicos.

Se podría usar la cobertura de prueba como una forma de sembrar la relación "can call" con hechos específicos de "did call"; que podría atrapar muchos despachos dinámicos (dependiendo de la cobertura de su suite de pruebas). Entonces el resultado que desea es el cierre transitivo de la llamada "puedo o lo hice". Esto aún puede ser erróneo, pero es probable que sea menor.

Una vez que obtenga un conjunto de funciones "necesarias", el siguiente problema será eliminando las funciones innecesarias de los archivos fuente que tiene.Si la cantidad de archivos con los que comienza es grande, el esfuerzo manual para eliminar los objetos muertos puede ser bastante alto. Peor aún, es probable que revise su aplicación y luego la respuesta sobre qué cambios mantener. Por lo tanto, para cada cambio (versión), debe volver a calcular confiablemente esta respuesta.

Mi empresa crea una herramienta que hace este análisis para paquetes Java (con advertencias apropiadas sobre cargas dinámicas y reflexión): la entrada es un conjunto de archivos Java y (como se indicó anteriormente) un conjunto designado de funciones raíz. La herramienta calcula el gráfico de llamadas, y también encuentra todas las variables de miembros muertos y produce dos salidas: a) la lista de métodos y miembros supuestamente muertos, yb) un conjunto revisado de archivos con todas las cosas "muertas" eliminadas. Si crees a), entonces usas b). Si cree que a) está mal, agregue los elementos enumerados en a) al conjunto de raíces y repita el análisis hasta que piense que a) es correcto. Para hacer esto, necesita una herramienta de análisis estático que analice Java, calcule el gráfico de llamadas y luego revise los módulos de código para eliminar las entradas muertas. La idea básica se aplica a cualquier idioma.

Necesitaría una herramienta similar para Python, me esperaba.

Quizás pueda simplemente dejar caer los archivos que están completamente sin usar, aunque eso aún puede ser un gran trabajo.

+1

+1 buen análisis del problema. – bstpierre

+0

En teoría, para mi aplicación los unittest serán una aproximación muy cercana del cierre transitivo que refieres, aunque como correctamente señalas, nunca puedo estar absolutamente seguro sin un análisis más riguroso, con una consideración adicional de las posibilidades de salida (Exceptions , finalmente-bloques, etc ...). Ser capaz de podar ramas enteras, con un propósito ortogonal de los bits de núcleo que estoy usando, sería un filtro útil. Claramente hay riesgos con esto que necesito considerar más profundamente. – codeasone

+0

Incluso si no despliego el árbol podado, ciertamente enfocaré mi atención cuando se trata de depuración lógica dentro de la biblioteca o desarrollo de parches, que es un objetivo secundario. – codeasone

0

No he utilizado la cobertura para la poda, pero parece que debe hacer bien. He usado la combinación de nosetests + cobertura, y funcionó mejor para mí que figleaf. En particular, encontré útil el informe html de nosetests + coverage; esto debería ser útil para comprender dónde se encuentran las partes no utilizadas de la biblioteca.

+0

Gracias por los comentarios sobre figleaf. Daré una oportunidad a ambos, pero concentraré mi atención inicial en la cobertura. – codeasone

1

Como han señalado otros, la cobertura puede indicarle qué código se ha ejecutado. El truco para usted es asegurarse de que su suite de pruebas realmente ejerza el código por completo. El caso de falla aquí es un exceso de poda porque sus pruebas saltaron algún código que realmente será necesario en la producción.

Asegúrese de obtener la última versión de coverage.py (v3.4): agrega una nueva función para indicar archivos que nunca se ejecutan.

BTW :: para una primera poda de corte, Python proporciona un truco perfecto: eliminar todos los archivos .pyc en su árbol de origen, luego ejecutar sus pruebas. ¡Los archivos que todavía no tienen un archivo .pyc claramente no se ejecutaron!

+0

Gracias por esos consejos Ned. – codeasone

Cuestiones relacionadas