Fixed #30137 -- Replaced OSError aliases with the canonical OSError.

Used more specific errors (e.g. FileExistsError) as appropriate.
This commit is contained in:
Jon Dufresne 2019-01-28 07:01:35 -08:00 committed by Tim Graham
parent 7444f32527
commit 7785e03ba8
33 changed files with 60 additions and 69 deletions

View File

@ -173,7 +173,7 @@ class CommonPasswordValidator:
try: try:
with gzip.open(str(password_list_path)) as f: with gzip.open(str(password_list_path)) as f:
common_passwords_lines = f.read().decode().splitlines() common_passwords_lines = f.read().decode().splitlines()
except IOError: except OSError:
with open(str(password_list_path)) as f: with open(str(password_list_path)) as f:
common_passwords_lines = f.readlines() common_passwords_lines = f.readlines()

View File

@ -13,8 +13,7 @@ logger = logging.getLogger('django.contrib.gis')
try: try:
from django.conf import settings from django.conf import settings
lib_path = settings.GDAL_LIBRARY_PATH lib_path = settings.GDAL_LIBRARY_PATH
except (AttributeError, EnvironmentError, except (AttributeError, ImportError, ImproperlyConfigured, OSError):
ImportError, ImproperlyConfigured):
lib_path = None lib_path = None
if lib_path: if lib_path:

View File

@ -23,8 +23,7 @@ def load_geos():
try: try:
from django.conf import settings from django.conf import settings
lib_path = settings.GEOS_LIBRARY_PATH lib_path = settings.GEOS_LIBRARY_PATH
except (AttributeError, EnvironmentError, except (AttributeError, ImportError, ImproperlyConfigured, OSError):
ImportError, ImproperlyConfigured):
lib_path = None lib_path = None
# Setting the appropriate names for the GEOS-C library. # Setting the appropriate names for the GEOS-C library.

View File

@ -94,7 +94,7 @@ class SessionStore(SessionBase):
session_data = {} session_data = {}
self.delete() self.delete()
self.create() self.create()
except (IOError, SuspiciousOperation): except (OSError, SuspiciousOperation):
self._session_key = None self._session_key = None
return session_data return session_data
@ -166,7 +166,7 @@ class SessionStore(SessionBase):
finally: finally:
if not renamed: if not renamed:
os.unlink(output_file_name) os.unlink(output_file_name)
except (OSError, IOError, EOFError): except (EOFError, OSError):
pass pass
def exists(self, session_key): def exists(self, session_key):

View File

@ -93,7 +93,7 @@ class HashedFilesMixin:
raise ValueError("The file '%s' could not be found with %r." % (filename, self)) raise ValueError("The file '%s' could not be found with %r." % (filename, self))
try: try:
content = self.open(filename) content = self.open(filename)
except IOError: except OSError:
# Handle directory paths and fragments # Handle directory paths and fragments
return name return name
try: try:
@ -380,7 +380,7 @@ class ManifestFilesMixin(HashedFilesMixin):
try: try:
with self.open(self.manifest_name) as manifest: with self.open(self.manifest_name) as manifest:
return manifest.read().decode() return manifest.read().decode()
except IOError: except OSError:
return None return None
def load_manifest(self): def load_manifest(self):

View File

@ -35,7 +35,7 @@ def file_move_safe(old_file_name, new_file_name, chunk_size=1024 * 64, allow_ove
If that fails, stream manually from one file to another in pure Python. If that fails, stream manually from one file to another in pure Python.
If the destination file exists and ``allow_overwrite`` is ``False``, raise If the destination file exists and ``allow_overwrite`` is ``False``, raise
``IOError``. ``FileExistsError``.
""" """
# There's no reason to move if we don't have to. # There's no reason to move if we don't have to.
if _samefile(old_file_name, new_file_name): if _samefile(old_file_name, new_file_name):
@ -43,7 +43,7 @@ def file_move_safe(old_file_name, new_file_name, chunk_size=1024 * 64, allow_ove
try: try:
if not allow_overwrite and os.access(new_file_name, os.F_OK): if not allow_overwrite and os.access(new_file_name, os.F_OK):
raise IOError("Destination file %s exists and allow_overwrite is False" % new_file_name) raise FileExistsError('Destination file %s exists and allow_overwrite is False.' % new_file_name)
os.rename(old_file_name, new_file_name) os.rename(old_file_name, new_file_name)
return return

View File

@ -246,7 +246,7 @@ class FileSystemStorage(Storage):
# was created concurrently. # was created concurrently.
pass pass
if not os.path.isdir(directory): if not os.path.isdir(directory):
raise IOError("%s exists and is not a directory." % directory) raise FileExistsError('%s exists and is not a directory.' % directory)
# There's a potential race condition between get_available_name and # There's a potential race condition between get_available_name and
# saving the file; it's possible that two threads might return the # saving the file; it's possible that two threads might return the

View File

@ -50,7 +50,7 @@ if os.name == 'nt':
self.close_called = True self.close_called = True
try: try:
self.file.close() self.file.close()
except (OSError, IOError): except OSError:
pass pass
try: try:
self.unlink(self.name) self.unlink(self.name)

View File

@ -1,6 +1,5 @@
"""SMTP email backend class.""" """SMTP email backend class."""
import smtplib import smtplib
import socket
import ssl import ssl
import threading import threading
@ -69,7 +68,7 @@ class EmailBackend(BaseEmailBackend):
if self.username and self.password: if self.username and self.password:
self.connection.login(self.username, self.password) self.connection.login(self.username, self.password)
return True return True
except (smtplib.SMTPException, socket.error): except OSError:
if not self.fail_silently: if not self.fail_silently:
raise raise

View File

@ -19,7 +19,7 @@ def is_writable(path):
try: try:
with open(path, 'a'): with open(path, 'a'):
os.utime(path, None) os.utime(path, None)
except (IOError, OSError): except OSError:
return False return False
return True return True

View File

@ -137,7 +137,7 @@ class Command(BaseCommand):
handler = self.get_handler(*args, **options) handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler, run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls) ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
except socket.error as e: except OSError as e:
# Use helpful error messages instead of ugly tracebacks. # Use helpful error messages instead of ugly tracebacks.
ERRORS = { ERRORS = {
errno.EACCES: "You don't have permission to access that port.", errno.EACCES: "You don't have permission to access that port.",

View File

@ -257,7 +257,7 @@ class TemplateCommand(BaseCommand):
self.stdout.write("Downloading %s\n" % display_url) self.stdout.write("Downloading %s\n" % display_url)
try: try:
the_path, info = urlretrieve(url, path.join(tempdir, filename)) the_path, info = urlretrieve(url, path.join(tempdir, filename))
except IOError as e: except OSError as e:
raise CommandError("couldn't download URL %s to %s: %s" % raise CommandError("couldn't download URL %s to %s: %s" %
(url, filename, e)) (url, filename, e))
@ -312,7 +312,7 @@ class TemplateCommand(BaseCommand):
try: try:
archive.extract(filename, tempdir) archive.extract(filename, tempdir)
return tempdir return tempdir
except (archive.ArchiveException, IOError) as e: except (archive.ArchiveException, OSError) as e:
raise CommandError("couldn't extract file %s to %s: %s" % raise CommandError("couldn't extract file %s to %s: %s" %
(filename, tempdir, e)) (filename, tempdir, e))

View File

@ -51,8 +51,8 @@ def get_internal_wsgi_application():
def is_broken_pipe_error(): def is_broken_pipe_error():
exc_type, exc_value = sys.exc_info()[:2] exc_type, _, _ = sys.exc_info()
return issubclass(exc_type, socket.error) and exc_value.args[0] == 32 return issubclass(exc_type, BrokenPipeError)
class WSGIServer(simple_server.WSGIServer): class WSGIServer(simple_server.WSGIServer):
@ -171,7 +171,7 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler):
self.handle_one_request() self.handle_one_request()
try: try:
self.connection.shutdown(socket.SHUT_WR) self.connection.shutdown(socket.SHUT_WR)
except (socket.error, AttributeError): except (AttributeError, OSError):
pass pass
def handle_one_request(self): def handle_one_request(self):

View File

@ -22,7 +22,7 @@ RAISE_ERROR = object()
host_validation_re = re.compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9\.:]+\])(:\d+)?$") host_validation_re = re.compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9\.:]+\])(:\d+)?$")
class UnreadablePostError(IOError): class UnreadablePostError(OSError):
pass pass
@ -284,7 +284,7 @@ class HttpRequest:
try: try:
self._body = self.read() self._body = self.read()
except IOError as e: except OSError as e:
raise UnreadablePostError(*e.args) from e raise UnreadablePostError(*e.args) from e
self._stream = BytesIO(self._body) self._stream = BytesIO(self._body)
return self._body return self._body
@ -339,14 +339,14 @@ class HttpRequest:
self._read_started = True self._read_started = True
try: try:
return self._stream.read(*args, **kwargs) return self._stream.read(*args, **kwargs)
except IOError as e: except OSError as e:
raise UnreadablePostError(*e.args) from e raise UnreadablePostError(*e.args) from e
def readline(self, *args, **kwargs): def readline(self, *args, **kwargs):
self._read_started = True self._read_started = True
try: try:
return self._stream.readline(*args, **kwargs) return self._stream.readline(*args, **kwargs)
except IOError as e: except OSError as e:
raise UnreadablePostError(*e.args) from e raise UnreadablePostError(*e.args) from e
def __iter__(self): def __iter__(self):

View File

@ -251,13 +251,13 @@ class HttpResponseBase:
signals.request_finished.send(sender=self._handler_class) signals.request_finished.send(sender=self._handler_class)
def write(self, content): def write(self, content):
raise IOError("This %s instance is not writable" % self.__class__.__name__) raise OSError('This %s instance is not writable' % self.__class__.__name__)
def flush(self): def flush(self):
pass pass
def tell(self): def tell(self):
raise IOError("This %s instance cannot tell its position" % self.__class__.__name__) raise OSError('This %s instance cannot tell its position' % self.__class__.__name__)
# These methods partially implement a stream-like object interface. # These methods partially implement a stream-like object interface.
# See https://docs.python.org/library/io.html#io.IOBase # See https://docs.python.org/library/io.html#io.IOBase
@ -272,7 +272,7 @@ class HttpResponseBase:
return False return False
def writelines(self, lines): def writelines(self, lines):
raise IOError("This %s instance is not writable" % self.__class__.__name__) raise OSError('This %s instance is not writable' % self.__class__.__name__)
class HttpResponse(HttpResponseBase): class HttpResponse(HttpResponseBase):

View File

@ -293,7 +293,7 @@ class CsrfViewMiddleware(MiddlewareMixin):
if request.method == "POST": if request.method == "POST":
try: try:
request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
except IOError: except OSError:
# Handle a broken connection before we've completed reading # Handle a broken connection before we've completed reading
# the POST data. process_view shouldn't raise any # the POST data. process_view shouldn't raise any
# exceptions, so we'll ignore and serve the user a 403 # exceptions, so we'll ignore and serve the user a 403

View File

@ -99,7 +99,7 @@ class DjangoTranslation(gettext_module.GNUTranslations):
self._add_local_translations() self._add_local_translations()
if self.__language == settings.LANGUAGE_CODE and self.domain == 'django' and self._catalog is None: if self.__language == settings.LANGUAGE_CODE and self.domain == 'django' and self._catalog is None:
# default lang should have at least one translation file available. # default lang should have at least one translation file available.
raise IOError("No translation files found for default language %s." % settings.LANGUAGE_CODE) raise OSError('No translation files found for default language %s.' % settings.LANGUAGE_CODE)
self._add_fallback(localedirs) self._add_fallback(localedirs)
if self._catalog is None: if self._catalog is None:
# No catalogs found for this language, set an empty catalog. # No catalogs found for this language, set an empty catalog.

View File

@ -357,7 +357,7 @@ class ExceptionReporter:
try: try:
with open(filename, 'rb') as fp: with open(filename, 'rb') as fp:
source = fp.read().splitlines() source = fp.read().splitlines()
except (OSError, IOError): except OSError:
pass pass
if source is None: if source is None:
return None, [], None, [] return None, [], None, []

View File

@ -114,7 +114,7 @@ over a large number of objects. If files are not manually closed after
accessing them, the risk of running out of file descriptors may arise. This accessing them, the risk of running out of file descriptors may arise. This
may lead to the following error:: may lead to the following error::
IOError: [Errno 24] Too many open files OSError: [Errno 24] Too many open files
File storage File storage

View File

@ -867,7 +867,7 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase):
for language_code, language_name in settings.LANGUAGES: for language_code, language_name in settings.LANGUAGES:
try: try:
catalog = gettext.translation('djangojs', path, [language_code]) catalog = gettext.translation('djangojs', path, [language_code])
except IOError: except OSError:
continue continue
if month_string in catalog._catalog: if month_string in catalog._catalog:
month_name = catalog._catalog[month_string] month_name = catalog._catalog[month_string]

View File

@ -1448,8 +1448,8 @@ class FileBasedCacheTests(BaseCacheTests, TestCase):
self.assertEqual(cache.get('foo', 'baz'), 'baz') self.assertEqual(cache.get('foo', 'baz'), 'baz')
def test_get_does_not_ignore_non_filenotfound_exceptions(self): def test_get_does_not_ignore_non_filenotfound_exceptions(self):
with mock.patch('builtins.open', side_effect=IOError): with mock.patch('builtins.open', side_effect=OSError):
with self.assertRaises(IOError): with self.assertRaises(OSError):
cache.get('foo') cache.get('foo')
def test_empty_cache_file_considered_expired(self): def test_empty_cache_file_considered_expired(self):

View File

@ -441,12 +441,12 @@ class CsrfViewMiddlewareTestMixin:
def test_post_data_read_failure(self): def test_post_data_read_failure(self):
""" """
#20128 -- IOErrors during POST data reading should be caught and OSErrors during POST data reading are caught and treated as if the
treated as if the POST data wasn't there. POST data wasn't there (#20128).
""" """
class CsrfPostRequest(HttpRequest): class CsrfPostRequest(HttpRequest):
""" """
HttpRequest that can raise an IOError when accessing POST data HttpRequest that can raise an OSError when accessing POST data
""" """
def __init__(self, token, raise_error): def __init__(self, token, raise_error):
super().__init__() super().__init__()
@ -464,7 +464,7 @@ class CsrfViewMiddlewareTestMixin:
self.raise_error = raise_error self.raise_error = raise_error
def _load_post_and_files(self): def _load_post_and_files(self):
raise IOError('error reading input data') raise OSError('error reading input data')
def _get_post(self): def _get_post(self):
if self.raise_error: if self.raise_error:

View File

@ -482,9 +482,9 @@ class FileStorageTests(SimpleTestCase):
f1 = ContentFile('chunks fails') f1 = ContentFile('chunks fails')
def failing_chunks(): def failing_chunks():
raise IOError raise OSError
f1.chunks = failing_chunks f1.chunks = failing_chunks
with self.assertRaises(IOError): with self.assertRaises(OSError):
self.storage.save('error.file', f1) self.storage.save('error.file', f1)
def test_delete_no_name(self): def test_delete_no_name(self):

View File

@ -548,16 +548,13 @@ class DirectoryCreationTests(SimpleTestCase):
self.obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', b'x'), save=False) self.obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', b'x'), save=False)
def test_not_a_directory(self): def test_not_a_directory(self):
"""The correct IOError is raised when the upload directory name exists but isn't a directory"""
# Create a file with the upload directory name # Create a file with the upload directory name
open(UPLOAD_TO, 'wb').close() open(UPLOAD_TO, 'wb').close()
self.addCleanup(os.remove, UPLOAD_TO) self.addCleanup(os.remove, UPLOAD_TO)
with self.assertRaises(IOError) as exc_info: msg = '%s exists and is not a directory.' % UPLOAD_TO
with self.assertRaisesMessage(FileExistsError, msg):
with SimpleUploadedFile('foo.txt', b'x') as file: with SimpleUploadedFile('foo.txt', b'x') as file:
self.obj.testfile.save('foo.txt', file, save=False) self.obj.testfile.save('foo.txt', file, save=False)
# The test needs to be done on a specific string as IOError
# is raised even without the patch (just not early enough)
self.assertEqual(exc_info.exception.args[0], "%s exists and is not a directory." % UPLOAD_TO)
class MultiParserTests(SimpleTestCase): class MultiParserTests(SimpleTestCase):

View File

@ -355,8 +355,9 @@ class FileMoveSafeTests(unittest.TestCase):
handle_a, self.file_a = tempfile.mkstemp() handle_a, self.file_a = tempfile.mkstemp()
handle_b, self.file_b = tempfile.mkstemp() handle_b, self.file_b = tempfile.mkstemp()
# file_move_safe should raise an IOError exception if destination file exists and allow_overwrite is False # file_move_safe() raises OSError if the destination file exists and
with self.assertRaises(IOError): # allow_overwrite is False.
with self.assertRaises(FileExistsError):
file_move_safe(self.file_a, self.file_b, allow_overwrite=False) file_move_safe(self.file_a, self.file_b, allow_overwrite=False)
# should allow it and continue on if allow_overwrite is True # should allow it and continue on if allow_overwrite is True

View File

@ -1747,13 +1747,10 @@ class TranslationFilesMissing(SimpleTestCase):
gettext_module.find = lambda *args, **kw: None gettext_module.find = lambda *args, **kw: None
def test_failure_finding_default_mo_files(self): def test_failure_finding_default_mo_files(self):
''' """OSError is raised if the default language is unparseable."""
Ensure IOError is raised if the default language is unparseable.
Refs: #18192
'''
self.patchGettextFind() self.patchGettextFind()
trans_real._translations = {} trans_real._translations = {}
with self.assertRaises(IOError): with self.assertRaises(OSError):
activate('en') activate('en')

View File

@ -4,7 +4,6 @@ import mimetypes
import os import os
import shutil import shutil
import smtpd import smtpd
import socket
import sys import sys
import tempfile import tempfile
import threading import threading
@ -1570,7 +1569,7 @@ class SMTPBackendStoppedServerTests(SMTPBackendTestsBase):
""" """
A socket connection error is silenced with fail_silently=True. A socket connection error is silenced with fail_silently=True.
""" """
with self.assertRaises(socket.error): with self.assertRaises(ConnectionError):
self.backend.open() self.backend.open()
self.backend.fail_silently = True self.backend.fail_silently = True
self.backend.open() self.backend.open()

View File

@ -479,11 +479,11 @@ class RequestsTests(SimpleTestCase):
def test_POST_connection_error(self): def test_POST_connection_error(self):
""" """
If wsgi.input.read() raises an exception while trying to read() the If wsgi.input.read() raises an exception while trying to read() the
POST, the exception should be identifiable (not a generic IOError). POST, the exception is identifiable (not a generic OSError).
""" """
class ExplodingBytesIO(BytesIO): class ExplodingBytesIO(BytesIO):
def read(self, len=0): def read(self, len=0):
raise IOError("kaboom!") raise OSError('kaboom!')
payload = b'name=value' payload = b'name=value'
request = WSGIRequest({ request = WSGIRequest({
@ -520,11 +520,11 @@ class RequestsTests(SimpleTestCase):
def test_FILES_connection_error(self): def test_FILES_connection_error(self):
""" """
If wsgi.input.read() raises an exception while trying to read() the If wsgi.input.read() raises an exception while trying to read() the
FILES, the exception should be identifiable (not a generic IOError). FILES, the exception is identifiable (not a generic OSError).
""" """
class ExplodingBytesIO(BytesIO): class ExplodingBytesIO(BytesIO):
def read(self, len=0): def read(self, len=0):
raise IOError("kaboom!") raise OSError('kaboom!')
payload = b'x' payload = b'x'
request = WSGIRequest({ request = WSGIRequest({

View File

@ -22,14 +22,14 @@ class HttpResponseBaseTests(SimpleTestCase):
r = HttpResponseBase() r = HttpResponseBase()
self.assertIs(r.writable(), False) self.assertIs(r.writable(), False)
with self.assertRaisesMessage(IOError, 'This HttpResponseBase instance is not writable'): with self.assertRaisesMessage(OSError, 'This HttpResponseBase instance is not writable'):
r.write('asdf') r.write('asdf')
with self.assertRaisesMessage(IOError, 'This HttpResponseBase instance is not writable'): with self.assertRaisesMessage(OSError, 'This HttpResponseBase instance is not writable'):
r.writelines(['asdf\n', 'qwer\n']) r.writelines(['asdf\n', 'qwer\n'])
def test_tell(self): def test_tell(self):
r = HttpResponseBase() r = HttpResponseBase()
with self.assertRaisesMessage(IOError, 'This HttpResponseBase instance cannot tell its position'): with self.assertRaisesMessage(OSError, 'This HttpResponseBase instance cannot tell its position'):
r.tell() r.tell()
def test_setdefault(self): def test_setdefault(self):

View File

@ -194,10 +194,10 @@ class LiveServerPort(LiveServerBase):
TestCase = type("TestCase", (LiveServerBase,), {}) TestCase = type("TestCase", (LiveServerBase,), {})
try: try:
TestCase.setUpClass() TestCase.setUpClass()
except socket.error as e: except OSError as e:
if e.errno == errno.EADDRINUSE: if e.errno == errno.EADDRINUSE:
# We're out of ports, LiveServerTestCase correctly fails with # We're out of ports, LiveServerTestCase correctly fails with
# a socket error. # an OSError.
return return
# Unexpected error. # Unexpected error.
raise raise

View File

@ -532,7 +532,7 @@ class FileSessionTests(SessionTestsMixin, unittest.TestCase):
def test_invalid_key_backslash(self): def test_invalid_key_backslash(self):
# Ensure we don't allow directory-traversal. # Ensure we don't allow directory-traversal.
# This is tested directly on _key_to_file, as load() will swallow # This is tested directly on _key_to_file, as load() will swallow
# a SuspiciousOperation in the same way as an IOError - by creating # a SuspiciousOperation in the same way as an OSError - by creating
# a new session, making it unclear whether the slashes were detected. # a new session, making it unclear whether the slashes were detected.
with self.assertRaises(InvalidSessionKey): with self.assertRaises(InvalidSessionKey):
self.backend()._key_to_file("a\\b\\c") self.backend()._key_to_file("a\\b\\c")

View File

@ -23,7 +23,7 @@ class BaseStaticFilesMixin:
) )
def assertFileNotFound(self, filepath): def assertFileNotFound(self, filepath):
with self.assertRaises(IOError): with self.assertRaises(OSError):
self._get_file(filepath) self._get_file(filepath)
def render_template(self, template, **kwargs): def render_template(self, template, **kwargs):

View File

@ -191,11 +191,11 @@ class FileSystemLoaderTests(SimpleTestCase):
tmppath = os.path.join(tmpdir, tmpfile.name) tmppath = os.path.join(tmpdir, tmpfile.name)
os.chmod(tmppath, 0o0222) os.chmod(tmppath, 0o0222)
with self.set_dirs([tmpdir]): with self.set_dirs([tmpdir]):
with self.assertRaisesMessage(IOError, 'Permission denied'): with self.assertRaisesMessage(PermissionError, 'Permission denied'):
self.engine.get_template(tmpfile.name) self.engine.get_template(tmpfile.name)
def test_notafile_error(self): def test_notafile_error(self):
with self.assertRaises(IOError): with self.assertRaises(IsADirectoryError):
self.engine.get_template('first') self.engine.get_template('first')