web-dev-qa-db-ja.com

python doctest結果文字列に特殊文字(タブ、改行)を含めるにはどうすればよいですか?

次の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)

与える

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

テスト結果の比較が適切に実行されるように、doctestヒアドキュメント文字列でタブ文字をエンコードするにはどうすればよいですか?

19
hobs

これは生のヒアドキュメント文字列表記です(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()
11
hobs

これは基本的に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の2文字を残します。このコードはPythonインタープリターに渡されます。インタープリターは、文字列リテラル内の「改行文字」を意味する「slashthenn」を取ります。

お好みの方を使用してください。

2
arantius

TL; DR:バックスラッシュをエスケープします。つまり、変更されていない文字列では、\\nまたは\\tの代わりに\nまたは\tを使用します。

おそらく、docstringを生にしたくないでしょう。そうすると、必要なものを含め、Python文字列エスケープを使用できなくなります。

通常のエスケープの使用をサポートするメソッドの場合、バックスラッシュ文字エスケープでバックスラッシュをエスケープするだけなので、Pythonが解釈した後、リテラルのバックスラッシュの後にdoctestという文字が続きます。解析できます。

1

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ドキュメントセクションから Docstringの例はどのように認識されますか?

すべてのハードタブ文字は、8列のタブストップを使用してスペースに展開されます。テストされたコードによって生成された出力のタブは変更されません。サンプル出力のハードタブは展開されているため、コード出力にハードタブが含まれている場合、doctestが合格できる唯一の方法は NORMALIZE_WHITESPACE オプションまたはディレクティブが有効です。または、テストを書き直して出力をキャプチャし、テストの一部として期待値と比較することもできます。ソース内のタブのこの処理は試行錯誤によって達成され、エラーが発生しにくい方法であることが証明されています。カスタムのDocTestParserクラスを作成することにより、タブを処理するために別のアルゴリズムを使用することができます。

編集:私の間違い、私はドキュメントを逆に理解しました。 dedupe_whitespaceに渡される文字列引数と次の行で比較される文字列リテラルの両方でタブが8スペースに拡張されているため、outputには次のものが含まれます。

"Black Ground"

と比較されています:

"Black        Ground"

独自のDocTestParserを作成するか、タブの代わりに重複排除されたスペースをテストしない限り、この制限を克服する方法を見つけることができません。

1
Chewie

期待される文字列のタブ文字をエスケープすることで機能するようになりました。

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

の代わりに

>>> function_that_returns_tabbed_text()
\t\t\tsometext\t\t
1
Jacob Nowitzky