nntplib — Protocolo de cliente NNTP

Código fuente: Lib/nntplib.py


This module defines the class NNTP which implements the client side of the Network News Transfer Protocol. It can be used to implement a news reader or poster, or automated news processors. It is compatible with RFC 3977 as well as the older RFC 977 and RFC 2980.

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: If the timeout parameter is set to be zero, it will raise a ValueError to prevent the creation of a non-blocking socket.

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 Security considerations 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: If the timeout parameter is set to be zero, it will raise a ValueError to prevent the creation of a non-blocking socket.

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 Security considerations 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 devolver 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()

Devuelve 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'