# `nntplib` — NNTP 프로토콜 클라이언트

소스 코드: Lib/nntplib.py

버전 3.11부터 폐지: The `nntplib` module is deprecated (see PEP 594 for details).

이 모듈은 네트워크 뉴스 전송 프로토콜(Network News Transfer Protocol)의 클라이언트 측을 구현하는 클래스 `NNTP`를 정의합니다. 뉴스 리더나 포스터 또는 자동화된 뉴스 프로세서를 구현하는 데 사용할 수 있습니다. 이전 RFC 977과 RFC 2980뿐만 아니라 RFC 3977과 호환됩니다.

다음은 사용 방법에 대한 두 가지 작은 예입니다. 뉴스 그룹에 대한 일부 통계를 나열하고 최근 10개 기사의 제목(subject)을 인쇄하려면 이렇게 합니다:

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

  port 포트에서 리스닝하면서 호스트 host에서 실행 중인 NNTP 서버에 대한 연결을 나타내는 새 `NNTP` 객체를 반환합니다. 소켓 연결에 대한 선택적 timeout을 지정할 수 있습니다. 선택적 user와 password가 제공되거나, `/.netrc`에 적합한 자격 증명이 존재하고 선택적 플래그 usenetrc가 참이면, `AUTHINFO USER`와 `AUTHINFO PASS` 명령이 서버에 사용자를 식별하고 인증하는 데 사용됩니다. 선택적 플래그 readermode가 참이면, 인증이 수행되기 전에 `mode reader` 명령이 전송됩니다. 로컬 시스템의 NNTP 서버에 연결하고 `group`과 같은 리더 특정 명령을 호출하려면 때때로 리더 모드가 필요합니다. 예기치 않은 `NNTPPermanentError` 가 발생하면, readermode를 설정해야 합니다. `NNTP` 클래스는 `OSError` 예외를 조건 없이 소비하고 완료 시 NNTP 연결을 닫는 `with` 문을 지원합니다. 예를 들면:

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

  인자 `self`, `host`, `port`로 감사 이벤트 `nntplib.connect`를 발생시킵니다.

  인자 `self`, `line`으로 감사 이벤트 `nntplib.putline`을 발생시킵니다.

  버전 3.2에서 변경: usenetrc는 이제 기본적으로 `False`입니다.

  버전 3.3에서 변경: `with` 문에 대한 지원이 추가되었습니다.

  버전 3.9에서 변경: timeout 매개 변수가 0으로 설정되면, 비 블로킹 소켓이 만들어지지 않도록 `ValueError`가 발생합니다.

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

  port 포트에서 리스닝하면서 host 호스트에서 실행 중인 NNTP 서버에 대한 암호화 된 연결을 나타내는 새 `NNTP_SSL` 객체를 반환합니다. `NNTP_SSL` 객체는 `NNTP` 객체와 같은 메서드를 갖습니다. port를 생략하면, 포트 563(NNTPS)이 사용됩니다. ssl_context도 선택적이며, `SSLContext` 객체입니다. 모범 사례를 보려면 보안 고려 사항을 읽으십시오. 다른 모든 매개 변수는 `NNTP`와 같게 작동합니다.

  SSL-on-563은 RFC 4642에 따라 권장되지 않고, 아래 설명된 STARTTLS로 대체합니다. 그러나, 일부 서버는 전자만 지원합니다.

  인자 `self`, `host`, `port`로 감사 이벤트 `nntplib.connect`를 발생시킵니다.

  인자 `self`, `line`으로 감사 이벤트 `nntplib.putline`을 발생시킵니다.

  버전 3.2에 추가.

  버전 3.4에서 변경: 이 클래스는 이제 `ssl.SSLContext.check_hostname`과 서버 이름 표시(Server Name Indication)(`ssl.HAS_SNI`를 참조하십시오)로 호스트명 확인을 지원합니다.

  버전 3.9에서 변경: timeout 매개 변수가 0으로 설정되면, 비 블로킹 소켓이 만들어지지 않도록 `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 프로토콜 버전을 나타내는 정수. 실제로, RFC 3977 준수를 광고하는 서버의 경우 `2`이고 다른 서버의 경우 `1`이어야 합니다.

  버전 3.2에 추가.

`NNTP.``nntp_implementation`

  NNTP 서버의 소프트웨어 이름과 버전을 기술하는 문자열, 또는 서버가 알리지 않으면 `None`.

  버전 3.2에 추가.

### 메서드

거의 모든 메서드의 반환 튜플에서 첫 번째 항목으로 반환되는 response는 서버의 응답입니다: 3 자리 숫자 코드로 시작하는 문자열. 서버의 응답이 에러를 가리키면, 메서드는 위의 예외 중 하나를 발생시킵니다.

다음 메서드 중 다수는 선택적 키워드 전용 인자 file을 취합니다. file 인자가 제공될 때, 바이너리 쓰기를 위해 열린 파일 객체이거나, 기록될 디스크에 있는 파일의 이름이어야 합니다. 그러면 메서드는 서버가 반환한 모든 데이터를 (응답 줄과 종료 점을 제외하고) 파일에 기록합니다; 메서드가 일반적으로 반환하는 줄, 튜플 또는 객체의 리스트는 비어 있습니다.

버전 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가 참이면 가능한 경우 `~/.netrc`의 자격 증명이 사용됩니다.

  의도적으로 지연되지 않는 한, 일반적으로 `NNTP` 객체 초기화 중에 로그인이 수행되며 별도로 이 함수를 호출할 필요가 없습니다. 인증을 강제로 지연시키려면, 객체를 만들 때 user나 password를 설정하지 말고, usenetrc를 False로 설정해야 합니다.

  버전 3.2에 추가.

`NNTP.``starttls`(context=None)

  `STARTTLS` 명령을 보냅니다. 이것은 NNTP 연결에서 암호화를 활성화합니다. context 인자는 선택적이며 `ssl.SSLContext` 객체여야 합니다. 모범 사례를 보려면 보안 고려 사항을 읽으십시오.

  인증 정보가 전송된 후에는 이 작업이 수행되지 않을 수 있으며, `NNTP` 객체 초기화 중에 가능한 경우 기본적으로 인증이 수행됩니다. 이 동작을 억제하는 것에 대한 정보는 `NNTP.login()`을 참조하십시오.

  버전 3.2에 추가.

  버전 3.4에서 변경: 이 메서드는 이제 `ssl.SSLContext.check_hostname`과 서버 이름 표시(Server Name Indication)(`ssl.HAS_SNI`를 참조하십시오)로 호스트명 확인을 지원합니다.

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

  `NEWGROUPS` 명령을 보냅니다. date 인자는 `datetime.date`나 `datetime.datetime` 객체여야 합니다. `(response, groups)` 쌍을 반환합니다. 여기서 groups는 지정된 date 이후의 새로운 그룹을 나타내는 리스트입니다. 그러나 file이 제공되면, groups는 비어 있습니다.

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

  `NEWNEWS` 명령을 보냅니다. 여기서 group은 그룹 이름이나 `'*'`이며, date는 `newgroups()`에서와 같은 의미입니다. `(response, articles)` 쌍을 반환합니다. 여기서 articles는 메시지 id의 리스트입니다.

  이 명령은 NNTP 서버 관리자가 자주 비활성화합니다.

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

  `LIST`나 `LIST ACTIVE` 명령을 전송합니다. 쌍 `(response, list)`를 반환합니다. 여기서 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)

  grouppattern이 RFC 3977에 지정된 와일드 매트(wildmat) 문자열(DOS나 UNIX 셸 와일드카드 문자열과 본질적으로 동일합니다)인, `LIST NEWSGROUPS` 명령을 전송합니다. `(response, descriptions)` 쌍을 반환합니다. 여기서 descriptions는 그룹 이름을 텍스트 설명에 매핑하는 딕셔너리입니다.

      >>> 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’이 실제 와일드 매트 문자열이면), 첫 번째 일치를 반환합니다. 일치하는 그룹이 없으면, 빈 문자열을 반환합니다.

  이것은 서버에서 온 응답 코드를 제거합니다. 응답 코드가 필요하면, `descriptions()`를 사용하십시오.

`NNTP.``group`(name)

  `GROUP` 명령을 전송합니다. 여기서 name은 그룹 이름입니다. 존재하면, 그룹이 현재 그룹으로 선택됩니다. 튜플 `(response, count, first, last, name)`을 반환합니다. 여기서 count는 그룹의 (추정된) 기사 수, first는 그룹의 첫 번째 기사 번호, last는 그룹의 마지막 기사 번호, name은 그룹 이름입니다.

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

  `OVER` 명령이나 레거시 서버에서는 `XOVER` 명령을 보냅니다. message_spec은 메시지 id를 나타내는 문자열이거나, 현재 그룹의 기사 범위를 나타내는 `(first, last)` 튜플, 또는 현재 그룹의 first에서 마지막 기사까지의 기사 범위를 나타내는 `(first, None)` 튜플이거나, 또는 현재 그룹에서 현재 기사를 선택하는 `None`입니다.

  쌍 `(response, overviews)`를 반환합니다. overviews는 message_spec으로 선택한 기사마다 하나씩 `(article_number, overview)` 튜플의 리스트입니다. 각 overview는 같은 수의 항목을 가진 딕셔너리이지만, 이 숫자는 서버에 따라 다릅니다. 이러한 항목은 메시지 헤더(키는 소문자 헤더 이름이 됩니다)나 메타 데이터 항목(키는 `":"`이 앞에 붙은 메타 데이터 이름이 됩니다)입니다. 다음 항목은 NNTP 명세에 따라 제공됨이 보장됩니다:

  - `subject`, `from`, `date`, `message-id` 및 `references` 헤더

  - `:bytes` 메타 데이터: 전체 원본 아티클의 바이트 수 (헤더와 본문을 포함합니다)

  - `:lines` 메타 데이터: 기사 본문의 줄 수

  각 항목의 값은 문자열이거나, 존재하지 않으면 `None`입니다.

  비 ASCII 문자를 포함할 수 있는 헤더 값에 `decode_header()` 함수를 사용하는 것이 좋습니다:

      >>> _, _, 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` 명령을 보냅니다. list가 도움말 문자열의 리스트인 `(response, list)` 쌍을 반환합니다.

`NNTP.``stat`(message_spec=None)

  `STAT` 명령을 보냅니다. 여기서 message_spec은 메시지 id(`'<'`과 `'>'`로 감싼)이거나 현재 그룹의 기사 번호입니다. message_spec이 생략되거나 `None`이면, 현재 그룹의 현재 기사가 고려됩니다. number가 기사 번호이고 id는 메시지 id인 트리플 `(response, number, 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`()

  `NEXT` 명령을 보냅니다. `stat()`과 같은 것을 반환합니다.

`NNTP.``last`()

  `LAST` 명령을 보냅니다. `stat()`과 같은 것을 반환합니다.

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

  `ARTICLE` 명령을 보냅니다. 여기서 message_spec은 `stat()`에서와 같은 의미입니다. 튜플 `(response, info)`를 반환합니다. 여기서 info는 3개의 어트리뷰트 number, message_id 및 lines(순서대로)가 있는 `namedtuple`입니다. number는 그룹의 기사 번호 (또는 정보가 없으면 0), message_id는 문자열 메시지 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` 명령을 보냅니다. 반환된 (또는 file에 기록되는) lines는 본문이 아닌 메시지 헤더만 포함합니다.

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

  `article()`과 같지만, `BODY` 명령을 보냅니다. 반환된 (또는 file에 기록되는) lines는 헤더가 아닌 메시지 본문만 포함합니다.

`NNTP.``post`(data)

  `POST` 명령을 사용하여 기사를 게시합니다. data 인자는 바이너리 읽기를 위해 열린 파일 객체, 또는 바이트열 객체의 이터러블(게시할 기사의 원시 줄을 나타냅니다)입니다. 필수 헤더를 포함하여 올바르게 구성된 뉴스 기사를 나타내야 합니다. `post()` 메서드는 `.`으로 시작하는 줄을 자동으로 이스케이프하고 종료 줄을 추가합니다.

  메서드가 성공하면, 서버의 응답이 반환됩니다. 서버가 게시를 거부하면, `NNTPReplyError` 가 발생합니다.

`NNTP.``ihave`(message_id, data)

  `IHAVE` 명령을 보냅니다. message_id는 서버로 보낼 메시지의 id입니다 (`'<'`과 `'>'`로 감쌉니다). data 매개 변수와 반환 값은 `post()`와 같습니다.

`NNTP.``date`()

  쌍 `(response, date)`를 반환합니다. date는 서버의 현재 날짜와 시간을 포함하는 `datetime` 객체입니다.

`NNTP.``slave`()

  `SLAVE` 명령을 보냅니다. 서버의 응답을 반환합니다.

`NNTP.``set_debuglevel`(level)

  인스턴스의 디버깅 수준을 설정합니다. 인쇄되는 디버깅 출력량을 제어합니다. 기본 `0`은 디버깅 출력을 생성하지 않습니다. `1` 값은 요청이나 응답마다 한 줄씩 적당한 양의 디버깅 출력을 생성합니다. `2` 이상의 값은 최대량의 디버깅 출력을 생성하여, 연결에서 주고받은 각 줄(메시지 텍스트를 포함합니다)을 로깅 합니다.

다음은 RFC 2980에 정의된 선택적 NNTP 확장입니다. 이 중 일부는 RFC 3977에서 새로운 명령으로 대체되었습니다.

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

  `XHDR` 명령을 보냅니다. hdr 인자는 헤더 키워드입니다, 예를 들어 `'subject'`. str 인자는 `'first-last'` 형식이어야 합니다. 여기서 first와 last는 검색할 첫 번째와 마지막 기사 번호입니다. 쌍 `(response, list)`를 반환합니다. 여기서 list는 쌍 `(id, text)`의 리스이고, id는 기사 번호(문자열)이고, text는 해당 기사에 대해 요청된 헤더의 텍스트입니다. file 매개 변수가 제공되면, `XHDR` 명령의 출력이 파일에 저장됩니다. file이 문자열이면, 메서드는 해당 이름의 파일을 열고, 쓰고 나서 닫습니다. file이 파일 객체이면 `write()`를 호출하여 명령 출력의 줄을 저장합니다. file이 제공되면, 반환된 list는 빈 리스트입니다.

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

  `XOVER` 명령을 보냅니다. start와 end는 선택할 기사 범위를 정하는 기사 번호입니다. 반환 값은 `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'