web-dev-qa-db-fra.com

Comment puis-je inclure des caractères spéciaux (tabulation, nouvelle ligne) dans une chaîne de résultats python doctest?

Étant donné le script python suivant:

# 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

La fonction fonctionne comme prévu dans l'interpréteur python:

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

Cependant, l'exemple de doctest échoue car les caractères de tabulation sont convertis en espaces avant la comparaison avec la chaîne de résultat:

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

donne

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

Comment puis-je encoder des caractères de tabulation dans une chaîne doctest heredoc afin qu'une comparaison des résultats de test soit effectuée correctement?

18
hobs

J'ai réussi à utiliser la notation littérale pour la chaîne de caractères:

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

    return '\t'.join(iterable)

if __== "__main__":
    import doctest
    doctest.testmod()
14
wutz

C'est la notation de chaîne heredoc brute (r""") qui a fait l'affaire:

# 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 __== "__main__":
    doctest.testmod()
10
hobs

C'est la réponse de YatharhROCK, mais un peu plus explicite. Vous pouvez utiliser des chaînes brutes ou double escaping. Mais pourquoi?

Vous avez besoin que le littéral de chaîne contienne un code Python valide qui, une fois interprété, correspond au code que vous souhaitez exécuter/tester. Ces deux fonctionnent:

#!/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()

L’effet de l’utilisation de chaînes brutes et l’effet de double échappement (échappent à la barre oblique) laissent dans la chaîne deux caractères, la barre oblique et le n. Ce code est transmis à l'interpréteur Python, qui prend "slash then n" pour signifier "caractère de nouvelle ligne" dans un littéral de chaîne.

Utilisez ce que vous préférez.

2
arantius

TL; DR: Échappe à la barre oblique inversée, c’est-à-dire, utilisez \\n ou \\t au lieu de \n ou \t dans vos chaînes non modifiées;

Vous ne voulez probablement pas rendre vos docstrings brutes car vous ne pourrez plus utiliser d’échappements de chaînes Python, y compris ceux que vous voudrez peut-être.

Pour une méthode prenant en charge les échappements normaux, il suffit d'échapper la barre oblique inversée dans l'échappement de barre oblique inversée afin que, une fois que Python l'interprète, elle laisse une barre oblique inverse littérale suivie du caractère que doctest peut analyser.

1
Yatharth Agarwal

Vous devez définir le NORMALIZE_WHITESPACEOu, alternativement, capturez le résultat et comparez-le à la valeur attendue:

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
    """

De la section doctest de la documentation comment les exemples de docstring sont-ils reconnus? :

Tous les caractères de tabulation sont développés en espaces, en utilisant des taquets de tabulation à 8 colonnes. Les onglets en sortie générés par le code testé ne sont pas modifiés. Etant donné que tous les onglets durs de l'exemple de sortie sont développés , cela signifie que si la sortie de code comprend des onglets durs, le doctest ne peut passer que si NORMALIZE_WHITESPACE L'option ou la directive est en vigueur. Sinon, le test peut être réécrit pour capturer la sortie et la comparer à une valeur attendue dans le cadre du test. Cette manipulation des onglets dans la source a été obtenue par essais et erreurs, et s’est révélée être le moyen le moins sujet aux erreurs. Il est possible d'utiliser un algorithme différent pour gérer les onglets en écrivant une classe personnalisée DocTestParser.

Edit: Mon erreur, j'ai compris la documentation à l'envers. L'argument de chaîne passé à dedupe_whitespace et le littéral de chaîne en cours de comparaison sur la ligne suivante sont étendus à 8 espaces, de sorte que output contienne:

"Black Ground"

et est comparé à:

"Black        Ground"

Je ne peux pas trouver un moyen de surmonter cette limitation sans écrire votre propre DocTestParser ou tester des espaces dédupliqués au lieu de tabulations.

1
Chewie

Je l'ai fait fonctionner en échappant le caractère de tabulation dans la chaîne attendue:

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

au lieu de

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