Skip to content

Commit

Permalink
bpo-39305: Update nntplib to merge nntplib.NNTP and nntplib._NNTPBase (
Browse files Browse the repository at this point in the history
  • Loading branch information
corona10 committed May 16, 2020
1 parent 372fa3e commit aa92a7c
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 60 deletions.
98 changes: 40 additions & 58 deletions Lib/nntplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def _encrypt_on(sock, context, hostname):


# The classes themselves
class _NNTPBase:
class NNTP:
# UTF-8 is the character set for all NNTP commands and responses: they
# are automatically encoded (when sending) and decoded (and receiving)
# by this class.
Expand All @@ -309,13 +309,18 @@ class _NNTPBase:
encoding = 'utf-8'
errors = 'surrogateescape'

def __init__(self, file, host,
readermode=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
def __init__(self, host, port=NNTP_PORT, user=None, password=None,
readermode=None, usenetrc=False,
timeout=_GLOBAL_DEFAULT_TIMEOUT):
"""Initialize an instance. Arguments:
- file: file-like object (open for read/write in binary mode)
- host: hostname of the server
- host: hostname to connect to
- port: port to connect to (default the standard NNTP port)
- user: username to authenticate with
- password: password to use with username
- readermode: if true, send 'mode reader' command after
connecting.
- usenetrc: allow loading username and password from ~/.netrc file
if not specified explicitly
- timeout: timeout (in seconds) used for socket connections
readermode is sometimes necessary if you are connecting to an
Expand All @@ -325,7 +330,24 @@ def __init__(self, file, host,
readermode.
"""
self.host = host
self.file = file
self.port = port
self.sock = self._create_socket(timeout)
self.file = None
try:
self.file = self.sock.makefile("rwb")
self._base_init(readermode)
if user or usenetrc:
self.login(user, password, usenetrc)
except:
if self.file:
self.file.close()
self.sock.close()
raise

def _base_init(self, readermode):
"""Partial initialization for the NNTP protocol.
This instance method is extracted for supporting the test code.
"""
self.debugging = 0
self.welcome = self._getresp()

Expand Down Expand Up @@ -370,6 +392,12 @@ def __exit__(self, *args):
if is_connected():
self._close()

def _create_socket(self, timeout):
if timeout is not None and not timeout:
raise ValueError('Non-blocking socket (timeout=0) is not supported')
sys.audit("nntplib.connect", self, self.host, self.port)
return socket.create_connection((self.host, self.port), timeout)

def getwelcome(self):
"""Get the welcome message from the server
(this is read and squirreled away by __init__()).
Expand Down Expand Up @@ -888,8 +916,12 @@ def ihave(self, message_id, data):
return self._post('IHAVE {0}'.format(message_id), data)

def _close(self):
self.file.close()
del self.file
try:
if self.file:
self.file.close()
del self.file
finally:
self.sock.close()

def quit(self):
"""Process a QUIT command and close the socket. Returns:
Expand Down Expand Up @@ -979,56 +1011,6 @@ def starttls(self, context=None):
raise NNTPError("TLS failed to start.")


class NNTP(_NNTPBase):

def __init__(self, host, port=NNTP_PORT, user=None, password=None,
readermode=None, usenetrc=False,
timeout=_GLOBAL_DEFAULT_TIMEOUT):
"""Initialize an instance. Arguments:
- host: hostname to connect to
- port: port to connect to (default the standard NNTP port)
- user: username to authenticate with
- password: password to use with username
- readermode: if true, send 'mode reader' command after
connecting.
- usenetrc: allow loading username and password from ~/.netrc file
if not specified explicitly
- timeout: timeout (in seconds) used for socket connections
readermode is sometimes necessary if you are connecting to an
NNTP server on the local machine and intend to call
reader-specific commands, such as `group'. If you get
unexpected NNTPPermanentErrors, you might need to set
readermode.
"""
self.host = host
self.port = port
self.sock = self._create_socket(timeout)
file = None
try:
file = self.sock.makefile("rwb")
super().__init__(file, host, readermode, timeout)
if user or usenetrc:
self.login(user, password, usenetrc)
except:
if file:
file.close()
self.sock.close()
raise

def _create_socket(self, timeout):
if timeout is not None and not timeout:
raise ValueError('Non-blocking socket (timeout=0) is not supported')
sys.audit("nntplib.connect", self, self.host, self.port)
return socket.create_connection((self.host, self.port), timeout)

def _close(self):
try:
super()._close()
finally:
self.sock.close()


if _have_ssl:
class NNTP_SSL(NNTP):

Expand Down
16 changes: 14 additions & 2 deletions Lib/test/test_nntplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
import unittest
import functools
import contextlib
import nntplib
import os.path
import re
import threading

from test import support
from test.support import socket_helper
from nntplib import NNTP, GroupInfo
import nntplib
from unittest.mock import patch
try:
import ssl
Expand Down Expand Up @@ -411,6 +411,18 @@ def make_mock_file(handler):
return (sio, file)


class NNTPServer(nntplib.NNTP):

def __init__(self, f, host, readermode=None):
self.file = f
self.host = host
self._base_init(readermode)

def _close(self):
self.file.close()
del self.file


class MockedNNTPTestsMixin:
# Override in derived classes
handler_class = None
Expand All @@ -426,7 +438,7 @@ def tearDown(self):
def make_server(self, *args, **kwargs):
self.handler = self.handler_class()
self.sio, file = make_mock_file(self.handler)
self.server = nntplib._NNTPBase(file, 'test.server', *args, **kwargs)
self.server = NNTPServer(file, 'test.server', *args, **kwargs)
return self.server


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Update :mod:`nntplib` to merge :class:`nntplib.NNTP` and
:class:`nntplib._NNTPBase`. Patch by Dong-hee Na.

0 comments on commit aa92a7c

Please sign in to comment.