2012-01-12 25 views
18

Dado el siguiente script en Python:¿Cómo puedo incluir caracteres especiales (tabulación, nueva línea) en una cadena de resultados doctest de 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 

La función funciona como está previsto en el intérprete de Python:

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

Sin embargo, el ejemplo doctest falla debido a los caracteres de tabulación se convierten en espacios antes de la comparación de los resultados cadena:

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

da

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

¿Cómo puedo codificar caracteres de tabulación en una cadena doctest heredoc para que la comparación de resultados de prueba se realice de forma adecuada?

Respuesta

13

He conseguido que esto funcione usando la notación literal de cadena para la cadena de documentación:

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

    return '\t'.join(iterable) 

if __name__ == "__main__": 
    import doctest 
    doctest.testmod() 
+0

Genial. Tal vez funcione porque no hay un carácter de tabulación en el literal de cadena que sea parte de un doctest statement. La pestaña en la respuesta literal de la cadena debe ser dejada sola. ¡Así que componer la cadena de prueba que contiene pestañas fuera de las citas heredoc y usar la notación Raw heredoc podría funcionar! – hobs

+0

¡Me gusta el truco de str.join (iterable)! – hobs

1

Debe configurar el NORMALIZE_WHITESPACE. O, alternativamente, capturar el resultado y compararlo con el valor esperado:

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

Desde la sección doctest documentación How are Docstring Examples Recognized?:

Todos los caracteres de tabulación duros se expanden a los espacios, usando la pestaña de 8 columnas paradas. Las pestañas en el resultado generado por el código probado no se modifican. Debido a que los separadores duros en la salida de la muestra son ampliado, esto significa que si la salida de código incluye pestañas duras, la única forma en que el doctest puede pasar es que si la opción NORMALIZE_WHITESPACE o directiva está en vigor. Alternativamente, la prueba puede ser reescrito para capturar la salida y compararla con un valor esperado como parte de la prueba. Este manejo de pestañas en la fuente llegó a mediante prueba y error, y ha demostrado ser el menos propenso a errores forma de manejarlos. Es posible usar un algoritmo diferente para las pestañas de manejo al escribir una clase personalizada DocTestParser.

Editar: Mi error, entendía la documentación al revés. Las fichas se están ampliando a 8 espacios, tanto en el argumento de cadena que se pasa a dedupe_whitespace y la cadena literal que se comparan en la siguiente línea, por lo output contiene:

"Black Ground" 

y está siendo comparado con:

"Black  Ground" 

No puedo encontrar una manera de superar esta limitación sin escribir tu propio DocTestParser o probando espacios deduplicados en lugar de pestañas.

+0

Ahh, no pensé en hacer la captura y comparar manualmente. Eso es exactamente lo que necesitaba. No quería usar NORMALIZE_WHITESPACE (porque estoy probando un script que modifica el espacio en blanco). – hobs

+0

Acabo de probar su cadena más doctest y falló. Probé casi todas las combinaciones de comillas dobles, comillas simples y cadenas sin formato para entrada y salida. . ... 'en __main __ dedupe_whitespace ejemplo Error: salida == 'Negro Tierra' esperado: verdadera Got: false' – hobs

+0

Tienes razón, estoy editando la respuesta. – Chewie

10

Es la notación de cadena heredoc prima (r""") que hizo el truco:

# 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() 
+0

Gracias amigo, funcionó perfectamente para mí. – colgur

0

TL; DR: Escape de la barra diagonal inversa, es decir, use \\n o \\t en lugar de \n o \t en las cadenas que de lo contrario no se modificarán;

Probablemente no desee hacer sus documentos crudos ya que no podrá usar ningún escape de cadena de Python, incluidos aquellos que desee.

Para un método que admite el uso de escapes normales, simplemente escapa de la barra invertida en el escape de barra invertida, así que después de que Python lo interprete, deja una barra invertida literal seguida del carácter que doctest puede analizar.

0

Esto es básicamente la respuesta de YatharhROCK, pero un poco más explícita. Puede usar cadenas sin formato o doble escape. ¿Pero por qué?

Necesita la cadena literal para contener un código de Python válido que, cuando se lo interpreta, es el código que desea ejecutar/probar. Estos dos trabajos:

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

El efecto del uso de cuerdas primas y el efecto de doble escape (escapar de la barra) dos hojas en la cadena de dos personajes, la barra y el n. Este código se pasa al intérprete de Python, que toma "barra oblicua luego n" para significar "carácter de nueva línea" dentro de una cadena literal.

Use el que prefiera.

Cuestiones relacionadas