Как я могу обработать этот текстовый файл и разобрать то, что мне нужно? - PullRequest
2 голосов
/ 08 августа 2009

Я пытаюсь разобрать вывод из модуля Python doctest и сохранить его в файле HTML.

У меня есть вывод, похожий на этот:

**********************************************************************
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.

Каждой ошибке предшествует строка звездочек, которые отделяют каждую ошибку теста друг от друга.

То, что я хотел бы сделать, это удалить имя файла и метод, который дал сбой, а также ожидаемые и фактические результаты. Затем я хотел бы создать HTML-документ, используя это (или сохранить его в текстовом файле, а затем выполнить второй раунд анализа).

Как я могу сделать это, используя только Python или некоторую комбинацию утилит оболочки UNIX?

РЕДАКТИРОВАТЬ: я сформулировал следующий сценарий оболочки, который соответствует каждому блоку, как я хотел бы, но я не уверен, как перенаправить каждое соответствие sed в свой собственный файл.

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

Ответы [ 4 ]

4 голосов
/ 08 августа 2009

Вы можете написать программу на Python, чтобы отделить ее от других, но, возможно, лучше было бы изучить модификацию doctest для вывода нужного вам отчета. Из документов для 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`.
1 голос
/ 08 августа 2009

Я написал быстрый парсер в pyparsing, чтобы сделать это.

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

дает

['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']
1 голос
/ 08 августа 2009

Это быстрый и грязный скрипт, который разбивает выходные данные в кортежи с соответствующей информацией:

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)
0 голосов
/ 08 августа 2009

Это, вероятно, один из наименее элегантных скриптов на python, который я когда-либо писал, но он должен иметь структуру, позволяющую делать то, что вы хотите, не прибегая к утилитам UNIX и отдельным скриптам для создания html. Он не проверен, но для его работы требуется лишь небольшая настройка.

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()
...