issue13287 - Define __all__ for urllib.request and urllib.error and expose only

the relevant module. Other cleanup improvements. Patch by flox.
This commit is contained in:
Senthil Kumaran 2011-11-01 23:20:31 +08:00
parent 712b14fc2a
commit 6c5bd40a3e
4 changed files with 40 additions and 18 deletions

View file

@ -19,6 +19,18 @@ import urllib.error
# parse_keqv_list, parse_http_list, HTTPDigestAuthHandler # parse_keqv_list, parse_http_list, HTTPDigestAuthHandler
class TrivialTests(unittest.TestCase): class TrivialTests(unittest.TestCase):
def test___all__(self):
# Verify which names are exposed
for module in 'request', 'response', 'parse', 'error', 'robotparser':
context = {}
exec('from urllib.%s import *' % module, context)
del context['__builtins__']
for k, v in context.items():
self.assertEqual(v.__module__, 'urllib.%s' % module,
"%r is exposed in 'urllib.%s' but defined in %r" %
(k, module, v.__module__))
def test_trivial(self): def test_trivial(self):
# A couple trivial tests # A couple trivial tests

View file

@ -13,6 +13,9 @@ response.
import urllib.response import urllib.response
__all__ = ['URLError', 'HTTPError', 'ContentTooShortError']
# do these error classes make sense? # do these error classes make sense?
# make sure all of the IOError stuff is overridden. we just want to be # make sure all of the IOError stuff is overridden. we just want to be
# subtypes. # subtypes.

View file

@ -89,7 +89,6 @@ import http.client
import io import io
import os import os
import posixpath import posixpath
import random
import re import re
import socket import socket
import sys import sys
@ -111,6 +110,22 @@ except ImportError:
else: else:
_have_ssl = True _have_ssl = True
__all__ = [
# Classes
'Request', 'OpenerDirector', 'BaseHandler', 'HTTPDefaultErrorHandler',
'HTTPRedirectHandler', 'HTTPCookieProcessor', 'ProxyHandler',
'HTTPPasswordMgr', 'HTTPPasswordMgrWithDefaultRealm',
'AbstractBasicAuthHandler', 'HTTPBasicAuthHandler', 'ProxyBasicAuthHandler',
'AbstractDigestAuthHandler', 'HTTPDigestAuthHandler', 'ProxyDigestAuthHandler',
'HTTPHandler', 'FileHandler', 'FTPHandler', 'CacheFTPHandler',
'UnknownHandler', 'HTTPErrorProcessor',
# Functions
'urlopen', 'install_opener', 'build_opener',
'pathname2url', 'url2pathname', 'getproxies',
# Legacy interface
'urlretrieve', 'urlcleanup', 'URLopener', 'FancyURLopener',
]
# used in User-Agent header sent # used in User-Agent header sent
__version__ = sys.version[:3] __version__ = sys.version[:3]
@ -885,9 +900,9 @@ class ProxyBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler):
return response return response
def randombytes(n): # Return n random bytes.
"""Return n random bytes.""" _randombytes = os.urandom
return os.urandom(n)
class AbstractDigestAuthHandler: class AbstractDigestAuthHandler:
# Digest authentication is specified in RFC 2617. # Digest authentication is specified in RFC 2617.
@ -951,7 +966,7 @@ class AbstractDigestAuthHandler:
# authentication, and to provide some message integrity protection. # authentication, and to provide some message integrity protection.
# This isn't a fabulous effort, but it's probably Good Enough. # This isn't a fabulous effort, but it's probably Good Enough.
s = "%s:%s:%s:" % (self.nonce_count, nonce, time.ctime()) s = "%s:%s:%s:" % (self.nonce_count, nonce, time.ctime())
b = s.encode("ascii") + randombytes(8) b = s.encode("ascii") + _randombytes(8)
dig = hashlib.sha1(b).hexdigest() dig = hashlib.sha1(b).hexdigest()
return dig[:16] return dig[:16]
@ -1171,7 +1186,6 @@ class HTTPHandler(AbstractHTTPHandler):
http_request = AbstractHTTPHandler.do_request_ http_request = AbstractHTTPHandler.do_request_
if hasattr(http.client, 'HTTPSConnection'): if hasattr(http.client, 'HTTPSConnection'):
import ssl
class HTTPSHandler(AbstractHTTPHandler): class HTTPSHandler(AbstractHTTPHandler):
@ -1677,13 +1691,11 @@ class URLopener:
if not host: raise IOError('http error', 'no host given') if not host: raise IOError('http error', 'no host given')
if proxy_passwd: if proxy_passwd:
import base64
proxy_auth = base64.b64encode(proxy_passwd.encode()).decode('ascii') proxy_auth = base64.b64encode(proxy_passwd.encode()).decode('ascii')
else: else:
proxy_auth = None proxy_auth = None
if user_passwd: if user_passwd:
import base64
auth = base64.b64encode(user_passwd.encode()).decode('ascii') auth = base64.b64encode(user_passwd.encode()).decode('ascii')
else: else:
auth = None auth = None
@ -1773,8 +1785,8 @@ class URLopener:
def open_local_file(self, url): def open_local_file(self, url):
"""Use local file.""" """Use local file."""
import mimetypes, email.utils import email.utils
from io import StringIO import mimetypes
host, file = splithost(url) host, file = splithost(url)
localname = url2pathname(file) localname = url2pathname(file)
try: try:
@ -1806,7 +1818,6 @@ class URLopener:
if not isinstance(url, str): if not isinstance(url, str):
raise URLError('ftp error', 'proxy support for ftp protocol currently not implemented') raise URLError('ftp error', 'proxy support for ftp protocol currently not implemented')
import mimetypes import mimetypes
from io import StringIO
host, path = splithost(url) host, path = splithost(url)
if not host: raise URLError('ftp error', 'no host given') if not host: raise URLError('ftp error', 'no host given')
host, port = splitport(host) host, port = splitport(host)
@ -1888,7 +1899,6 @@ class URLopener:
time.gmtime(time.time()))) time.gmtime(time.time())))
msg.append('Content-type: %s' % type) msg.append('Content-type: %s' % type)
if encoding == 'base64': if encoding == 'base64':
import base64
# XXX is this encoding/decoding ok? # XXX is this encoding/decoding ok?
data = base64.decodebytes(data.encode('ascii')).decode('latin-1') data = base64.decodebytes(data.encode('ascii')).decode('latin-1')
else: else:
@ -1984,7 +1994,6 @@ class FancyURLopener(URLopener):
URLopener.http_error_default(self, url, fp, URLopener.http_error_default(self, url, fp,
errcode, errmsg, headers) errcode, errmsg, headers)
stuff = headers['www-authenticate'] stuff = headers['www-authenticate']
import re
match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff) match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff)
if not match: if not match:
URLopener.http_error_default(self, url, fp, URLopener.http_error_default(self, url, fp,
@ -2010,7 +2019,6 @@ class FancyURLopener(URLopener):
URLopener.http_error_default(self, url, fp, URLopener.http_error_default(self, url, fp,
errcode, errmsg, headers) errcode, errmsg, headers)
stuff = headers['proxy-authenticate'] stuff = headers['proxy-authenticate']
import re
match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff) match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff)
if not match: if not match:
URLopener.http_error_default(self, url, fp, URLopener.http_error_default(self, url, fp,
@ -2302,8 +2310,6 @@ def _proxy_bypass_macosx_sysconf(host, proxy_settings):
'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16'] 'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16']
} }
""" """
import re
import socket
from fnmatch import fnmatch from fnmatch import fnmatch
hostonly, port = splitport(host) hostonly, port = splitport(host)
@ -2406,7 +2412,6 @@ elif os.name == 'nt':
for p in proxyServer.split(';'): for p in proxyServer.split(';'):
protocol, address = p.split('=', 1) protocol, address = p.split('=', 1)
# See if address has a type:// prefix # See if address has a type:// prefix
import re
if not re.match('^([^/:]+)://', address): if not re.match('^([^/:]+)://', address):
address = '%s://%s' % (protocol, address) address = '%s://%s' % (protocol, address)
proxies[protocol] = address proxies[protocol] = address
@ -2438,7 +2443,6 @@ elif os.name == 'nt':
def proxy_bypass_registry(host): def proxy_bypass_registry(host):
try: try:
import winreg import winreg
import re
except ImportError: except ImportError:
# Std modules, so should be around - but you never know! # Std modules, so should be around - but you never know!
return 0 return 0

View file

@ -350,6 +350,9 @@ Core and Builtins
Library Library
------- -------
- Issue #13287: urllib.request and urllib.error now contains a __all__ and
exposes only relevant Classes, Functions. Patch by Florent Xicluna.
- Issue #670664: Fix HTMLParser to correctly handle the content of - Issue #670664: Fix HTMLParser to correctly handle the content of
``<script>...</script>`` and ``<style>...</style>``. ``<script>...</script>`` and ``<style>...</style>``.