2009-08-07 6 views
2

J'essaye d'analyser ouput à partir du module doctest de Python et de le stocker dans un fichier HTML.Comment puis-je traiter ce fichier texte et analyser ce dont j'ai besoin?

J'ai un résultat similaire à:

********************************************************************** 
File "example.py", line 16, in __main__.factorial 
Failed example: 
    [factorial(n) for n in range(6)] 
Expected: 
    [0, 1, 2, 6, 24, 120] 
Got: 
    [1, 1, 2, 6, 24, 120] 
********************************************************************** 
File "example.py", line 20, in __main__.factorial 
Failed example: 
    factorial(30) 
Expected: 
    25252859812191058636308480000000L 
Got: 
    265252859812191058636308480000000L 
********************************************************************** 
1 items had failures: 
    2 of 8 in __main__.factorial 
***Test Failed*** 2 failures. 

Chaque échec est précédé d'une ligne d'astérisques, qui délimitent chaque échec de test de l'autre.

Ce que je voudrais faire est de supprimer le nom de fichier et la méthode qui a échoué, ainsi que les résultats attendus et réels. Ensuite, je voudrais créer un document HTML en utilisant ceci (ou le stocker dans un fichier texte, puis faire un second tour d'analyse). Comment puis-je faire cela en utilisant uniquement Python ou une combinaison d'utilitaires shell UNIX?

EDIT: J'ai formulé le script shell suivant qui correspond à chaque bloc comme je le souhaite, mais je ne sais pas comment rediriger chaque correspondance sed vers son propre fichier.

python example.py | sed -n '/.*/,/^\**$/p' > `mktemp error.XXX` 
+0

Si vous supprimez le fichier, la méthode, le résultat prévu et le résultat réel, que reste-t-il? – juanjux

+0

Eh bien, j'ai juste du mal à les analyser en morceaux séparés, parce que jusqu'à présent, je ne peux saisir le bloc entier à la fois, pas les champs individuels. – samoz

Répondre

1

Ceci est un script rapide et sale qui analyse la sortie en tuples avec les informations pertinentes:

import sys 
import re 

stars_re = re.compile('^[*]+$', re.MULTILINE) 
file_line_re = re.compile(r'^File "(.*?)", line (\d*), in (.*)$') 

doctest_output = sys.stdin.read() 
chunks = stars_re.split(doctest_output)[1:-1] 

for chunk in chunks: 
    chunk_lines = chunk.strip().splitlines() 
    m = file_line_re.match(chunk_lines[0]) 

    file, line, module = m.groups() 
    failed_example = chunk_lines[2].strip() 
    expected = chunk_lines[4].strip() 
     got = chunk_lines[6].strip() 

    print (file, line, module, failed_example, expected, got) 
4

Vous pouvez écrire un programme Python pour prendre cette part, mais peut-être une meilleure chose à faire serait de se pencher sur la modification doctest à la sortie du rapport que vous voulez en premier lieu. De la documentation pour doctest.DocTestRunner:

        ... the display output 
can be also customized by subclassing DocTestRunner, and 
overriding the methods `report_start`, `report_success`, 
`report_unexpected_exception`, and `report_failure`. 
+0

Je vais certainement y jeter un coup d'oeil! – samoz

1

j'ai écrit un analyseur rapide dans pyparsing pour le faire .

from pyparsing import * 

str = """ 
********************************************************************** 
File "example.py", line 16, in __main__.factorial 
Failed example: 
    [factorial(n) for n in range(6)] 
Expected: 
    [0, 1, 2, 6, 24, 120] 
Got: 
    [1, 1, 2, 6, 24, 120] 
********************************************************************** 
File "example.py", line 20, in __main__.factorial 
Failed example: 
    factorial(30) 
Expected: 
    25252859812191058636308480000000L 
Got: 
    265252859812191058636308480000000L 
********************************************************************** 
""" 

quote = Literal('"').suppress() 
comma = Literal(',').suppress() 
in_ = Keyword('in').suppress() 
block = OneOrMore("**").suppress() + \ 
     Keyword("File").suppress() + \ 
     quote + Word(alphanums + ".") + quote + \ 
     comma + Keyword("line").suppress() + Word(nums) + comma + \ 
     in_ + Word(alphanums + "._") + \ 
     LineStart() + restOfLine.suppress() + \ 
     LineStart() + restOfLine + \ 
     LineStart() + restOfLine.suppress() + \ 
     LineStart() + restOfLine + \ 
     LineStart() + restOfLine.suppress() + \ 
     LineStart() + restOfLine 

all = OneOrMore(Group(block)) 

result = all.parseString(str) 

for section in result: 
    print section 

donne

['example.py', '16', '__main__.factorial', ' [factorial(n) for n in range(6)]', ' [0, 1, 2, 6, 24, 120]', ' [1, 1, 2, 6, 24, 120]'] 
['example.py', '20', '__main__.factorial', ' factorial(30)', ' 25252859812191058636308480000000L', ' 265252859812191058636308480000000L'] 
+0

Très beau travail! Je pense que je vais jouer avec ça ... – samoz

+0

Pourquoi str a 3 "marques avant et après le texte? Désolé, mon Python n'est vraiment pas génial – samoz

+0

Les guillemets simples signifient juste une chaîne de texte qui peut aller sur plusieurs lignes. –

0

C'est probablement l'un des moins élégants scripts python je l'ai déjà écrit, mais il devrait avoir le cadre de faire ce que vous voulez sans avoir recours à des utilitaires et scripts UNIX distincts pour créer le code HTML. Il n'a pas été testé, mais il ne devrait avoir besoin que de modifications mineures pour fonctionner.

import os 
import sys 

#create a list of all files in directory 
dirList = os.listdir('') 

#Ignore anything that isn't a .txt file. 
# 
#Read in text, then split it into a list. 
for thisFile in dirList: 
    if thisFile.endswith(".txt"): 
     infile = open(thisFile,'r') 

     rawText = infile.read() 

     yourList = rawText.split('\n') 

     #Strings 
     compiledText = '' 
     htmlText = '' 

     for i in yourList: 

      #clunky way of seeing whether or not current line 
      #should be included in compiledText 

      if i.startswith("*****"): 
       compiledText += "\n\n--- New Report ---\n" 

      if i.startswith("File"): 
       compiledText += i + '\n' 

      if i.startswith("Fail"): 
       compiledText += i + '\n' 

      if i.startswith("Expe"): 
       compiledText += i + '\n' 

      if i.startswith("Got"): 
       compiledText += i + '\n' 

      if i.startswith(" "): 
       compiledText += i + '\n' 


    #insert your HTML template below 

    htmlText = '<html>...\n <body> \n '+htmlText+'</body>... </html>' 


    #write out to file 
    outfile = open('processed/'+thisFile+'.html','w') 
    outfile.write(htmlText) 
    outfile.close() 
Questions connexes