# `nntplib` — Protocolo de cliente NNTP

Código fuente: Lib/nntplib.py

Obsoleto desde la versión 3.11: El módulo `nntplib` está en desuso (ver PEP 594 para más detalles).

Este módulo define la clase `NNTP` que implementa el lado del cliente del Protocolo de transferencia de noticias por red. Se puede utilizar para implementar un lector o póster de noticias, o procesadores de noticias automatizados. Es compatible con RFC 3977 así como con los antiguos RFC 977 y RFC 2980.

Availability: not Emscripten, not WASI.

Este módulo no funciona o no está disponible en las plataformas WebAssembly `wasm32-emscripten` y `wasm32-wasi`. Consulte Plataformas WebAssembly para obtener más información.

Aquí hay dos pequeños ejemplos de cómo se puede utilizar. Para enumerar algunas estadísticas sobre un grupo de noticias e imprimir los temas de los últimos 10 artículos:

    >>> s = nntplib.NNTP('news.gmane.io')
    >>> resp, count, first, last, name = s.group('gmane.comp.python.committers')
    >>> print('Group', name, 'has', count, 'articles, range', first, 'to', last)
    Group gmane.comp.python.committers has 1096 articles, range 1 to 1096
    >>> resp, overviews = s.over((last - 9, last))
    >>> for id, over in overviews:
    ...     print(id, nntplib.decode_header(over['subject']))
    ...
    1087 Re: Commit privileges for Łukasz Langa
    1088 Re: 3.2 alpha 2 freeze
    1089 Re: 3.2 alpha 2 freeze
    1090 Re: Commit privileges for Łukasz Langa
    1091 Re: Commit privileges for Łukasz Langa
    1092 Updated ssh key
    1093 Re: Updated ssh key
    1094 Re: Updated ssh key
    1095 Hello fellow committers!
    1096 Re: Hello fellow committers!
    >>> s.quit()
    '205 Bye!'

Para publicar un artículo desde un archivo binario (esto supone que el artículo tiene encabezados válidos y que tienes permitido publicar en el grupo de noticias en particular):

    >>> s = nntplib.NNTP('news.gmane.io')
    >>> f = open('article.txt', 'rb')
    >>> s.post(f)
    '240 Article posted successfully.'
    >>> s.quit()
    '205 Bye!'

El módulo en sí define las siguientes clases:

class nntplib.NNTP(host, port=119, user=None, password=None, readermode=None, usenetrc=False[, timeout])

  Retorna un nuevo objeto `NNTP` que representa una conexión con el servidor NNTP ejecutándose en el host host, escuchando en el puerto port. Se puede especificar un timeout opcional para la conexión de socket. Si se proporcionan las credenciales opcionales user y password, o si hay credenciales adecuadas en `/.netrc` y el indicador opcional usenetrc es verdadero, los comandos `AUTHINFO USER` y `AUTHINFO PASS` se utilizan para identificar y autenticar al usuario en el servidor. Si el indicador opcional readermode es verdadero, se envía un comando `mode reader` antes de que se realice la autenticación. El modo de lector a veces es necesario si se conecta a un servidor NNTP en el equipo local y tiene la intención de llamar a comandos específicos del lector, como `group`. Si obtienes un valor inesperado `NNTPPermanentError`, es posible que debas establecer readermode. La clase `NNTP` admite la instrucción `with` para consumir incondicionalmente las excepciones `OSError` y para cerrar la conexión NNTP cuando haya terminado, e.g.:

      >>> from nntplib import NNTP
      >>> with NNTP('news.gmane.io') as n:
      ...     n.group('gmane.comp.python.committers')
      ...
      ('211 1755 1 1755 gmane.comp.python.committers', 1755, 1, 1755, 'gmane.comp.python.committers')
      >>>

  Genera un evento de auditoría `nntplib.connect` con los argumentos `self`, `host`, `port`.

  Genera un evento de auditoría `nntplib.putline` con los argumentos `self`, `line`.

  Distinto en la versión 3.2: usenetrc es ahora `False` por defecto.

  Distinto en la versión 3.3: El soporte para la declaración `with` fue añadido.

  Distinto en la versión 3.9: Si el parámetro timeout se establece en cero, lanzará un `ValueError` para evitar la creación de un socket sin bloqueo.

class nntplib.NNTP_SSL(host, port=563, user=None, password=None, ssl_context=None, readermode=None, usenetrc=False[, timeout])

  Retorna un nuevo objeto `NNTP_SSL`, que representa una conexión cifrada con el servidor NNTP ejecutándose en el host host, escuchando en el puerto port. Los objetos `NNTP_SSL` tienen los mismos métodos que los objetos `NNTP`. Si se omite el port se utiliza el puerto 563 (NNTPS). ssl_context también es opcional, y también el objeto `SSLContext`. Por favor, lea Consideraciones de seguridad para conocer las buenas prácticas. Todos los demás parámetros se comportan igual que para `NNTP`.

  Tenga en cuenta que SSL-on-563 no es recomendado por RFC 4642, en favor de STARTTLS como se describe abajo. Sin embargo, algunos servidores solo admiten el primero.

  Genera un evento de auditoría `nntplib.connect` con los argumentos `self`, `host`, `port`.

  Genera un evento de auditoría `nntplib.putline` con los argumentos `self`, `line`.

  Nuevo en la versión 3.2.

  Distinto en la versión 3.4: La clase ahora admite la verificación del nombre de host con `ssl.SSLContext.check_hostname` e Indicador del nombre del servidor (SNI por sus siglas en inglés, consulte `ssl.HAS_SNI`).

  Distinto en la versión 3.9: Si el parámetro timeout se establece en cero, lanzará un `ValueError` para evitar la creación de un socket sin bloqueo.

exception nntplib.NNTPError

  Derivado de la excepción estándar `Exception`, esta es la clase base para todas las excepciones generadas por el módulo `nntplib`. Las instancias de esta clase tienen el siguiente atributo:

  response

    La respuesta del servidor, si está disponible, como un objeto `str`.

exception nntplib.NNTPReplyError

  Excepción generada cuando se recibe una respuesta inesperada del servidor.

exception nntplib.NNTPTemporaryError

  Excepción generada cuando se recibe un código de respuesta dentro del rango del 400–499.

exception nntplib.NNTPPermanentError

  Excepción generada cuando se recibe un código de respuesta dentro del rango del 500–599.

exception nntplib.NNTPProtocolError

  Excepción generada cuando se recibe una respuesta del servidor que no comienza con un dígito dentro del rango 1–5.

exception nntplib.NNTPDataError

  Excepción generada cuando hay algún error en los datos de la respuesta.

## Objetos NNTP

Cuando están conectados, los objetos `NNTP` y `NNTP_SSL` admiten los siguientes métodos y atributos.

### Atributos

NNTP.nntp_version

  Un entero que representa la versión del protocolo NNTP compatible con el servidor. En la práctica, esto debería ser `2` para los servidores que anuncian el cumplimiento RFC 3977 y `1` para otros.

  Nuevo en la versión 3.2.

NNTP.nntp_implementation

  Cadena que describe el nombre de software y la versión del servidor NNTP, o `None` si el servidor no lo anuncia.

  Nuevo en la versión 3.2.

### Métodos

La response que es retornada como el primer elemento de la tupla de retorno de casi todos los métodos es la respuesta del servidor: una cadena que comienza con un código de tres dígitos. Si la respuesta del servidor indica un error, el método genera una de las excepciones anteriores.

Muchos de los métodos siguientes toman un argumento opcional de solamente palabra clave file. Cuando se proporciona el argumento file, debe ser un file object abierto para la escritura binaria o el nombre de un archivo en disco a ser escrito. El método escribirá los datos retornados por el servidor (excepto la línea de respuesta y el punto de terminación) en el archivo; cualquier lista de líneas, tuplas u objetos que el método retorna normalmente estará vacía.

Distinto en la versión 3.2: Muchos de los siguientes métodos se han rediseñado y corregido, lo que los hace incompatibles con sus contrapartes 3.1.

NNTP.quit()

  Envía un comando `QUIT` y cierra la conexión. Una vez que se ha invocado este método, no se debe invocar ningún otro método del objeto NNTP.

NNTP.getwelcome()

  Retorna el mensaje de bienvenida enviado por el servidor en respuesta a la conexión inicial. (Este mensaje a veces contiene aclaraciones o información de ayuda que puede ser relevante para el usuario.)

NNTP.getcapabilities()

  Retorna las capacidades RFC 3977 anunciadas por el servidor, como una instancia `dict` mapeando nombres de capacidades a listas de valores (posiblemente vacías). En los servidores heredados que no entienden el comando `CAPABILITIES`, se retorna un diccionario vacío en su lugar.

      >>> s = NNTP('news.gmane.io')
      >>> 'POST' in s.getcapabilities()
      True

  Nuevo en la versión 3.2.

NNTP.login(user=None, password=None, usenetrc=True)

  Envía comandos `AUTHINFO` con el nombre de usuario y la contraseña. Si user y password son `None` y usenetrc es verdadero, se utilizarán las credenciales de `~/.netrc` si su uso es posible.

  A menos que se retrase intencionalmente, el inicio de sesión se realiza normalmente durante la inicialización del objeto `NNTP` y no es necesario invocar esta función por separado. Para forzar el retraso de la autenticación, no debes establecer user o password al crear el objeto y debes establecer usenetrc en False.

  Nuevo en la versión 3.2.

NNTP.starttls(context=None)

  Envía un comando `STARTTLS`. Esto habilitará el cifrado en la conexión NNTP. El argumento context es opcional y debe ser el objeto `ssl. SSLContext`. Por favor lea Consideraciones de seguridad para conocer las buenas prácticas.

  Tenga en cuenta que esto no se puede hacer después de que se haya transmitido la información de autenticación y la autenticación se produce de forma predeterminada, si es posible, durante la inicialización de un objeto `NNTP`. Consulte `NNTP.login()` para obtener información sobre cómo suprimir este comportamiento.

  Nuevo en la versión 3.2.

  Distinto en la versión 3.4: El método ahora admite la comprobación del nombre de host con `ssl. SSLContext.check_hostname` y Indicador del nombre del servidor (SNI por sus siglas en inglés, consulte `ssl.HAS_SNI`).

NNTP.newgroups(date, *, file=None)

  Envía un comando `NEWGROUPS`. El argumento date debe ser un objeto `datetime.date` o `datetime.datetime`. Retorna un par `(response, groups)` donde groups es una lista que representa los grupos que son nuevos desde la fecha determinada. Sin embargo, si se proporciona file, entonces groups estará vacío.

      >>> from datetime import date, timedelta
      >>> resp, groups = s.newgroups(date.today() - timedelta(days=3))
      >>> len(groups)
      85
      >>> groups[0]
      GroupInfo(group='gmane.network.tor.devel', last='4', first='1', flag='m')

NNTP.newnews(group, date, *, file=None)

  Envía un comando `NEWNEWS`. Aquí, group es un nombre de grupo o `'*'`, y date tiene el mismo significado que para `newgroups()`. Retorna un par `(response, articles)` donde articles es una lista de identificadores de mensaje.

  Este comando es inhabilitado frecuentemente por los administradores del servidor NNTP.

NNTP.list(group_pattern=None, *, file=None)

  Envía un comando `LIST` o `LIST ACTIVE`. Retorna un par `(response, list)` donde list es una lista de tuplas que representan todos los grupos disponibles desde este servidor NNTP, opcionalmente coincidiendo con el patrón de cadena group_pattern. Cada tupla tiene el formato `(group, last, first, flag)`, donde group es un nombre de grupo, last y first son los últimos y primeros números de artículo, y flag suele tomar uno de estos valores:

  - `y`: Se permiten publicaciones locales y artículos de pares.

  - `m`: El grupo está moderado y todas las publicaciones deben ser aprobadas.

  - `n`: No se permiten publicaciones locales, solo artículos de pares.

  - `j`: Los artículos de pares se archivan en el grupo de basura en su lugar.

  - `x`: No hay publicaciones locales y los artículos de pares son ignorados.

  - `=foo.bar`: Los artículos se archivan en el grupo `foo.bar` en su lugar.

  Si flag tiene otro valor, el estado del grupo de noticias debe considerarse como desconocido.

  Este comando puede retornar resultados muy grandes, especialmente si no se especifica group_pattern. Es mejor almacenar en caché los resultados sin conexión a menos que realmente necesite actualizarlos.

  Distinto en la versión 3.2: group_pattern fue añadido.

NNTP.descriptions(grouppattern)

  Envía un comando `LIST NEWSGROUPS`, donde grouppattern es una cadena comodín como se especifica en RFC 3977 (es esencialmente lo mismo que las cadenas comodín de shell DOS o UNIX). Retorna un par `(response, descriptions)`, donde descriptions es un diccionario que asigna nombres de grupos a descripciones textuales.

      >>> resp, descs = s.descriptions('gmane.comp.python.*')
      >>> len(descs)
      295
      >>> descs.popitem()
      ('gmane.comp.python.bio.general', 'BioPython discussion list (Moderated)')

NNTP.description(group)

  Obtiene una descripción para un único grupo group. Si más de un grupo coincide (si “group” es una cadena comodín real), retorna la primera coincidencia. Si ningún grupo coincide, retorna una cadena vacía.

  Esto elude el código de respuesta del servidor. Si necesita el código de respuesta, use `descriptions()`.

NNTP.group(name)

  Envía un comando `GROUP`, donde name es el nombre del grupo. El grupo se selecciona como el grupo actual, si este existe. Retorna una tupla `(response, count, first, last, name)` donde count es el número (estimado) de artículos en el grupo, first es el primer número de artículo del grupo, last es el último número de artículo en el grupo y name es el nombre del grupo.

NNTP.over(message_spec, *, file=None)

  Envía un comando `OVER` o un comando `XOVER` en servidores heredados. message_spec puede ser una cadena que represente un identificador de mensaje o una tupla de números `(first, None)` que indique un rango de artículos en el grupo actual, o una tupla `(first, None)` que indique un rango de artículos comenzando desde first hasta el último artículo del grupo actual, o `None` para seleccionar el artículo actual en el grupo actual.

  Retorna un par `(response, overviews)`. overviews es una lista de tuplas del tipo `(article_number, overview)`, una para cada artículo seleccionado por message_spec. Cada overview es un diccionario con el mismo número de elementos, pero este número depende del servidor. Estos elementos son encabezados de mensajes (la clave es entonces el nombre del encabezado en minúsculas) o elementos de metadatos (la clave es entonces el nombre de los metadatos precedido de `":"`). Se garantiza la presencia de los siguientes elementos por la especificación NNTP:

  - los encabezados `subject`, `from`, `date`, `message-id` y `references`

  - los metadatos `:bytes`: el número de bytes en todo el artículo sin procesar (incluidos los encabezados y el cuerpo)

  - los metadatos `:lines`: el número de líneas en el cuerpo del artículo

  El valor de cada elemento es una cadena o `None` si no está presente.

  Es aconsejable utilizar la función `decode_header()` en los valores del encabezado cuando pueden contener caracteres no-ASCII:

      >>> _, _, first, last, _ = s.group('gmane.comp.python.devel')
      >>> resp, overviews = s.over((last, last))
      >>> art_num, over = overviews[0]
      >>> art_num
      117216
      >>> list(over.keys())
      ['xref', 'from', ':lines', ':bytes', 'references', 'date', 'message-id', 'subject']
      >>> over['from']
      '=?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?= <martin@v.loewis.de>'
      >>> nntplib.decode_header(over['from'])
      '"Martin v. Löwis" <martin@v.loewis.de>'

  Nuevo en la versión 3.2.

NNTP.help(*, file=None)

  Envía un comando `HELP`. Retorna un par `(response, list)` donde list es una lista de cadenas de caracteres de ayuda.

NNTP.stat(message_spec=None)

  Envía un comando `STAT`, donde message_spec es un identificador de mensaje (incluido en `'<'` y `'>'`) o un número de artículo en el grupo actual. Si se omite message_spec o es `None` se considera el artículo actual del grupo actual. Retorna un triple `(response, number, id)` donde number es el número de artículo e id es el identificador del mensaje.

      >>> _, _, first, last, _ = s.group('gmane.comp.python.devel')
      >>> resp, number, message_id = s.stat(first)
      >>> number, message_id
      (9099, '<20030112190404.GE29873@epoch.metaslash.com>')

NNTP.next()

  Envía un comando `NEXT`. Retorna como para `stat()`.

NNTP.last()

  Envía un comando `LAST`. Retorna como para `stat()`.

NNTP.article(message_spec=None, *, file=None)

  Envía un comando `ARTICLE`, donde message_spec tiene el mismo significado que para `stat()`. Retorna una tupla `(response, info)` donde info es un `namedtuple` con tres atributos number, message_id y lines (en ese orden). number es el número de artículo del grupo (o 0 si la información no está disponible), message_id el identificador del mensaje como una cadena y lines una lista de líneas (sin terminar líneas nuevas) que comprende el mensaje sin procesar, incluidos los encabezados y el cuerpo.

      >>> resp, info = s.article('<20030112190404.GE29873@epoch.metaslash.com>')
      >>> info.number
      0
      >>> info.message_id
      '<20030112190404.GE29873@epoch.metaslash.com>'
      >>> len(info.lines)
      65
      >>> info.lines[0]
      b'Path: main.gmane.org!not-for-mail'
      >>> info.lines[1]
      b'From: Neal Norwitz <neal@metaslash.com>'
      >>> info.lines[-3:]
      [b'There is a patch for 2.3 as well as 2.2.', b'', b'Neal']

NNTP.head(message_spec=None, *, file=None)

  Igual que `article()`, pero envía un comando `HEAD`. Las lines retornadas (o escritas a file) solo contendrán los encabezados del mensaje, no el cuerpo.

NNTP.body(message_spec=None, *, file=None)

  Igual que `article()`, pero envía un comando `BODY`. Las lines retornadas (o escritas a file) solo contendrán los encabezados del mensaje, no el cuerpo.

NNTP.post(data)

  Publica un artículo utilizando el comando `POST`. El argumento data es un file object abierto para la lectura binaria o cualquier iterable de objetos bytes (que representa las líneas sin procesar del artículo que se va a publicar). Debe representar un artículo de noticias bien formado, incluidos los encabezados requeridos. El método `post()` escapa automáticamente las líneas que comienzan con `.` y añade la línea de terminación.

  Si el método tiene éxito, se retorna la respuesta del servidor. Si el servidor se niega a publicarlo, se genera un `NNTPReplyError`.

NNTP.ihave(message_id, data)

  Envía un comando `IHAVE`. message_id es el identificador del mensaje que se enviará al servidor (incluido entre `'<'` y `'>'`). El parámetro data y el valor de retorno son los mismos que para `post()`.

NNTP.date()

  Retorna un par `(response, date)`. date es un objeto `datetime` que contiene la fecha y hora actuales del servidor.

NNTP.slave()

  Envía un comando `SLAVE`. Retorna la response del servidor.

NNTP.set_debuglevel(level)

  Establece el nivel de depuración de la instancia. Esto controla la cantidad de salida de depuración impresa. El valor por defecto, `0`, no produce salida de depuración. Un valor de `1` produce una cantidad moderada de salida de depuración, generalmente una sola línea por solicitud o por respuesta. Un valor de `2` o superior produce la cantidad máxima de salida de depuración, registrando cada línea enviada y recibida en la conexión (incluyendo el texto del mensaje).

Las siguientes son extensiones NNTP opcionales definidas en RFC 2980. Algunas de ellas han sido reemplazados por comandos más nuevos en RFC 3977.

NNTP.xhdr(hdr, str, *, file=None)

  Envía un comando `XHDR`. El argumento hdr es una palabra clave de encabezado, por ejemplo `'subject'`. El argumento str debe tener la forma `'first-last'` donde first y last son el primer y último número de artículo para buscar. Retorna un par `(response, list)`, donde list es una lista de pares `(id, text)`, donde id es un número de artículo (como una cadena) y text es el texto del encabezado solicitado para ese artículo. Si se proporciona el parámetro file, entonces la salida del comando `XHDR` se almacena en un archivo. Si file es una cadena, entonces el método abrirá un archivo con ese nombre, que escribirá en él y luego lo cerrará. Si file es un file object, entonces comenzará invocando `write()` en él para almacenar las líneas de la salida del comando. Si se proporciona file, entonces retorna list o una lista vacía.

NNTP.xover(start, end, *, file=None)

  Envía un comando `XOVER`. start and end son números de artículo que delimitan el rango de artículos a seleccionar. El valor de retorno es el mismo que para `over()`. Se recomienda usar `over()` en su lugar, ya que se usará automáticamente el comando más nuevo `OVER` si está disponible.

## Funciones de utilidad

El módulo también define la siguiente función de utilidad:

nntplib.decode_header(header_str)

  Decodifica un valor de encabezado, eliminando los caracteres de escape que no sean ASCII. header_str debe ser un objeto `str`. Se retorna el valor sin escape. Se recomienda utilizar esta función para mostrar algunos encabezados en una forma legible por humanos:

      >>> decode_header("Some subject")
      'Some subject'
      >>> decode_header("=?ISO-8859-15?Q?D=E9buter_en_Python?=")
      'Débuter en Python'
      >>> decode_header("Re: =?UTF-8?B?cHJvYmzDqG1lIGRlIG1hdHJpY2U=?=")
      'Re: problème de matrice'