diff --git a/django/contrib/auth/password_validation.py b/django/contrib/auth/password_validation.py index 948ded6dbc..30c82f0b93 100644 --- a/django/contrib/auth/password_validation.py +++ b/django/contrib/auth/password_validation.py @@ -173,7 +173,7 @@ class CommonPasswordValidator: try: with gzip.open(str(password_list_path)) as f: common_passwords_lines = f.read().decode().splitlines() - except IOError: + except OSError: with open(str(password_list_path)) as f: common_passwords_lines = f.readlines() diff --git a/django/contrib/gis/gdal/libgdal.py b/django/contrib/gis/gdal/libgdal.py index 295c5ea099..5232e58717 100644 --- a/django/contrib/gis/gdal/libgdal.py +++ b/django/contrib/gis/gdal/libgdal.py @@ -13,8 +13,7 @@ logger = logging.getLogger('django.contrib.gis') try: from django.conf import settings lib_path = settings.GDAL_LIBRARY_PATH -except (AttributeError, EnvironmentError, - ImportError, ImproperlyConfigured): +except (AttributeError, ImportError, ImproperlyConfigured, OSError): lib_path = None if lib_path: diff --git a/django/contrib/gis/geos/libgeos.py b/django/contrib/gis/geos/libgeos.py index 40f3cae33a..951508c950 100644 --- a/django/contrib/gis/geos/libgeos.py +++ b/django/contrib/gis/geos/libgeos.py @@ -23,8 +23,7 @@ def load_geos(): try: from django.conf import settings lib_path = settings.GEOS_LIBRARY_PATH - except (AttributeError, EnvironmentError, - ImportError, ImproperlyConfigured): + except (AttributeError, ImportError, ImproperlyConfigured, OSError): lib_path = None # Setting the appropriate names for the GEOS-C library. diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py index 075b55e36b..60c10d6959 100644 --- a/django/contrib/sessions/backends/file.py +++ b/django/contrib/sessions/backends/file.py @@ -94,7 +94,7 @@ class SessionStore(SessionBase): session_data = {} self.delete() self.create() - except (IOError, SuspiciousOperation): + except (OSError, SuspiciousOperation): self._session_key = None return session_data @@ -166,7 +166,7 @@ class SessionStore(SessionBase): finally: if not renamed: os.unlink(output_file_name) - except (OSError, IOError, EOFError): + except (EOFError, OSError): pass def exists(self, session_key): diff --git a/django/contrib/staticfiles/storage.py b/django/contrib/staticfiles/storage.py index f6f335ce13..e49febe611 100644 --- a/django/contrib/staticfiles/storage.py +++ b/django/contrib/staticfiles/storage.py @@ -93,7 +93,7 @@ class HashedFilesMixin: raise ValueError("The file '%s' could not be found with %r." % (filename, self)) try: content = self.open(filename) - except IOError: + except OSError: # Handle directory paths and fragments return name try: @@ -380,7 +380,7 @@ class ManifestFilesMixin(HashedFilesMixin): try: with self.open(self.manifest_name) as manifest: return manifest.read().decode() - except IOError: + except OSError: return None def load_manifest(self): diff --git a/django/core/files/move.py b/django/core/files/move.py index 4d791ac263..2cce7848ca 100644 --- a/django/core/files/move.py +++ b/django/core/files/move.py @@ -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 the destination file exists and ``allow_overwrite`` is ``False``, raise - ``IOError``. + ``FileExistsError``. """ # There's no reason to move if we don't have to. 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: 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) return diff --git a/django/core/files/storage.py b/django/core/files/storage.py index 9a7d8793fc..db0d311209 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -246,7 +246,7 @@ class FileSystemStorage(Storage): # was created concurrently. pass 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 # saving the file; it's possible that two threads might return the diff --git a/django/core/files/temp.py b/django/core/files/temp.py index 07935930bd..57a8107b37 100644 --- a/django/core/files/temp.py +++ b/django/core/files/temp.py @@ -50,7 +50,7 @@ if os.name == 'nt': self.close_called = True try: self.file.close() - except (OSError, IOError): + except OSError: pass try: self.unlink(self.name) diff --git a/django/core/mail/backends/smtp.py b/django/core/mail/backends/smtp.py index 50b5b048ec..13ed4a2798 100644 --- a/django/core/mail/backends/smtp.py +++ b/django/core/mail/backends/smtp.py @@ -1,6 +1,5 @@ """SMTP email backend class.""" import smtplib -import socket import ssl import threading @@ -69,7 +68,7 @@ class EmailBackend(BaseEmailBackend): if self.username and self.password: self.connection.login(self.username, self.password) return True - except (smtplib.SMTPException, socket.error): + except OSError: if not self.fail_silently: raise diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py index 80537dd6ac..ba800d269e 100644 --- a/django/core/management/commands/compilemessages.py +++ b/django/core/management/commands/compilemessages.py @@ -19,7 +19,7 @@ def is_writable(path): try: with open(path, 'a'): os.utime(path, None) - except (IOError, OSError): + except OSError: return False return True diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py index 862da12c64..8425c6a443 100644 --- a/django/core/management/commands/runserver.py +++ b/django/core/management/commands/runserver.py @@ -137,7 +137,7 @@ class Command(BaseCommand): handler = self.get_handler(*args, **options) run(self.addr, int(self.port), handler, 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. ERRORS = { errno.EACCES: "You don't have permission to access that port.", diff --git a/django/core/management/templates.py b/django/core/management/templates.py index acfcdf437d..f261a9235e 100644 --- a/django/core/management/templates.py +++ b/django/core/management/templates.py @@ -257,7 +257,7 @@ class TemplateCommand(BaseCommand): self.stdout.write("Downloading %s\n" % display_url) try: 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" % (url, filename, e)) @@ -312,7 +312,7 @@ class TemplateCommand(BaseCommand): try: archive.extract(filename, 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" % (filename, tempdir, e)) diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 3e8f176bc6..ef93e28f26 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -51,8 +51,8 @@ def get_internal_wsgi_application(): def is_broken_pipe_error(): - exc_type, exc_value = sys.exc_info()[:2] - return issubclass(exc_type, socket.error) and exc_value.args[0] == 32 + exc_type, _, _ = sys.exc_info() + return issubclass(exc_type, BrokenPipeError) class WSGIServer(simple_server.WSGIServer): @@ -171,7 +171,7 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler): self.handle_one_request() try: self.connection.shutdown(socket.SHUT_WR) - except (socket.error, AttributeError): + except (AttributeError, OSError): pass def handle_one_request(self): diff --git a/django/http/request.py b/django/http/request.py index f1c232d89a..51d0a8dfc3 100644 --- a/django/http/request.py +++ b/django/http/request.py @@ -22,7 +22,7 @@ RAISE_ERROR = object() host_validation_re = re.compile(r"^([a-z0-9.-]+|\[[a-f0-9]*:[a-f0-9\.:]+\])(:\d+)?$") -class UnreadablePostError(IOError): +class UnreadablePostError(OSError): pass @@ -284,7 +284,7 @@ class HttpRequest: try: self._body = self.read() - except IOError as e: + except OSError as e: raise UnreadablePostError(*e.args) from e self._stream = BytesIO(self._body) return self._body @@ -339,14 +339,14 @@ class HttpRequest: self._read_started = True try: return self._stream.read(*args, **kwargs) - except IOError as e: + except OSError as e: raise UnreadablePostError(*e.args) from e def readline(self, *args, **kwargs): self._read_started = True try: return self._stream.readline(*args, **kwargs) - except IOError as e: + except OSError as e: raise UnreadablePostError(*e.args) from e def __iter__(self): diff --git a/django/http/response.py b/django/http/response.py index 5a640a51cf..6a84e193ba 100644 --- a/django/http/response.py +++ b/django/http/response.py @@ -251,13 +251,13 @@ class HttpResponseBase: signals.request_finished.send(sender=self._handler_class) 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): pass 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. # See https://docs.python.org/library/io.html#io.IOBase @@ -272,7 +272,7 @@ class HttpResponseBase: return False 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): diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py index c9c27666ae..a7b0a22ba2 100644 --- a/django/middleware/csrf.py +++ b/django/middleware/csrf.py @@ -293,7 +293,7 @@ class CsrfViewMiddleware(MiddlewareMixin): if request.method == "POST": try: request_csrf_token = request.POST.get('csrfmiddlewaretoken', '') - except IOError: + except OSError: # Handle a broken connection before we've completed reading # the POST data. process_view shouldn't raise any # exceptions, so we'll ignore and serve the user a 403 diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 98e3d0f51b..0e53b223e5 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -99,7 +99,7 @@ class DjangoTranslation(gettext_module.GNUTranslations): self._add_local_translations() 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. - 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) if self._catalog is None: # No catalogs found for this language, set an empty catalog. diff --git a/django/views/debug.py b/django/views/debug.py index b59fe29bdd..1128301c57 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -357,7 +357,7 @@ class ExceptionReporter: try: with open(filename, 'rb') as fp: source = fp.read().splitlines() - except (OSError, IOError): + except OSError: pass if source is None: return None, [], None, [] diff --git a/docs/topics/files.txt b/docs/topics/files.txt index 6a2ff44f0b..3154459116 100644 --- a/docs/topics/files.txt +++ b/docs/topics/files.txt @@ -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 may lead to the following error:: - IOError: [Errno 24] Too many open files + OSError: [Errno 24] Too many open files File storage diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 623fa39bc1..a7335f8f69 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -867,7 +867,7 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): for language_code, language_name in settings.LANGUAGES: try: catalog = gettext.translation('djangojs', path, [language_code]) - except IOError: + except OSError: continue if month_string in catalog._catalog: month_name = catalog._catalog[month_string] diff --git a/tests/cache/tests.py b/tests/cache/tests.py index 0dd9208710..9f717cfa23 100644 --- a/tests/cache/tests.py +++ b/tests/cache/tests.py @@ -1448,8 +1448,8 @@ class FileBasedCacheTests(BaseCacheTests, TestCase): self.assertEqual(cache.get('foo', 'baz'), 'baz') def test_get_does_not_ignore_non_filenotfound_exceptions(self): - with mock.patch('builtins.open', side_effect=IOError): - with self.assertRaises(IOError): + with mock.patch('builtins.open', side_effect=OSError): + with self.assertRaises(OSError): cache.get('foo') def test_empty_cache_file_considered_expired(self): diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py index 2c40e44ae1..59abc6da32 100644 --- a/tests/csrf_tests/tests.py +++ b/tests/csrf_tests/tests.py @@ -441,12 +441,12 @@ class CsrfViewMiddlewareTestMixin: def test_post_data_read_failure(self): """ - #20128 -- IOErrors during POST data reading should be caught and - treated as if the POST data wasn't there. + OSErrors during POST data reading are caught and treated as if the + POST data wasn't there (#20128). """ 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): super().__init__() @@ -464,7 +464,7 @@ class CsrfViewMiddlewareTestMixin: self.raise_error = raise_error def _load_post_and_files(self): - raise IOError('error reading input data') + raise OSError('error reading input data') def _get_post(self): if self.raise_error: diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index 8c50abc9b0..991f1ff8cd 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -482,9 +482,9 @@ class FileStorageTests(SimpleTestCase): f1 = ContentFile('chunks fails') def failing_chunks(): - raise IOError + raise OSError f1.chunks = failing_chunks - with self.assertRaises(IOError): + with self.assertRaises(OSError): self.storage.save('error.file', f1) def test_delete_no_name(self): diff --git a/tests/file_uploads/tests.py b/tests/file_uploads/tests.py index fb333dcf13..07a9d9b647 100644 --- a/tests/file_uploads/tests.py +++ b/tests/file_uploads/tests.py @@ -548,16 +548,13 @@ class DirectoryCreationTests(SimpleTestCase): self.obj.testfile.save('foo.txt', SimpleUploadedFile('foo.txt', b'x'), save=False) 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 open(UPLOAD_TO, 'wb').close() 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: 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): diff --git a/tests/files/tests.py b/tests/files/tests.py index b50061649a..1c005dde57 100644 --- a/tests/files/tests.py +++ b/tests/files/tests.py @@ -355,8 +355,9 @@ class FileMoveSafeTests(unittest.TestCase): handle_a, self.file_a = 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 - with self.assertRaises(IOError): + # file_move_safe() raises OSError if the destination file exists and + # allow_overwrite is False. + with self.assertRaises(FileExistsError): file_move_safe(self.file_a, self.file_b, allow_overwrite=False) # should allow it and continue on if allow_overwrite is True diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py index 2377c8992e..0f58789237 100644 --- a/tests/i18n/tests.py +++ b/tests/i18n/tests.py @@ -1747,13 +1747,10 @@ class TranslationFilesMissing(SimpleTestCase): gettext_module.find = lambda *args, **kw: None def test_failure_finding_default_mo_files(self): - ''' - Ensure IOError is raised if the default language is unparseable. - Refs: #18192 - ''' + """OSError is raised if the default language is unparseable.""" self.patchGettextFind() trans_real._translations = {} - with self.assertRaises(IOError): + with self.assertRaises(OSError): activate('en') diff --git a/tests/mail/tests.py b/tests/mail/tests.py index f06e053074..e283101b79 100644 --- a/tests/mail/tests.py +++ b/tests/mail/tests.py @@ -4,7 +4,6 @@ import mimetypes import os import shutil import smtpd -import socket import sys import tempfile import threading @@ -1570,7 +1569,7 @@ class SMTPBackendStoppedServerTests(SMTPBackendTestsBase): """ A socket connection error is silenced with fail_silently=True. """ - with self.assertRaises(socket.error): + with self.assertRaises(ConnectionError): self.backend.open() self.backend.fail_silently = True self.backend.open() diff --git a/tests/requests/tests.py b/tests/requests/tests.py index 720178a8b4..9391ca2a08 100644 --- a/tests/requests/tests.py +++ b/tests/requests/tests.py @@ -479,11 +479,11 @@ class RequestsTests(SimpleTestCase): def test_POST_connection_error(self): """ 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): def read(self, len=0): - raise IOError("kaboom!") + raise OSError('kaboom!') payload = b'name=value' request = WSGIRequest({ @@ -520,11 +520,11 @@ class RequestsTests(SimpleTestCase): def test_FILES_connection_error(self): """ 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): def read(self, len=0): - raise IOError("kaboom!") + raise OSError('kaboom!') payload = b'x' request = WSGIRequest({ diff --git a/tests/responses/tests.py b/tests/responses/tests.py index 8adf092ca0..934e4dfe60 100644 --- a/tests/responses/tests.py +++ b/tests/responses/tests.py @@ -22,14 +22,14 @@ class HttpResponseBaseTests(SimpleTestCase): r = HttpResponseBase() 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') - 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']) def test_tell(self): 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() def test_setdefault(self): diff --git a/tests/servers/tests.py b/tests/servers/tests.py index 7f75b85d6c..1f111fb5ae 100644 --- a/tests/servers/tests.py +++ b/tests/servers/tests.py @@ -194,10 +194,10 @@ class LiveServerPort(LiveServerBase): TestCase = type("TestCase", (LiveServerBase,), {}) try: TestCase.setUpClass() - except socket.error as e: + except OSError as e: if e.errno == errno.EADDRINUSE: # We're out of ports, LiveServerTestCase correctly fails with - # a socket error. + # an OSError. return # Unexpected error. raise diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py index 733f5adb1d..0e8cb79fd5 100644 --- a/tests/sessions_tests/tests.py +++ b/tests/sessions_tests/tests.py @@ -532,7 +532,7 @@ class FileSessionTests(SessionTestsMixin, unittest.TestCase): def test_invalid_key_backslash(self): # Ensure we don't allow directory-traversal. # 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. with self.assertRaises(InvalidSessionKey): self.backend()._key_to_file("a\\b\\c") diff --git a/tests/staticfiles_tests/cases.py b/tests/staticfiles_tests/cases.py index ea746164a6..24de4e029e 100644 --- a/tests/staticfiles_tests/cases.py +++ b/tests/staticfiles_tests/cases.py @@ -23,7 +23,7 @@ class BaseStaticFilesMixin: ) def assertFileNotFound(self, filepath): - with self.assertRaises(IOError): + with self.assertRaises(OSError): self._get_file(filepath) def render_template(self, template, **kwargs): diff --git a/tests/template_tests/test_loaders.py b/tests/template_tests/test_loaders.py index ea69472264..9023457751 100644 --- a/tests/template_tests/test_loaders.py +++ b/tests/template_tests/test_loaders.py @@ -191,11 +191,11 @@ class FileSystemLoaderTests(SimpleTestCase): tmppath = os.path.join(tmpdir, tmpfile.name) os.chmod(tmppath, 0o0222) with self.set_dirs([tmpdir]): - with self.assertRaisesMessage(IOError, 'Permission denied'): + with self.assertRaisesMessage(PermissionError, 'Permission denied'): self.engine.get_template(tmpfile.name) def test_notafile_error(self): - with self.assertRaises(IOError): + with self.assertRaises(IsADirectoryError): self.engine.get_template('first')