Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 46 additions & 61 deletions Lib/nntplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,7 @@ def _encrypt_on(sock, context, hostname):
return context.wrap_socket(sock, server_hostname=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 @@ -310,8 +309,9 @@ class _NNTPBase:
encoding = 'utf-8'
errors = 'surrogateescape'

def __init__(self, file, host,
readermode=None, timeout=_GLOBAL_DEFAULT_TIMEOUT):
def __init__(self, host, file=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to add a new parameter file for NNTP.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will change this.

readermode=None, timeout=_GLOBAL_DEFAULT_TIMEOUT,
port=NNTP_PORT, user=None, password=None, usenetrc=False):
"""Initialize an instance. Arguments:
- file: file-like object (open for read/write in binary mode)
- host: hostname of the server
Expand All @@ -326,13 +326,32 @@ def __init__(self, file, host,
readermode.
"""
self.host = host
self.file = file
self.readermode = readermode

if file is not None:
self.file = file
self._initialize_instance()
return

self.port = port
self.sock = self._create_socket(timeout)
self.file = None
try:
self.file = self.sock.makefile("rwb")
self._initialize_instance()
if user or usenetrc:
self.login(user, password, usenetrc)
except:
if self.file:
self.file.close()
self.sock.close()
raise

def _initialize_instance(self):
self.debugging = 0
self.welcome = self._getresp()

# Inquire about capabilities (RFC 3977).
self._caps = None
self.getcapabilities()
self._inquire_capabilities()

# 'MODE READER' is sometimes necessary to enable 'reader' mode.
# However, the order in which 'MODE READER' and 'AUTHINFO' need to
Expand All @@ -342,12 +361,11 @@ def __init__(self, file, host,
# after performing its normal function.
# Enable only if we're not already in READER mode anyway.
self.readermode_afterauth = False
if readermode and 'READER' not in self._caps:
if self.readermode and 'READER' not in self._caps:
self._setreadermode()
if not self.readermode_afterauth:
# Capabilities might have changed after MODE READER
self._caps = None
self.getcapabilities()
self._inquire_capabilities()

# RFC 4642 2.2.2: Both the client and the server MUST know if there is
# a TLS session active. A client MUST NOT attempt to start a TLS
Expand All @@ -357,6 +375,23 @@ def __init__(self, file, host,
# Log in and encryption setup order is left to subclasses.
self.authenticated = False

def _inquire_capabilities(self):
# Inquire about capabilities (RFC 3977).
self._caps = None
self.getcapabilities()

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

def __enter__(self):
return self

Expand Down Expand Up @@ -1018,56 +1053,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
2 changes: 1 addition & 1 deletion Lib/test/test_nntplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,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 = nntplib.NNTP('test.server', file=file, *args, **kwargs)
return self.server


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Refactor :mod:`nntplib` merging `_NNTPBase` with `NNTP` - by Luciana Marques