Как я могу включить специальные символы (табуляция, новая строка) в строку результатов тестирования Python? - PullRequest
18 голосов
/ 12 января 2012

С учетом следующего скрипта Python:

# dedupe.py
import re

def dedupe_whitespace(s,spacechars='\t '):
    """Merge repeated whitespace characters.
    Example:
    >>> dedupe_whitespace(r"Green\t\tGround")  # doctest: +REPORT_NDIFF
    'Green\tGround'
    """
    for w in spacechars:
        s = re.sub(r"("+w+"+)", w, s)
    return s

Функция работает так, как задумано в интерпретаторе python:

$ python
>>> import dedupe
>>> dedupe.dedupe_whitespace('Purple\t\tHaze')
'Purple\tHaze'
>>> print dedupe.dedupe_whitespace('Blue\t\tSky')
Blue    Sky

Однако пример doctest завершается неудачно, поскольку символы табуляции преобразуются в пробелы перед сравнением со строкой результата:

>>> import doctest, dedupe
>>> doctest.testmod(dedupe)

1010 * дает *

Failed example:
    dedupe_whitespace(r"Green           Ground")  #doctest: +REPORT_NDIFF
Differences (ndiff with -expected +actual):
    - 'Green  Ground'
    ?       -
    + 'Green Ground'

Как я могу кодировать символы табуляции в строке heredoc doctest, чтобы сравнение результатов теста выполнялось надлежащим образом?

Ответы [ 6 ]

14 голосов
/ 13 января 2012

Я получил это, чтобы работать с использованием буквенной нотации строки документации:

def join_with_tab(iterable):
    r"""
    >>> join_with_tab(['1', '2'])
    '1\t2'
    """

    return '\t'.join(iterable)

if __name__ == "__main__":
    import doctest
    doctest.testmod()
11 голосов
/ 14 января 2012

Это необработанная запись строки heredoc (r"""), которая сделала трюк:

# filename: dedupe.py
import re,doctest
def dedupe_whitespace(s,spacechars='\t '):
    r"""Merge repeated whitespace characters.
    Example:
    >>> dedupe_whitespace('Black\t\tGround')  #doctest: +REPORT_NDIFF
    'Black\tGround'
    """
    for w in spacechars:
        s = re.sub(r"("+w+"+)", w, s)
    return s

if __name__ == "__main__":
    doctest.testmod()
2 голосов
/ 07 марта 2015

Это, в основном, ответ YatharhROCK, но немного более явный. Вы можете использовать необработанные строки или с двойным экранированием. Но почему?

Вам нужно, чтобы строковый литерал содержал действительный код Python, который при интерпретации является кодом, который вы хотите запустить / проверить. Они оба работают:

#!/usr/bin/env python

def split_raw(val, sep='\n'):
  r"""Split a string on newlines (by default).

  >>> split_raw('alpha\nbeta\ngamma')
  ['alpha', 'beta', 'gamma']
  """
  return val.split(sep)


def split_esc(val, sep='\n'):
  """Split a string on newlines (by default).

  >>> split_esc('alpha\\nbeta\\ngamma')
  ['alpha', 'beta', 'gamma']
  """
  return val.split(sep)

import doctest
doctest.testmod()

Эффект от использования необработанных строк и эффект двойного экранирования (экранирования от косой черты) оставляют в строке два символа: слеш и n. Этот код передается интерпретатору Python, в котором «косая черта, затем n» означает «символ новой строки» внутри строкового литерала.

Используйте то, что вы предпочитаете.

1 голос
/ 19 октября 2018

Я заставил его работать, экранируя символ табуляции в ожидаемой строке:

>>> function_that_returns_tabbed_text()
'\\t\\t\\tsometext\\t\\t'

вместо

>>> function_that_returns_tabbed_text()
\t\t\tsometext\t\t
1 голос
/ 14 августа 2013

TL; DR: Избегайте обратной косой черты, т. Е. Используйте \\n или \\t вместо \n или \t в ваших неизмененных строках;

Возможно, вы не захотите делать сырые строки документации, так как тогда вы не сможете использовать любые экранированные строки Python, включая те, которые вам могут понадобиться.

Для метода, который поддерживает использование обычных экранирований, просто экранируйте обратную косую черту в escape-символе обратной косой черты, поэтому после того, как Python его интерпретирует, он оставляет буквальный обратный слеш, за которым следует символ, который doctest может проанализировать.

1 голос
/ 12 января 2012

Вы должны установить NORMALIZE_WHITESPACE . Или, в качестве альтернативы, захватите выходные данные и сравните их с ожидаемым значением:

def dedupe_whitespace(s,spacechars='\t '):
    """Merge repeated whitespace characters.
    Example:
    >>> output = dedupe_whitespace(r"Black\t\tGround")  #doctest: +REPORT_NDIFF
    >>> output == 'Black\tGround'
    True
    """

Из раздела документации doctest Как используются примеры документацииРаспознано? :

Все символы с жесткими табуляциями расширяются до пробелов с использованием табуляции в 8 столбцов.Вкладки в выводе, генерируемые тестируемым кодом, не изменяются.Поскольку любые жесткие вкладки в примере вывода развернуты , это означает, что если вывод кода включает жесткие вкладки, единственный способ, которым может пройти тестирование, - это если параметр или директива NORMALIZE_WHITESPACE находится вэффект.В качестве альтернативы, тест может быть переписан, чтобы захватить выходные данные и сравнить их с ожидаемым значением как часть теста.Такая обработка вкладок в источнике была получена методом проб и ошибок и оказалась наименее подверженным ошибкам способом их обработки.Можно использовать другой алгоритм для обработки вкладок, написав собственный класс DocTestParser.

Редактировать: Моя ошибка, я понял документы наоборот.Вкладки расширяются до 8 пробелов как в строковом аргументе, передаваемом в dedupe_whitespace, так и в строковом литерале, который сравнивается в следующей строке, поэтому output содержит:

"Black Ground"

и сравнивается с:

"Black        Ground"

Я не могу найти способ обойти это ограничение без написания собственного DocTestParser или проверки на наличие дедуплицированных пробелов вместо вкладок.

...