nntplib — клієнт протоколу NNTP

Вихідний код: Lib/nntplib.py

Застаріло починаючи з версії 3.11: Модуль nntplib є застарілим (докладніше див. PEP 594).


Цей модуль визначає клас NNTP, який реалізує клієнтську сторону протоколу передачі мережевих новин. Він може бути використаний для реалізації програми для читання новин, плакатів або автоматизованих процесорів новин. Він сумісний із RFC 3977, а також зі старішими RFC 977 і RFC 2980.

Ось два невеликих приклади того, як це можна використовувати. Щоб навести деякі статистичні дані про групу новин і надрукувати теми останніх 10 статей:

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

Щоб опублікувати статтю з бінарного файлу (припускається, що стаття має дійсні заголовки, і ви маєте право опублікувати допис у певній групі новин):

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

Сам модуль визначає такі класи:

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

Повертає новий об’єкт NNTP, що представляє з’єднання з сервером NNTP, що працює на хості host, прослуховуючи порт port. Для з’єднання через сокет можна вказати необов’язковий тайм-аут. Якщо надано необов’язковий користувач і пароль або відповідні облікові дані присутні в /.netrc і необов’язковий прапор usenetrc має значення true, AUTHINFO USER і AUTHINFO PASS Команди використовуються для ідентифікації та автентифікації користувача на сервері. Якщо необов’язковий прапорець readermode має значення true, тоді перед виконанням автентифікації надсилається команда mode reader. Режим читання іноді необхідний, якщо ви підключаєтеся до NNTP-сервера на локальній машині та маєте намір викликати специфічні команди читача, такі як group. Якщо ви отримуєте неочікувані помилки NNTPPermanentError, можливо, потрібно встановити режим читання. Клас NNTP підтримує оператор with для безумовного використання винятків OSError і закриття з’єднання NNTP після завершення, наприклад:

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

Викликає подію аудиту nntplib.connect з аргументами self, host, port.

Викликає подію аудиту nntplib.putline з аргументами self, line.

Змінено в версії 3.2: usenetrc тепер має значення False за замовчуванням.

Змінено в версії 3.3: Додано підтримку оператора with.

Змінено в версії 3.9: Якщо параметр timeout дорівнює нулю, це викличе ValueError, щоб запобігти створенню неблокуючого сокета.

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

Повертає новий об’єкт NNTP_SSL, що представляє зашифроване з’єднання з сервером NNTP, що працює на хості host, прослуховуючи порт port. Об’єкти NNTP_SSL мають ті самі методи, що й об’єкти NNTP. Якщо порт не вказано, використовується порт 563 (NNTPS). ssl_context також є необов’язковим і є об’єктом SSLContext. Будь ласка, прочитайте Міркування безпеки, щоб дізнатися про найкращі практики. Усі інші параметри поводяться так само, як і для NNTP.

Зверніть увагу, що SSL-on-563 не рекомендується відповідно до RFC 4642 на користь STARTTLS, як описано нижче. Однак деякі сервери підтримують лише перше.

Викликає подію аудиту nntplib.connect з аргументами self, host, port.

Викликає подію аудиту nntplib.putline з аргументами self, line.

Нове в версії 3.2.

Змінено в версії 3.4: Клас тепер підтримує перевірку імені хоста за допомогою ssl.SSLContext.check_hostname і Індикація імені сервера (див. ssl.HAS_SNI).

Змінено в версії 3.9: Якщо параметр timeout дорівнює нулю, це викличе ValueError, щоб запобігти створенню неблокуючого сокета.

exception nntplib.NNTPError

Похідний від стандартного винятку Exception, це базовий клас для всіх винятків, викликаних модулем nntplib. Примірники цього класу мають наступний атрибут:

response

Відповідь сервера, якщо доступна, як об’єкт str.

exception nntplib.NNTPReplyError

Виняток виникає, коли від сервера надходить неочікувана відповідь.

exception nntplib.NNTPTemporaryError

Коли отримано код відповіді в діапазоні 400–499, виникає виняток.

exception nntplib.NNTPPermanentError

Коли отримано код відповіді в діапазоні 500–599, виникає виняток.

exception nntplib.NNTPProtocolError

Виняток виникає, коли від сервера отримано відповідь, яка не починається з цифри в діапазоні 1–5.

exception nntplib.NNTPDataError

Виняток виникає, коли є помилка в даних відповіді.

Об’єкти NNTP

При підключенні об’єкти NNTP і NNTP_SSL підтримують наступні методи та атрибути.

Атрибути

NNTP.nntp_version

Ціле число, що представляє версію протоколу NNTP, яку підтримує сервер. На практиці це має бути 2 для серверів, що рекламують відповідність RFC 3977, і 1 для інших.

Нове в версії 3.2.

NNTP.nntp_implementation

Рядок, що описує назву програмного забезпечення та версію NNTP-сервера, або None, якщо сервер не повідомляє про це.

Нове в версії 3.2.

методи

Відповідь, яка повертається як перший елемент у кортежі повернення майже всіх методів, є відповіддю сервера: рядок, що починається з тризначного коду. Якщо відповідь сервера вказує на помилку, метод викликає одне з наведених вище винятків.

Багато з наведених нижче методів приймають необов’язковий аргумент файл, що містить лише ключове слово. Якщо надається аргумент file, це має бути або file object, відкритий для двійкового запису, або ім’я файлу на диску, у який потрібно записати. Потім метод записуватиме будь-які дані, повернуті сервером (за винятком рядка відповіді та кінцевої точки), у файл; будь-який список рядків, кортежів або об’єктів, які зазвичай повертає метод, буде порожнім.

Змінено в версії 3.2: Багато з наведених нижче методів було перероблено та виправлено, що робить їх несумісними з аналогами 3.1.

NNTP.quit()

Надішліть команду QUIT і закрийте з’єднання. Після виклику цього методу не слід викликати інші методи об’єкта NNTP.

NNTP.getwelcome()

Повернути вітальне повідомлення, надіслане сервером у відповідь на початкове підключення. (Це повідомлення іноді містить застереження або довідкову інформацію, яка може бути актуальною для користувача.)

NNTP.getcapabilities()

Повертає можливості RFC 3977, оголошені сервером, як екземпляр dict, який зіставляє імена можливостей із (можливо, порожніми) списками значень. На застарілих серверах, які не розуміють команду CAPABILITIES, замість неї повертається порожній словник.

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

Нове в версії 3.2.

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

Надсилайте команди AUTHINFO з іменем користувача та паролем. Якщо user і password мають значення None і usenetrc має значення true, облікові дані з ~/.netrc використовуватимуться, якщо це можливо.

Якщо не навмисно відкладено, вхід зазвичай виконується під час ініціалізації об’єкта NNTP, тому окремий виклик цієї функції непотрібний. Щоб примусово відкласти автентифікацію, ви не повинні встановлювати користувача або пароль під час створення об’єкта та повинні встановити для usenetrc значення False.

Нове в версії 3.2.

NNTP.starttls(context=None)

Надішліть команду STARTTLS. Це дозволить шифрувати підключення NNTP. Аргумент context є необов’язковим і має бути об’єктом ssl.SSLContext. Будь ласка, прочитайте Міркування безпеки, щоб дізнатися про найкращі практики.

Зауважте, що це не можна зробити після передачі інформації про автентифікацію, і автентифікація відбувається за замовчуванням, якщо це можливо під час ініціалізації об’єкта NNTP. Перегляньте NNTP.login() для отримання інформації про придушення такої поведінки.

Нове в версії 3.2.

Змінено в версії 3.4: Тепер цей метод підтримує перевірку імені хоста за допомогою ssl.SSLContext.check_hostname і Індикація імені сервера (див. ssl.HAS_SNI).

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

Надішліть команду NEWGROUPS. Аргумент date має бути об’єктом datetime.date або datetime.datetime. Повертає пару (відповідь, групи), де групи — це список, що представляє групи, які були новими з указаної дати. Однак, якщо вказано файл, групи будуть порожніми.

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

Надіслати команду НОВИНА. Тут group — це назва групи або '*', а date має те саме значення, що й для newgroups(). Повертає пару «(відповідь, статті)», де статті — це список ідентифікаторів повідомлень.

Цю команду часто вимикають адміністратори NNTP-сервера.

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

Надішліть команду СПИСОК або СПИСОК АКТИВНИХ. Повертає пару «(відповідь, список)», де list — це список кортежів, що представляють усі групи, доступні з цього NNTP-сервера, необов’язково відповідаючи рядку шаблону group_pattern. Кожен кортеж має форму (group, last, first, flag), де group — це ім’я групи, last і first — останній і перший номери статей, а flag зазвичай займає один цих значень:

  • y: дозволені локальні публікації та статті від однолітків.

  • m: Група модерується, і всі публікації мають бути затверджені.

  • n: заборонені локальні публікації, лише статті від аналогів.

  • j: Статті від аналогів натомість зберігаються в групі сміття.

  • x: жодних локальних повідомлень, а статті від аналогів ігноруються.

  • =foo.bar: натомість статті зберігаються в групі foo.bar.

Якщо flag має інше значення, то статус групи новин слід вважати невідомим.

Ця команда може повернути дуже великі результати, особливо якщо group_pattern не вказано. Найкраще кешувати результати в автономному режимі, якщо вам дійсно не потрібно їх оновити.

Змінено в версії 3.2: Додано group_pattern.

NNTP.descriptions(grouppattern)

Надішліть команду LIST NEWSGROUPS, де grouppattern — рядок wildmat, як зазначено в RFC 3977 (це по суті те саме, що рядки символів узагальнення оболонки DOS або UNIX). Повертає пару (відповідь, описи), де описи — це словник, що зіставляє імена груп із текстовими описами.

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

Отримайте опис для однієї групи group. Якщо збігається більше ніж одна група (якщо „group“ є справжнім рядком wildmat), поверніть перший збіг. Якщо жодна група не відповідає, поверніть порожній рядок.

Це видаляє код відповіді з сервера. Якщо потрібен код відповіді, використовуйте descriptions().

NNTP.group(name)

Надішліть команду GROUP, де name – це назва групи. Групу вибрано як поточну, якщо вона існує. Повертає кортеж «(відповідь, кількість, ім’я, прізвище, ім’я)», де кількість — це (приблизна) кількість статей у групі, перша — номер першої статті в групі, остання — останній номер статті в групі, а ім’я — це назва групи.

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

Надішліть команду OVER або команду XOVER на застарілих серверах. message_spec може бути або рядком, що представляє ідентифікатор повідомлення, або кортежем (first, last) чисел, що вказує на діапазон статей у поточній групі, або (first, None) кортеж, що вказує діапазон статей, починаючи від першої до останньої статті в поточній групі, або None, щоб вибрати поточну статтю в поточній групі.

Повернути пару (відповідь, огляди). Огляди — це список кортежів (номер_статті, огляд), по одному для кожної статті, вибраної специфікацією_повідомлення. Кожен огляд є словником з однаковою кількістю елементів, але ця кількість залежить від сервера. Ці елементи є або заголовками повідомлень (ключ — це ім’я заголовка в нижньому регістрі), або елементи метаданих (ключ — це ім’я метаданих, перед яким додається ":"). Специфікація NNTP гарантує наявність таких елементів:

  • заголовки subject, from, date, message-id і references

  • метадані :bytes: кількість байтів у всій необробленій статті (включаючи заголовки та тіло)

  • метадані :lines: кількість рядків у тілі статті

Значення кожного елемента є або рядком, або None, якщо його немає.

Рекомендовано використовувати функцію decode_header() для значень заголовків, якщо вони можуть містити символи, відмінні від 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>'

Нове в версії 3.2.

NNTP.help(*, file=None)

Надішліть команду HELP. Повертає пару (відповідь, список), де список — це список довідкових рядків.

NNTP.stat(message_spec=None)

Надішліть команду STAT, де message_spec є або ідентифікатором повідомлення (включеним у ' <' and '> ''), або номером статті в поточній групі. Якщо message_spec опущено або None, розглядається поточна стаття в поточній групі. Повертає трійку (відповідь, номер, ідентифікатор), де номер — номер статті, а id — ідентифікатор повідомлення.

>>> _, _, 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()

Надішліть команду ДАЛІ. Повернути як для stat().

NNTP.last()

Надіслати команду LAST. Повернути як для stat().

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

Надішліть команду ARTICLE, де message_spec має те саме значення, що й для stat(). Повертає кортеж (відповідь, інформація), де info є namedtuple з трьома атрибутами number, message_id і lines (у такому порядку). number — це номер статті в групі (або 0, якщо інформація недоступна), message_id — ідентифікатор повідомлення у вигляді рядка, а lines — список рядків (без символів нового рядка), що містять необроблене повідомлення, включаючи заголовки і тіло.

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

Те саме, що article(), але надсилає команду HEAD. Повернуті рядки (або записані у файл) міститимуть лише заголовки повідомлень, а не тіло.

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

Те саме, що article(), але надсилає команду BODY. Повернуті рядки (або записані у файл) міститимуть лише тіло повідомлення, а не заголовки.

NNTP.post(data)

Опублікуйте статтю за допомогою команди POST. Аргумент data є або file object, відкритим для двійкового читання, або будь-яким ітерованим об’єктом байтів (що представляє необроблені рядки статті, яка буде опублікована). Він має представляти добре сформовану новинну статтю, включаючи необхідні заголовки. Метод post() автоматично екранує рядки, що починаються з ., і додає кінцевий рядок.

Якщо метод завершується успішно, повертається відповідь сервера. Якщо сервер відмовляється надсилати повідомлення, виникає NNTPReplyError.

NNTP.ihave(message_id, data)

Надішліть команду IHAVE. message_id — це ідентифікатор повідомлення, яке потрібно надіслати на сервер (включено в '<' and '>'). Параметр data і значення, що повертається, такі ж, як і для post().

NNTP.date()

Повертає пару (відповідь, дата). date — це об’єкт datetime, що містить поточну дату й час сервера.

NNTP.slave()

Надішліть команду SLAVE. Повернути відповідь сервера.

NNTP.set_debuglevel(level)

Установіть рівень налагодження примірника. Це контролює кількість надрукованих виводів налагодження. Значення за замовчуванням, 0, не створює вихідних даних для налагодження. Значення 1 дає помірну кількість вихідних даних налагодження, як правило, один рядок на запит або відповідь. Значення 2 або вище створює максимальну кількість вихідних даних налагодження, реєструючи кожен рядок, надісланий і отриманий під час з’єднання (включаючи текст повідомлення).

Нижче наведено додаткові розширення NNTP, визначені в RFC 2980. Деякі з них були замінені новішими командами в RFC 3977.

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

Надішліть команду XHDR. Аргумент hdr є ключовим словом заголовка, наприклад. 'тема''. Аргумент str повинен мати форму 'перший-останній', де перший і останній є першим і останнім номерами статей для пошуку. Повертає пару (відповідь, список), де list — це список пар (id, text), де id — номер статті (у вигляді рядка), а text — це текст запитуваного заголовка для цієї статті. Якщо вказано параметр file, вихідні дані команди XHDR зберігаються у файлі. Якщо file є рядком, тоді метод відкриє файл із такою назвою, запише в нього та закриє. Якщо file є file object, тоді він почне викликати write() для збереження рядків виведення команди. Якщо надано файл, то повернутий список є порожнім списком.

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

Надішліть команду XOVER. початок і кінець — це номери статей, які розмежовують діапазон статей для вибору. Значення, що повертається, таке ж, як і для over(). Натомість рекомендується використовувати over(), оскільки вона автоматично використовуватиме новішу команду OVER, якщо вона доступна.

Функції корисності

Модуль також визначає таку службову функцію:

nntplib.decode_header(header_str)

Декодуйте значення заголовка, видаляючи екрановані символи, які не є ASCII. header_str має бути об’єктом str. Повертається неекрановане значення. Рекомендується використовувати цю функцію для відображення деяких заголовків у зрозумілій людині формі:

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