"pprint" --- Impresión bonita de datos
**************************************

**Código fuente:** Lib/pprint.py

======================================================================

El módulo "pprint" proporciona la capacidad de "imprimir de forma
bonita" estructuras de datos arbitrarias de Python de manera que se
puede utilizar como entrada para el intérprete. Si las estructuras
formateadas incluyen objetos que no son tipos fundamentales de Python,
es posible que la representación no sea válida como tal para el
intérprete. Esto puede darse si se incluyen objetos como archivos,
sockets o clases, así como muchos otros objetos que no se pueden
representar como literales de Python.

La representación formateada mantiene los objetos en una sola línea
siempre que sea posible y los divide en varias líneas si no encajan
dentro del ancho permitido. Se deben crear objetos "PrettyPrinter" de
forma explícita si se necesita ajustar la restricción de ancho.

Los diccionarios se ordenan por clave antes de que se calcule la
representación en pantalla.

El módulo "pprint" define una sola clase:

class pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, compact=False, sort_dicts=True)

   Construye una instancia de "PrettyPrinter".  Este constructor
   acepta varios argumento por palabra clave.  Se puede establecer un
   flujo de salida usando la palabra clave *stream*; el único método
   utilizado en el objeto *stream* es el método "write()" del
   protocolo de archivo.  Si no se especifica, "PrettyPrinter" adopta
   "sys.stdout" por defecto.  La cantidad de sangría agregada para
   cada nivel recursivo se especifica mediante *indent*; por defecto
   es uno.  Otros valores pueden hacer que la salida se vea un poco
   extraña, pero pueden hacer más fácil la visualización de los
   anidamientos. El número de niveles que se pueden mostrar se
   controla mediante *depth*; si la estructura de datos que se muestra
   es demasiado profunda, el siguiente nivel contenido se reemplaza
   por "...".  De forma predeterminada, no hay restricciones en la
   profundidad de los objetos que se formatean. El ancho de salida
   deseado se restringe mediante el parámetro *width*; el valor
   predeterminado es 80 caracteres.  Si no se puede formatear una
   estructura dentro del límite de ancho establecido, se ajustará lo
   mejor posible. Si *compact* es *False* (el valor por defecto), cada
   elemento de una secuencia larga se formateará en una línea
   separada.  Si *compact* es *True*, en cada linea de salida se
   formatearán todos los elementos que quepan dentro del ancho
   definido. Si *sort_dicts* es *True* (el valor por defecto), los
   diccionarios se formatearán con sus claves ordenadas; de lo
   contrario, se mostrarán según orden de inserción.

   Distinto en la versión 3.4: Añadido el argumento *compact*.

   Distinto en la versión 3.8: Añadido el argumento *sort_dicts*.

   >>> import pprint
   >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
   >>> stuff.insert(0, stuff[:])
   >>> pp = pprint.PrettyPrinter(indent=4)
   >>> pp.pprint(stuff)
   [   ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
       'spam',
       'eggs',
       'lumberjack',
       'knights',
       'ni']
   >>> pp = pprint.PrettyPrinter(width=41, compact=True)
   >>> pp.pprint(stuff)
   [['spam', 'eggs', 'lumberjack',
     'knights', 'ni'],
    'spam', 'eggs', 'lumberjack', 'knights',
    'ni']
   >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
   ... ('parrot', ('fresh fruit',))))))))
   >>> pp = pprint.PrettyPrinter(depth=6)
   >>> pp.pprint(tup)
   ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))

El módulo "pprint" también proporciona varias funciones de atajo:

pprint.pformat(object, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True)

   Retorna la representación formateada de *object* como una cadena de
   caracteres. *indent*, *width*, *depth*, *compact* y *sort_dicts* se
   pasarán al constructor de "PrettyPrinter" como parámetros de
   formato.

   Distinto en la versión 3.4: Añadido el argumento *compact*.

   Distinto en la versión 3.8: Añadido el argumento *sort_dicts*.

pprint.pp(object, *args, sort_dicts=False, **kwargs)

   Imprime la representación formateada de *object* seguida de una
   nueva línea. Si *sort_dicts* es *False* (el valor por defecto), los
   diccionarios se mostrarán con sus claves según orden de inserción,
   de lo contrario, las claves del diccionario serán ordenadas. *args*
   y *kwargs* se pasarán a "pprint()" como parámetros de formato.

   Nuevo en la versión 3.8.

pprint.pprint(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True)

   Imprime la representación formateada de *object* en *stream*,
   seguida de una nueva línea. Si *stream* es "None", se usa
   "sys.stdout". Esta función se puede usar en el intérprete
   interactivo en lugar de la función "print()" para inspeccionar
   valores (incluso puedes reasignar "print = pprint.pprint" para su
   uso dentro del ámbito). *indent*, *width*, *depth*, *compact* y
   *sort_dicts* se pasarán al constructor de "PrettyPrinter" como
   parámetros de formato.

   Distinto en la versión 3.4: Añadido el argumento *compact*.

   Distinto en la versión 3.8: Añadido el argumento *sort_dicts*.

   >>> import pprint
   >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
   >>> stuff.insert(0, stuff)
   >>> pprint.pprint(stuff)
   [<Recursion on list with id=...>,
    'spam',
    'eggs',
    'lumberjack',
    'knights',
    'ni']

pprint.isreadable(object)

   Determina si la representación formateada de *object* es "legible"
   o si puede usarse para reconstruir el objeto usando "eval()".
   Siempre retorna "False" para objetos recursivos.

   >>> pprint.isreadable(stuff)
   False

pprint.isrecursive(object)

   Determina si *object* requiere una representación recursiva.

Una función extra de soporte es también definida:

pprint.saferepr(object)

   Retorna una representación en forma de cadena de caracteres de
   *object*, que está protegida contra estructuras de datos
   recursivas. Si la representación de *object* presenta una entrada
   recursiva, dicha referencia recursiva se representará como
   "<Recursion on typename with id=number>". Además, la representación
   no tendrá otro formato.

   >>> pprint.saferepr(stuff)
   "[<Recursion on list with id=...>, 'spam', 'eggs', 'lumberjack', 'knights', 'ni']"


Objetos *PrettyPrinter*
=======================

Las instancias de "PrettyPrinter" tienen los siguientes métodos:

PrettyPrinter.pformat(object)

   Retorna la representación formateada de *object*.  Tiene en cuenta
   las opciones pasadas al constructor de la clase "PrettyPrinter".

PrettyPrinter.pprint(object)

   Imprime la representación formateada de *object* en la secuencia
   configurada, seguida de una nueva línea.

Los siguientes métodos proporcionan las implementaciones para las
funciones correspondientes con los mismos nombres. Usar estos métodos
en una instancia es algo más eficiente, ya que no es necesario crear
nuevos objetos "PrettyPrinter".

PrettyPrinter.isreadable(object)

   Determina si la representación formateada de *object* es "legible"
   o si se puede usar para reconstruir su valor usando "eval()". Se
   debe tener en cuenta que se retorna "False" para objetos
   recursivos. Si el parámetro *depth* de "PrettyPrinter" es
   proporcionado y el objeto es más profundo de lo permitido, también
   se retorna "False".

PrettyPrinter.isrecursive(object)

   Determina si *object* requiere una representación recursiva.

Este método se proporciona como un punto de entrada o método de enlace
automático (*hook* en inglés) para permitir que las subclases
modifiquen la forma en que los objetos se convierten en cadenas de
caracteres. La implementación por defecto utiliza la implementación
interna de "saferepr()".

PrettyPrinter.format(object, context, maxlevels, level)

   Retorna tres valores: la versión formateada de *object* como una
   cadena de caracteres, una bandera que indica si el resultado es
   legible y una bandera que indica si se detectó recursividad. El
   primer argumento es el objeto a representar. El segundo es un
   diccionario que contiene la "id()" de los objetos que son parte del
   contexto de representación actual (contenedores directos e
   indirectos para *object* que están afectando a la representación),
   como las claves; si es necesario representar un objeto que ya está
   representado en *context*, el tercer valor de retorno será "True".
   Las llamadas recursivas al método "format()" deben agregar entradas
   adicionales a los contenedores de este diccionario. El tercer
   argumento, *maxlevels*, proporciona el límite máximo de
   recursividad; su valor por defecto es "0". Este argumento debe
   pasarse sin modificaciones a las llamadas recursivas. El cuarto
   argumento, *level*, da el nivel actual; las llamadas recursivas
   sucesivas deben pasar un valor menor que el de la llamada actual.


Ejemplo
=======

Para demostrar varios usos de la función "pprint()" y sus parámetros,
busquemos información sobre un proyecto en PyPI:

   >>> import json
   >>> import pprint
   >>> from urllib.request import urlopen
   >>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp:
   ...     project_info = json.load(resp)['info']

En su forma básica, la función "pprint()" muestra el objeto completo:

   >>> pprint.pprint(project_info)
   {'author': 'The Python Packaging Authority',
    'author_email': 'pypa-dev@googlegroups.com',
    'bugtrack_url': None,
    'classifiers': ['Development Status :: 3 - Alpha',
                    'Intended Audience :: Developers',
                    'License :: OSI Approved :: MIT License',
                    'Programming Language :: Python :: 2',
                    'Programming Language :: Python :: 2.6',
                    'Programming Language :: Python :: 2.7',
                    'Programming Language :: Python :: 3',
                    'Programming Language :: Python :: 3.2',
                    'Programming Language :: Python :: 3.3',
                    'Programming Language :: Python :: 3.4',
                    'Topic :: Software Development :: Build Tools'],
    'description': 'A sample Python project\n'
                   '=======================\n'
                   '\n'
                   'This is the description file for the project.\n'
                   '\n'
                   'The file should use UTF-8 encoding and be written using '
                   'ReStructured Text. It\n'
                   'will be used to generate the project webpage on PyPI, and '
                   'should be written for\n'
                   'that purpose.\n'
                   '\n'
                   'Typical contents for this file would include an overview of '
                   'the project, basic\n'
                   'usage examples, etc. Generally, including the project '
                   'changelog in here is not\n'
                   'a good idea, although a simple "What\'s New" section for the '
                   'most recent version\n'
                   'may be appropriate.',
    'description_content_type': None,
    'docs_url': None,
    'download_url': 'UNKNOWN',
    'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1},
    'home_page': 'https://github.com/pypa/sampleproject',
    'keywords': 'sample setuptools development',
    'license': 'MIT',
    'maintainer': None,
    'maintainer_email': None,
    'name': 'sampleproject',
    'package_url': 'https://pypi.org/project/sampleproject/',
    'platform': 'UNKNOWN',
    'project_url': 'https://pypi.org/project/sampleproject/',
    'project_urls': {'Download': 'UNKNOWN',
                     'Homepage': 'https://github.com/pypa/sampleproject'},
    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
    'requires_dist': None,
    'requires_python': None,
    'summary': 'A sample Python project',
    'version': '1.2.0'}

El resultado puede limitarse a una cierta profundidad asignando un
valor al argumento *depth* ("..." se utiliza para contenidos más
"profundos"):

   >>> pprint.pprint(project_info, depth=1)
   {'author': 'The Python Packaging Authority',
    'author_email': 'pypa-dev@googlegroups.com',
    'bugtrack_url': None,
    'classifiers': [...],
    'description': 'A sample Python project\n'
                   '=======================\n'
                   '\n'
                   'This is the description file for the project.\n'
                   '\n'
                   'The file should use UTF-8 encoding and be written using '
                   'ReStructured Text. It\n'
                   'will be used to generate the project webpage on PyPI, and '
                   'should be written for\n'
                   'that purpose.\n'
                   '\n'
                   'Typical contents for this file would include an overview of '
                   'the project, basic\n'
                   'usage examples, etc. Generally, including the project '
                   'changelog in here is not\n'
                   'a good idea, although a simple "What\'s New" section for the '
                   'most recent version\n'
                   'may be appropriate.',
    'description_content_type': None,
    'docs_url': None,
    'download_url': 'UNKNOWN',
    'downloads': {...},
    'home_page': 'https://github.com/pypa/sampleproject',
    'keywords': 'sample setuptools development',
    'license': 'MIT',
    'maintainer': None,
    'maintainer_email': None,
    'name': 'sampleproject',
    'package_url': 'https://pypi.org/project/sampleproject/',
    'platform': 'UNKNOWN',
    'project_url': 'https://pypi.org/project/sampleproject/',
    'project_urls': {...},
    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
    'requires_dist': None,
    'requires_python': None,
    'summary': 'A sample Python project',
    'version': '1.2.0'}

Además, se puede establecer un valor máximo de caracteres por línea
asignando un valor al parámetro *width*. Si un objeto largo no se
puede dividir, el valor dado al ancho se anulará y será excedido:

   >>> pprint.pprint(project_info, depth=1, width=60)
   {'author': 'The Python Packaging Authority',
    'author_email': 'pypa-dev@googlegroups.com',
    'bugtrack_url': None,
    'classifiers': [...],
    'description': 'A sample Python project\n'
                   '=======================\n'
                   '\n'
                   'This is the description file for the '
                   'project.\n'
                   '\n'
                   'The file should use UTF-8 encoding and be '
                   'written using ReStructured Text. It\n'
                   'will be used to generate the project '
                   'webpage on PyPI, and should be written '
                   'for\n'
                   'that purpose.\n'
                   '\n'
                   'Typical contents for this file would '
                   'include an overview of the project, '
                   'basic\n'
                   'usage examples, etc. Generally, including '
                   'the project changelog in here is not\n'
                   'a good idea, although a simple "What\'s '
                   'New" section for the most recent version\n'
                   'may be appropriate.',
    'description_content_type': None,
    'docs_url': None,
    'download_url': 'UNKNOWN',
    'downloads': {...},
    'home_page': 'https://github.com/pypa/sampleproject',
    'keywords': 'sample setuptools development',
    'license': 'MIT',
    'maintainer': None,
    'maintainer_email': None,
    'name': 'sampleproject',
    'package_url': 'https://pypi.org/project/sampleproject/',
    'platform': 'UNKNOWN',
    'project_url': 'https://pypi.org/project/sampleproject/',
    'project_urls': {...},
    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
    'requires_dist': None,
    'requires_python': None,
    'summary': 'A sample Python project',
    'version': '1.2.0'}
