浏览代码

Reverted "Fixed #27818 -- Replaced try/except/pass with contextlib.suppress()."

This reverts commit 550cb3a365dee4edfdd1563224d5304de2a57fda
because try/except performs better.
Tim Graham 7 年之前
父节点
当前提交
6e4c6281db
共有 66 个文件被更改,包括 351 次插入207 次删除
  1. 3 2
      django/contrib/admin/models.py
  2. 6 3
      django/contrib/admin/sites.py
  3. 3 3
      django/contrib/auth/middleware.py
  4. 3 2
      django/contrib/contenttypes/fields.py
  5. 3 2
      django/contrib/contenttypes/models.py
  6. 6 4
      django/contrib/contenttypes/views.py
  7. 6 4
      django/contrib/gis/db/backends/spatialite/schema.py
  8. 3 2
      django/contrib/gis/db/models/fields.py
  9. 3 2
      django/contrib/gis/gdal/layer.py
  10. 3 3
      django/contrib/gis/utils/__init__.py
  11. 3 2
      django/contrib/messages/storage/cookie.py
  12. 3 2
      django/contrib/sessions/backends/base.py
  13. 6 3
      django/contrib/sessions/backends/file.py
  14. 6 3
      django/contrib/sitemaps/__init__.py
  15. 6 4
      django/contrib/sites/models.py
  16. 3 2
      django/contrib/staticfiles/management/commands/collectstatic.py
  17. 6 3
      django/contrib/syndication/views.py
  18. 10 5
      django/core/cache/backends/filebased.py
  19. 13 6
      django/core/cache/backends/locmem.py
  20. 5 4
      django/core/files/move.py
  21. 11 8
      django/core/files/storage.py
  22. 8 5
      django/core/management/__init__.py
  23. 5 4
      django/core/management/base.py
  24. 3 2
      django/core/management/commands/flush.py
  25. 3 2
      django/core/management/commands/shell.py
  26. 3 2
      django/core/validators.py
  27. 5 4
      django/db/backends/postgresql/client.py
  28. 6 4
      django/db/backends/sqlite3/operations.py
  29. 3 2
      django/db/migrations/autodetector.py
  30. 4 2
      django/db/migrations/state.py
  31. 3 2
      django/db/migrations/writer.py
  32. 3 2
      django/db/models/expressions.py
  33. 12 5
      django/db/models/options.py
  34. 7 3
      django/db/models/query.py
  35. 3 2
      django/db/models/sql/query.py
  36. 3 2
      django/forms/fields.py
  37. 3 2
      django/forms/forms.py
  38. 3 3
      django/forms/formsets.py
  39. 3 2
      django/forms/models.py
  40. 3 2
      django/forms/widgets.py
  41. 9 4
      django/http/response.py
  42. 5 6
      django/template/backends/base.py
  43. 6 3
      django/template/defaultfilters.py
  44. 9 4
      django/test/signals.py
  45. 6 3
      django/urls/base.py
  46. 15 6
      django/utils/autoreload.py
  47. 3 2
      django/utils/datastructures.py
  48. 7 4
      django/utils/dateformat.py
  49. 6 3
      django/utils/formats.py
  50. 3 2
      django/utils/http.py
  51. 5 3
      django/utils/translation/__init__.py
  52. 9 4
      django/utils/translation/trans_real.py
  53. 6 3
      django/views/debug.py
  54. 6 3
      tests/admin_scripts/tests.py
  55. 3 2
      tests/backends/tests.py
  56. 3 2
      tests/bash_completion/tests.py
  57. 3 3
      tests/handlers/views.py
  58. 5 4
      tests/mail/tests.py
  59. 3 2
      tests/postgres_tests/test_aggregates.py
  60. 3 2
      tests/postgres_tests/test_array.py
  61. 3 2
      tests/postgres_tests/test_hstore.py
  62. 3 2
      tests/postgres_tests/test_json.py
  63. 3 2
      tests/postgres_tests/test_ranges.py
  64. 6 3
      tests/runtests.py
  65. 3 2
      tests/staticfiles_tests/storage.py
  66. 24 10
      tests/transaction_hooks/tests.py

+ 3 - 2
django/contrib/admin/models.py

@@ -1,5 +1,4 @@
 import json
-from contextlib import suppress
 
 from django.conf import settings
 from django.contrib.admin.utils import quote
@@ -138,6 +137,8 @@ class LogEntry(models.Model):
         """
         if self.content_type and self.object_id:
             url_name = 'admin:%s_%s_change' % (self.content_type.app_label, self.content_type.model)
-            with suppress(NoReverseMatch):
+            try:
                 return reverse(url_name, args=(quote(self.object_id),))
+            except NoReverseMatch:
+                pass
         return None

+ 6 - 3
django/contrib/admin/sites.py

@@ -1,4 +1,3 @@
-from contextlib import suppress
 from functools import update_wrapper
 from weakref import WeakSet
 
@@ -428,11 +427,15 @@ class AdminSite:
                 'perms': perms,
             }
             if perms.get('change'):
-                with suppress(NoReverseMatch):
+                try:
                     model_dict['admin_url'] = reverse('admin:%s_%s_changelist' % info, current_app=self.name)
+                except NoReverseMatch:
+                    pass
             if perms.get('add'):
-                with suppress(NoReverseMatch):
+                try:
                     model_dict['add_url'] = reverse('admin:%s_%s_add' % info, current_app=self.name)
+                except NoReverseMatch:
+                    pass
 
             if app_label in app_dict:
                 app_dict[app_label]['models'].append(model_dict)

+ 3 - 3
django/contrib/auth/middleware.py

@@ -1,5 +1,3 @@
-from contextlib import suppress
-
 from django.conf import settings
 from django.contrib import auth
 from django.contrib.auth import load_backend
@@ -91,8 +89,10 @@ class RemoteUserMiddleware(MiddlewareMixin):
         """
         backend_str = request.session[auth.BACKEND_SESSION_KEY]
         backend = auth.load_backend(backend_str)
-        with suppress(AttributeError):  # Backend has no clean_username method.
+        try:
             username = backend.clean_username(username)
+        except AttributeError:  # Backend has no clean_username method.
+            pass
         return username
 
     def _remove_invalid_user(self, request):

+ 3 - 2
django/contrib/contenttypes/fields.py

@@ -1,5 +1,4 @@
 from collections import defaultdict
-from contextlib import suppress
 
 from django.contrib.contenttypes.models import ContentType
 from django.core import checks
@@ -237,8 +236,10 @@ class GenericForeignKey(FieldCacheMixin):
                 rel_obj = None
         if ct_id is not None:
             ct = self.get_content_type(id=ct_id, using=instance._state.db)
-            with suppress(ObjectDoesNotExist):
+            try:
                 rel_obj = ct.get_object_for_this_type(pk=pk_val)
+            except ObjectDoesNotExist:
+                pass
         self.set_cached_value(instance, rel_obj)
         return rel_obj
 

+ 3 - 2
django/contrib/contenttypes/models.py

@@ -1,5 +1,4 @@
 from collections import defaultdict
-from contextlib import suppress
 
 from django.apps import apps
 from django.db import models
@@ -39,8 +38,10 @@ class ContentTypeManager(models.Manager):
         for the same model don't hit the database.
         """
         opts = self._get_opts(model, for_concrete_model)
-        with suppress(KeyError):
+        try:
             return self._get_from_cache(opts)
+        except KeyError:
+            pass
 
         # The ContentType entry was not found in the cache, therefore we
         # proceed to load or create it.

+ 6 - 4
django/contrib/contenttypes/views.py

@@ -1,5 +1,3 @@
-from contextlib import suppress
-
 from django.apps import apps
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.sites.requests import RequestSite
@@ -55,10 +53,12 @@ def shortcut(request, content_type_id, object_id):
         # First, look for an many-to-many relationship to Site.
         for field in opts.many_to_many:
             if field.remote_field.model is Site:
-                with suppress(IndexError):
+                try:
                     # Caveat: In the case of multiple related Sites, this just
                     # selects the *first* one, which is arbitrary.
                     object_domain = getattr(obj, field.name).all()[0].domain
+                except IndexError:
+                    pass
                 if object_domain is not None:
                     break
 
@@ -77,8 +77,10 @@ def shortcut(request, content_type_id, object_id):
 
         # Fall back to the current site (if possible).
         if object_domain is None:
-            with suppress(Site.DoesNotExist):
+            try:
                 object_domain = Site.objects.get_current(request).domain
+            except Site.DoesNotExist:
+                pass
 
     else:
         # Fall back to the current request's site.

+ 6 - 4
django/contrib/gis/db/backends/spatialite/schema.py

@@ -1,5 +1,3 @@
-from contextlib import suppress
-
 from django.db.backends.sqlite3.schema import DatabaseSchemaEditor
 from django.db.utils import DatabaseError
 
@@ -91,13 +89,15 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
                 self.remove_geometry_metadata(model, field)
         # Make sure all geom stuff is gone
         for geom_table in self.geometry_tables:
-            with suppress(DatabaseError):
+            try:
                 self.execute(
                     self.sql_discard_geometry_columns % {
                         "geom_table": geom_table,
                         "table": self.quote_name(model._meta.db_table),
                     }
                 )
+            except DatabaseError:
+                pass
         super().delete_model(model, **kwargs)
 
     def add_field(self, model, field):
@@ -138,7 +138,7 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
         super().alter_db_table(model, old_db_table, new_db_table)
         # Repoint any straggler names
         for geom_table in self.geometry_tables:
-            with suppress(DatabaseError):
+            try:
                 self.execute(
                     self.sql_update_geometry_columns % {
                         "geom_table": geom_table,
@@ -146,6 +146,8 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
                         "new_table": self.quote_name(new_db_table),
                     }
                 )
+            except DatabaseError:
+                pass
         # Re-add geometry-ness and rename spatial index tables
         for field in model._meta.local_fields:
             if isinstance(field, GeometryField):

+ 3 - 2
django/contrib/gis/db/models/fields.py

@@ -1,5 +1,4 @@
 from collections import defaultdict, namedtuple
-from contextlib import suppress
 
 from django.contrib.gis import forms, gdal
 from django.contrib.gis.db.models.proxy import SpatialProxy
@@ -157,8 +156,10 @@ class BaseSpatialField(Field):
         if isinstance(value, gdal.GDALRaster):
             return value
         elif is_candidate:
-            with suppress(GDALException):
+            try:
                 return gdal.GDALRaster(value)
+            except GDALException:
+                pass
         elif isinstance(value, dict):
             try:
                 return gdal.GDALRaster(value)

+ 3 - 2
django/contrib/gis/gdal/layer.py

@@ -1,4 +1,3 @@
-from contextlib import suppress
 from ctypes import byref, c_double
 
 from django.contrib.gis.gdal.base import GDALBase
@@ -77,8 +76,10 @@ class Layer(GDALBase):
         """
         if self._random_read:
             # If the Layer supports random reading, return.
-            with suppress(GDALException):
+            try:
                 return Feature(capi.get_feature(self.ptr, feat_id), self)
+            except GDALException:
+                pass
         else:
             # Random access isn't supported, have to increment through
             # each feature until the given feature ID is encountered.

+ 3 - 3
django/contrib/gis/utils/__init__.py

@@ -1,14 +1,14 @@
 """
  This module contains useful utilities for GeoDjango.
 """
-from contextlib import suppress
-
 from django.contrib.gis.utils.ogrinfo import ogrinfo  # NOQA
 from django.contrib.gis.utils.ogrinspect import mapping, ogrinspect  # NOQA
 from django.contrib.gis.utils.srs import add_srs_entry  # NOQA
 from django.core.exceptions import ImproperlyConfigured
 
-with suppress(ImproperlyConfigured):
+try:
     # LayerMapping requires DJANGO_SETTINGS_MODULE to be set,
     # and ImproperlyConfigured is raised if that's not the case.
     from django.contrib.gis.utils.layermapping import LayerMapping, LayerMapError  # NOQA
+except ImproperlyConfigured:
+    pass

+ 3 - 2
django/contrib/messages/storage/cookie.py

@@ -1,5 +1,4 @@
 import json
-from contextlib import suppress
 
 from django.conf import settings
 from django.contrib.messages.storage.base import BaseStorage, Message
@@ -154,10 +153,12 @@ class CookieStorage(BaseStorage):
         if len(bits) == 2:
             hash, value = bits
             if constant_time_compare(hash, self._hash(value)):
-                with suppress(ValueError):
+                try:
                     # If we get here (and the JSON decode works), everything is
                     # good. In any other case, drop back and return None.
                     return json.loads(value, cls=MessageDecoder)
+                except ValueError:
+                    pass
         # Mark the data as used (so it gets removed) since something was wrong
         # with the data.
         self.used = True

+ 3 - 2
django/contrib/sessions/backends/base.py

@@ -1,7 +1,6 @@
 import base64
 import logging
 import string
-from contextlib import suppress
 from datetime import datetime, timedelta
 
 from django.conf import settings
@@ -263,8 +262,10 @@ class SessionBase:
         """
         if value is None:
             # Remove any custom expiration for this session.
-            with suppress(KeyError):
+            try:
                 del self['_session_expiry']
+            except KeyError:
+                pass
             return
         if isinstance(value, timedelta):
             value = timezone.now() + value

+ 6 - 3
django/contrib/sessions/backends/file.py

@@ -3,7 +3,6 @@ import logging
 import os
 import shutil
 import tempfile
-from contextlib import suppress
 
 from django.conf import settings
 from django.contrib.sessions.backends.base import (
@@ -156,7 +155,7 @@ class SessionStore(SessionBase):
         # See ticket #8616.
         dir, prefix = os.path.split(session_file_name)
 
-        with suppress(OSError, IOError, EOFError):
+        try:
             output_file_fd, output_file_name = tempfile.mkstemp(dir=dir, prefix=prefix + '_out_')
             renamed = False
             try:
@@ -173,6 +172,8 @@ class SessionStore(SessionBase):
             finally:
                 if not renamed:
                     os.unlink(output_file_name)
+        except (OSError, IOError, EOFError):
+            pass
 
     def exists(self, session_key):
         return os.path.exists(self._key_to_file(session_key))
@@ -182,8 +183,10 @@ class SessionStore(SessionBase):
             if self.session_key is None:
                 return
             session_key = self.session_key
-        with suppress(OSError):
+        try:
             os.unlink(self._key_to_file(session_key))
+        except OSError:
+            pass
 
     def clean(self):
         pass

+ 6 - 3
django/contrib/sitemaps/__init__.py

@@ -1,4 +1,3 @@
-from contextlib import suppress
 from urllib.parse import urlencode
 from urllib.request import urlopen
 
@@ -37,9 +36,11 @@ def _get_sitemap_full_url(sitemap_url):
             # First, try to get the "index" sitemap URL.
             sitemap_url = reverse('django.contrib.sitemaps.views.index')
         except NoReverseMatch:
-            with suppress(NoReverseMatch):
+            try:
                 # Next, try for the "global" sitemap URL.
                 sitemap_url = reverse('django.contrib.sitemaps.views.sitemap')
+            except NoReverseMatch:
+                pass
 
     if sitemap_url is None:
         raise SitemapNotFound("You didn't provide a sitemap_url, and the sitemap URL couldn't be auto-detected.")
@@ -88,8 +89,10 @@ class Sitemap:
         if site is None:
             if django_apps.is_installed('django.contrib.sites'):
                 Site = django_apps.get_model('sites.Site')
-                with suppress(Site.DoesNotExist):
+                try:
                     site = Site.objects.get_current()
+                except Site.DoesNotExist:
+                    pass
             if site is None:
                 raise ImproperlyConfigured(
                     "To use sitemaps, either enable the sites framework or pass "

+ 6 - 4
django/contrib/sites/models.py

@@ -1,5 +1,4 @@
 import string
-from contextlib import suppress
 
 from django.core.exceptions import ImproperlyConfigured, ValidationError
 from django.db import models
@@ -108,11 +107,14 @@ def clear_site_cache(sender, **kwargs):
     """
     instance = kwargs['instance']
     using = kwargs['using']
-    with suppress(KeyError):
+    try:
         del SITE_CACHE[instance.pk]
-
-    with suppress(KeyError, Site.DoesNotExist):
+    except KeyError:
+        pass
+    try:
         del SITE_CACHE[Site.objects.using(using).get(pk=instance.pk).domain]
+    except (KeyError, Site.DoesNotExist):
+        pass
 
 
 pre_save.connect(clear_site_cache, sender=Site)

+ 3 - 2
django/contrib/staticfiles/management/commands/collectstatic.py

@@ -1,6 +1,5 @@
 import os
 from collections import OrderedDict
-from contextlib import suppress
 
 from django.apps import apps
 from django.contrib.staticfiles.finders import get_finders
@@ -313,8 +312,10 @@ class Command(BaseCommand):
         else:
             self.log("Linking '%s'" % source_path, level=1)
             full_path = self.storage.path(prefixed_path)
-            with suppress(OSError):
+            try:
                 os.makedirs(os.path.dirname(full_path))
+            except OSError:
+                pass
             try:
                 if os.path.lexists(full_path):
                     os.unlink(full_path)

+ 6 - 3
django/contrib/syndication/views.py

@@ -1,5 +1,4 @@
 from calendar import timegm
-from contextlib import suppress
 
 from django.conf import settings
 from django.contrib.sites.shortcuts import get_current_site
@@ -153,13 +152,17 @@ class Feed:
 
         title_tmp = None
         if self.title_template is not None:
-            with suppress(TemplateDoesNotExist):
+            try:
                 title_tmp = loader.get_template(self.title_template)
+            except TemplateDoesNotExist:
+                pass
 
         description_tmp = None
         if self.description_template is not None:
-            with suppress(TemplateDoesNotExist):
+            try:
                 description_tmp = loader.get_template(self.description_template)
+            except TemplateDoesNotExist:
+                pass
 
         for item in self._get_dynamic_attr('items', obj):
             context = self.get_context_data(item=item, site=current_site,

+ 10 - 5
django/core/cache/backends/filebased.py

@@ -7,7 +7,6 @@ import random
 import tempfile
 import time
 import zlib
-from contextlib import suppress
 
 from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
 from django.core.files.move import file_move_safe
@@ -30,10 +29,12 @@ class FileBasedCache(BaseCache):
 
     def get(self, key, default=None, version=None):
         fname = self._key_to_file(key, version)
-        with suppress(FileNotFoundError):
+        try:
             with open(fname, 'rb') as f:
                 if not self._is_expired(f):
                     return pickle.loads(zlib.decompress(f.read()))
+        except FileNotFoundError:
+            pass
         return default
 
     def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
@@ -59,9 +60,11 @@ class FileBasedCache(BaseCache):
     def _delete(self, fname):
         if not fname.startswith(self._dir) or not os.path.exists(fname):
             return
-        with suppress(FileNotFoundError):
-            # The file may have been removed by another process.
+        try:
             os.remove(fname)
+        except FileNotFoundError:
+            # The file may have been removed by another process.
+            pass
 
     def has_key(self, key, version=None):
         fname = self._key_to_file(key, version)
@@ -90,8 +93,10 @@ class FileBasedCache(BaseCache):
 
     def _createdir(self):
         if not os.path.exists(self._dir):
-            with suppress(FileExistsError):
+            try:
                 os.makedirs(self._dir, 0o700)
+            except FileExistsError:
+                pass
 
     def _key_to_file(self, key, version=None):
         """

+ 13 - 6
django/core/cache/backends/locmem.py

@@ -1,7 +1,7 @@
 "Thread-safe in-memory cache backend."
 import pickle
 import time
-from contextlib import contextmanager, suppress
+from contextlib import contextmanager
 
 from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
 from django.utils.synch import RWLock
@@ -50,9 +50,11 @@ class LocMemCache(BaseCache):
                 return default
 
         with (self._lock.writer() if acquire_lock else dummy()):
-            with suppress(KeyError):
+            try:
                 del self._cache[key]
                 del self._expire_info[key]
+            except KeyError:
+                pass
             return default
 
     def _set(self, key, value, timeout=DEFAULT_TIMEOUT):
@@ -87,9 +89,11 @@ class LocMemCache(BaseCache):
                 return True
 
         with self._lock.writer():
-            with suppress(KeyError):
+            try:
                 del self._cache[key]
                 del self._expire_info[key]
+            except KeyError:
+                pass
             return False
 
     def _has_expired(self, key):
@@ -107,11 +111,14 @@ class LocMemCache(BaseCache):
                 self._delete(k)
 
     def _delete(self, key):
-        with suppress(KeyError):
+        try:
             del self._cache[key]
-
-        with suppress(KeyError):
+        except KeyError:
+            pass
+        try:
             del self._expire_info[key]
+        except KeyError:
+            pass
 
     def delete(self, key, version=None):
         key = self.make_key(key, version=version)

+ 5 - 4
django/core/files/move.py

@@ -7,7 +7,6 @@ Move a file in the safest way possible::
 
 import errno
 import os
-from contextlib import suppress
 from shutil import copystat
 
 from django.core.files import locks
@@ -42,14 +41,16 @@ def file_move_safe(old_file_name, new_file_name, chunk_size=1024 * 64, allow_ove
     if _samefile(old_file_name, new_file_name):
         return
 
-    # OSError happens with os.rename() if moving to another filesystem or when
-    # moving opened files on certain operating systems.
-    with suppress(OSError):
+    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)
 
         os.rename(old_file_name, new_file_name)
         return
+    except OSError:
+        # OSError happens with os.rename() if moving to another filesystem or
+        # when moving opened files on certain operating systems.
+        pass
 
     # first open the old file, so that it won't go away
     with open(old_file_name, 'rb') as old_file:

+ 11 - 8
django/core/files/storage.py

@@ -1,5 +1,4 @@
 import os
-from contextlib import suppress
 from datetime import datetime
 from urllib.parse import urljoin
 
@@ -224,10 +223,7 @@ class FileSystemStorage(Storage):
         # Create any intermediate directories that do not exist.
         directory = os.path.dirname(full_path)
         if not os.path.exists(directory):
-            # There's a race between os.path.exists() and os.makedirs().
-            # If os.makedirs() fails with FileNotFoundError, the directory
-            # was created concurrently.
-            with suppress(FileNotFoundError):
+            try:
                 if self.directory_permissions_mode is not None:
                     # os.makedirs applies the global umask, so we reset it,
                     # for consistency with file_permissions_mode behavior.
@@ -238,6 +234,11 @@ class FileSystemStorage(Storage):
                         os.umask(old_umask)
                 else:
                     os.makedirs(directory)
+            except FileNotFoundError:
+                # There's a race between os.path.exists() and os.makedirs().
+                # If os.makedirs() fails with FileNotFoundError, the directory
+                # was created concurrently.
+                pass
         if not os.path.isdir(directory):
             raise IOError("%s exists and is not a directory." % directory)
 
@@ -293,13 +294,15 @@ class FileSystemStorage(Storage):
         assert name, "The name argument is not allowed to be empty."
         name = self.path(name)
         # If the file or directory exists, delete it from the filesystem.
-        # FileNotFoundError is raised if the file or directory was removed
-        # concurrently.
-        with suppress(FileNotFoundError):
+        try:
             if os.path.isdir(name):
                 os.rmdir(name)
             else:
                 os.remove(name)
+        except FileNotFoundError:
+            # FileNotFoundError is raised if the file or directory was removed
+            # concurrently.
+            pass
 
     def exists(self, name):
         return os.path.exists(self.path(name))

+ 8 - 5
django/core/management/__init__.py

@@ -3,7 +3,6 @@ import os
 import pkgutil
 import sys
 from collections import OrderedDict, defaultdict
-from contextlib import suppress
 from importlib import import_module
 
 import django
@@ -262,12 +261,14 @@ class ManagementUtility:
             subcommand_cls = self.fetch_command(cwords[0])
             # special case: add the names of installed apps to options
             if cwords[0] in ('dumpdata', 'sqlmigrate', 'sqlsequencereset', 'test'):
-                # Fail silently if DJANGO_SETTINGS_MODULE isn't set. The
-                # user will find out once they execute the command.
-                with suppress(ImportError):
+                try:
                     app_configs = apps.get_app_configs()
                     # Get the last part of the dotted path as the app name.
                     options.extend((app_config.label, 0) for app_config in app_configs)
+                except ImportError:
+                    # Fail silently if DJANGO_SETTINGS_MODULE isn't set. The
+                    # user will find out once they execute the command.
+                    pass
             parser = subcommand_cls.create_parser('', cwords[0])
             options.extend(
                 (min(s_opt.option_strings), s_opt.nargs != 0)
@@ -306,9 +307,11 @@ class ManagementUtility:
         parser.add_argument('--settings')
         parser.add_argument('--pythonpath')
         parser.add_argument('args', nargs='*')  # catch-all
-        with suppress(CommandError):  # Ignore any option errors at this point.
+        try:
             options, args = parser.parse_known_args(self.argv[2:])
             handle_default_options(options)
+        except CommandError:
+            pass  # Ignore any option errors at this point.
 
         try:
             settings.INSTALLED_APPS

+ 5 - 4
django/core/management/base.py

@@ -5,7 +5,6 @@ be executed through ``django-admin`` or ``manage.py``).
 import os
 import sys
 from argparse import ArgumentParser
-from contextlib import suppress
 from io import TextIOBase
 
 import django
@@ -298,10 +297,12 @@ class BaseCommand:
                 self.stderr.write('%s: %s' % (e.__class__.__name__, e))
             sys.exit(1)
         finally:
-            # Ignore if connections aren't setup at this point (e.g. no
-            # configured settings).
-            with suppress(ImproperlyConfigured):
+            try:
                 connections.close_all()
+            except ImproperlyConfigured:
+                # Ignore if connections aren't setup at this point (e.g. no
+                # configured settings).
+                pass
 
     def execute(self, *args, **options):
         """

+ 3 - 2
django/core/management/commands/flush.py

@@ -1,4 +1,3 @@
-from contextlib import suppress
 from importlib import import_module
 
 from django.apps import apps
@@ -40,8 +39,10 @@ class Command(BaseCommand):
         # Import the 'management' module within each installed app, to register
         # dispatcher events.
         for app_config in apps.get_app_configs():
-            with suppress(ImportError):
+            try:
                 import_module('.management', app_config.name)
+            except ImportError:
+                pass
 
         sql_list = sql_flush(self.style, connection, only_django=True,
                              reset_sequences=reset_sequences,

+ 3 - 2
django/core/management/commands/shell.py

@@ -2,7 +2,6 @@ import os
 import select
 import sys
 import traceback
-from contextlib import suppress
 
 from django.core.management import BaseCommand, CommandError
 from django.utils.datastructures import OrderedSet
@@ -96,6 +95,8 @@ class Command(BaseCommand):
         available_shells = [options['interface']] if options['interface'] else self.shells
 
         for shell in available_shells:
-            with suppress(ImportError):
+            try:
                 return getattr(self, shell)(options)
+            except ImportError:
+                pass
         raise CommandError("Couldn't import {} interface.".format(shell))

+ 3 - 2
django/core/validators.py

@@ -1,7 +1,6 @@
 import ipaddress
 import os
 import re
-from contextlib import suppress
 from urllib.parse import urlsplit, urlunsplit
 
 from django.core.exceptions import ValidationError
@@ -215,9 +214,11 @@ class EmailValidator:
         literal_match = self.literal_regex.match(domain_part)
         if literal_match:
             ip_address = literal_match.group(1)
-            with suppress(ValidationError):
+            try:
                 validate_ipv46_address(ip_address)
                 return True
+            except ValidationError:
+                pass
         return False
 
     def __eq__(self, other):

+ 5 - 4
django/db/backends/postgresql/client.py

@@ -1,7 +1,6 @@
 import os
 import signal
 import subprocess
-from contextlib import suppress
 
 from django.core.files.temp import NamedTemporaryFile
 from django.db.backends.base.client import BaseDatabaseClient
@@ -41,9 +40,7 @@ class DatabaseClient(BaseDatabaseClient):
             if passwd:
                 # Create temporary .pgpass file.
                 temp_pgpass = NamedTemporaryFile(mode='w+')
-                # If the current locale can't encode the data, let the user
-                # input the password manually.
-                with suppress(UnicodeEncodeError):
+                try:
                     print(
                         _escape_pgpass(host) or '*',
                         str(port) or '*',
@@ -55,6 +52,10 @@ class DatabaseClient(BaseDatabaseClient):
                         flush=True,
                     )
                     os.environ['PGPASSFILE'] = temp_pgpass.name
+                except UnicodeEncodeError:
+                    # If the current locale can't encode the data, let the
+                    # user input the password manually.
+                    pass
             # Allow SIGINT to pass to psql to abort queries.
             signal.signal(signal.SIGINT, signal.SIG_IGN)
             subprocess.check_call(args)

+ 6 - 4
django/db/backends/sqlite3/operations.py

@@ -1,6 +1,5 @@
 import datetime
 import uuid
-from contextlib import suppress
 
 from django.conf import settings
 from django.core.exceptions import FieldError
@@ -36,10 +35,13 @@ class DatabaseOperations(BaseDatabaseOperations):
         bad_aggregates = (aggregates.Sum, aggregates.Avg, aggregates.Variance, aggregates.StdDev)
         if isinstance(expression, bad_aggregates):
             for expr in expression.get_source_expressions():
-                # Not every subexpression has an output_field which is fine
-                # to ignore.
-                with suppress(FieldError):
+                try:
                     output_field = expr.output_field
+                except FieldError:
+                    # Not every subexpression has an output_field which is fine
+                    # to ignore.
+                    pass
+                else:
                     if isinstance(output_field, bad_fields):
                         raise NotImplementedError(
                             'You cannot use Sum, Avg, StdDev, and Variance '

+ 3 - 2
django/db/migrations/autodetector.py

@@ -1,6 +1,5 @@
 import functools
 import re
-from contextlib import suppress
 from itertools import chain
 
 from django.conf import settings
@@ -435,7 +434,7 @@ class MigrationAutodetector:
         Place potential swappable models first in lists of created models (only
         real way to solve #22783).
         """
-        with suppress(LookupError):
+        try:
             model = self.new_apps.get_model(item[0], item[1])
             base_names = [base.__name__ for base in model.__bases__]
             string_version = "%s.%s" % (item[0], item[1])
@@ -446,6 +445,8 @@ class MigrationAutodetector:
                 settings.AUTH_USER_MODEL.lower() == string_version.lower()
             ):
                 return ("___" + item[0], "___" + item[1])
+        except LookupError:
+            pass
         return item
 
     def generate_renamed_models(self):

+ 4 - 2
django/db/migrations/state.py

@@ -1,6 +1,6 @@
 import copy
 from collections import OrderedDict
-from contextlib import contextmanager, suppress
+from contextlib import contextmanager
 
 from django.apps import AppConfig
 from django.apps.registry import Apps, apps as global_apps
@@ -338,9 +338,11 @@ class StateApps(Apps):
         self.clear_cache()
 
     def unregister_model(self, app_label, model_name):
-        with suppress(KeyError):
+        try:
             del self.all_models[app_label][model_name]
             del self.app_configs[app_label].models[model_name]
+        except KeyError:
+            pass
 
 
 class ModelState:

+ 3 - 2
django/db/migrations/writer.py

@@ -1,6 +1,5 @@
 import os
 import re
-from contextlib import suppress
 from importlib import import_module
 
 from django import get_version
@@ -223,8 +222,10 @@ class MigrationWriter:
         except ImportError:
             pass
         else:
-            with suppress(ValueError):
+            try:
                 return module_dir(migrations_module)
+            except ValueError:
+                pass
 
         # Alright, see if it's a direct submodule of the app
         app_config = apps.get_app_config(self.migration.app_label)

+ 3 - 2
django/db/models/expressions.py

@@ -1,6 +1,5 @@
 import copy
 import datetime
-from contextlib import suppress
 from decimal import Decimal
 
 from django.core.exceptions import EmptyResultSet, FieldError
@@ -17,9 +16,11 @@ class SQLiteNumericMixin:
     """
     def as_sqlite(self, compiler, connection, **extra_context):
         sql, params = self.as_sql(compiler, connection, **extra_context)
-        with suppress(FieldError):
+        try:
             if self.output_field.get_internal_type() == 'DecimalField':
                 sql = 'CAST(%s AS NUMERIC)' % sql
+        except FieldError:
+            pass
         return sql, params
 
 

+ 12 - 5
django/db/models/options.py

@@ -3,7 +3,6 @@ import inspect
 import warnings
 from bisect import bisect
 from collections import OrderedDict, defaultdict
-from contextlib import suppress
 
 from django.apps import apps
 from django.conf import settings
@@ -269,8 +268,10 @@ class Options:
         # is a cached property, and all the models haven't been loaded yet, so
         # we need to make sure we don't cache a string reference.
         if field.is_relation and hasattr(field.remote_field, 'model') and field.remote_field.model:
-            with suppress(AttributeError):
+            try:
                 field.remote_field.model._meta._expire_cache(forward=False)
+            except AttributeError:
+                pass
             self._expire_cache()
         else:
             self._expire_cache(reverse=False)
@@ -518,8 +519,10 @@ class Options:
             # Due to the way Django's internals work, get_field() should also
             # be able to fetch a field by attname. In the case of a concrete
             # field with relation, includes the *_id name too
-            with suppress(AttributeError):
+            try:
                 res[field.attname] = field
+            except AttributeError:
+                pass
         return res
 
     @cached_property
@@ -531,8 +534,10 @@ class Options:
             # Due to the way Django's internals work, get_field() should also
             # be able to fetch a field by attname. In the case of a concrete
             # field with relation, includes the *_id name too
-            with suppress(AttributeError):
+            try:
                 res[field.attname] = field
+            except AttributeError:
+                pass
         return res
 
     def get_field(self, field_name):
@@ -749,10 +754,12 @@ class Options:
         # Creates a cache key composed of all arguments
         cache_key = (forward, reverse, include_parents, include_hidden, topmost_call)
 
-        with suppress(KeyError):
+        try:
             # In order to avoid list manipulation. Always return a shallow copy
             # of the results.
             return self._get_fields_cache[cache_key]
+        except KeyError:
+            pass
 
         fields = []
         # Recursively call _get_fields() on each parent, with the same

+ 7 - 3
django/db/models/query.py

@@ -7,7 +7,6 @@ import operator
 import sys
 import warnings
 from collections import OrderedDict, namedtuple
-from contextlib import suppress
 from functools import lru_cache
 from itertools import chain
 
@@ -521,8 +520,10 @@ class QuerySet:
             return obj, True
         except IntegrityError:
             exc_info = sys.exc_info()
-            with suppress(self.model.DoesNotExist):
+            try:
                 return self.get(**lookup), False
+            except self.model.DoesNotExist:
+                pass
             raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
 
     def _extract_model_params(self, defaults, **kwargs):
@@ -1337,8 +1338,11 @@ class RawQuerySet:
         # Adjust any column names which don't match field names
         for (query_name, model_name) in self.translations.items():
             # Ignore translations for nonexistent column names
-            with suppress(ValueError):
+            try:
                 index = columns.index(query_name)
+            except ValueError:
+                pass
+            else:
                 columns[index] = model_name
         return columns
 

+ 3 - 2
django/db/models/sql/query.py

@@ -7,7 +7,6 @@ databases). The abstraction barrier only works one way: this module has to know
 all about the internals of models in order to get the information it needs.
 """
 from collections import Counter, Iterator, Mapping, OrderedDict, namedtuple
-from contextlib import suppress
 from itertools import chain, count, product
 from string import ascii_uppercase
 
@@ -313,8 +312,10 @@ class Query:
             obj.subq_aliases = self.subq_aliases.copy()
         obj.used_aliases = self.used_aliases.copy()
         # Clear the cached_property
-        with suppress(AttributeError):
+        try:
             del obj.base_table
+        except AttributeError:
+            pass
         return obj
 
     def chain(self, klass=None):

+ 3 - 2
django/forms/fields.py

@@ -9,7 +9,6 @@ import math
 import os
 import re
 import uuid
-from contextlib import suppress
 from decimal import Decimal, DecimalException
 from io import BytesIO
 from urllib.parse import urlsplit, urlunsplit
@@ -1093,7 +1092,7 @@ class FilePathField(ChoiceField):
                             f = os.path.join(root, f)
                             self.choices.append((f, f.replace(path, "", 1)))
         else:
-            with suppress(OSError):
+            try:
                 for f in sorted(os.listdir(self.path)):
                     if f == '__pycache__':
                         continue
@@ -1102,6 +1101,8 @@ class FilePathField(ChoiceField):
                             (self.allow_folders and os.path.isdir(full_file))) and
                             (self.match is None or self.match_re.search(f))):
                         self.choices.append((full_file, f))
+            except OSError:
+                pass
 
         self.widget.choices = self.choices
 

+ 3 - 2
django/forms/forms.py

@@ -4,7 +4,6 @@ Form classes
 
 import copy
 from collections import OrderedDict
-from contextlib import suppress
 
 from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
 # BoundField is imported for backwards compatibility in Django 1.9
@@ -126,8 +125,10 @@ class BaseForm:
             return
         fields = OrderedDict()
         for key in field_order:
-            with suppress(KeyError):  # ignore unknown fields
+            try:
                 fields[key] = self.fields.pop(key)
+            except KeyError:  # ignore unknown fields
+                pass
         fields.update(self.fields)  # add remaining fields in original order
         self.fields = fields
 

+ 3 - 3
django/forms/formsets.py

@@ -1,5 +1,3 @@
-from contextlib import suppress
-
 from django.core.exceptions import ValidationError
 from django.forms import Form
 from django.forms.fields import BooleanField, IntegerField
@@ -162,8 +160,10 @@ class BaseFormSet:
             defaults['data'] = self.data
             defaults['files'] = self.files
         if self.initial and 'initial' not in kwargs:
-            with suppress(IndexError):
+            try:
                 defaults['initial'] = self.initial[i]
+            except IndexError:
+                pass
         # Allow extra forms to be empty, unless they're part of
         # the minimum forms.
         if i >= self.initial_form_count() and i >= self.min_num:

+ 3 - 2
django/forms/models.py

@@ -4,7 +4,6 @@ and database field objects.
 """
 
 from collections import OrderedDict
-from contextlib import suppress
 from itertools import chain
 
 from django.core.exceptions import (
@@ -615,8 +614,10 @@ class BaseModelFormSet(BaseFormSet):
                 kwargs['instance'] = self.get_queryset()[i]
         elif self.initial_extra:
             # Set initial values for extra forms
-            with suppress(IndexError):
+            try:
                 kwargs['initial'] = self.initial_extra[i - self.initial_form_count()]
+            except IndexError:
+                pass
         form = super()._construct_form(i, **kwargs)
         if pk_required:
             form.fields[self.model._meta.pk.name].required = True

+ 3 - 2
django/forms/widgets.py

@@ -6,7 +6,6 @@ import copy
 import datetime
 import re
 import warnings
-from contextlib import suppress
 from itertools import chain
 
 from django.conf import settings
@@ -651,8 +650,10 @@ class ChoiceWidget(Widget):
     def value_from_datadict(self, data, files, name):
         getter = data.get
         if self.allow_multiple_selected:
-            with suppress(AttributeError):
+            try:
                 getter = data.getlist
+            except AttributeError:
+                pass
         return getter(name)
 
     def format_value(self, value):

+ 9 - 4
django/http/response.py

@@ -3,7 +3,6 @@ import json
 import re
 import sys
 import time
-from contextlib import suppress
 from email.header import Header
 from http.client import responses
 from urllib.parse import urlparse
@@ -137,8 +136,10 @@ class HttpResponseBase:
         self._headers[header.lower()] = (header, value)
 
     def __delitem__(self, header):
-        with suppress(KeyError):
+        try:
             del self._headers[header.lower()]
+        except KeyError:
+            pass
 
     def __getitem__(self, header):
         return self._headers[header.lower()][1]
@@ -237,8 +238,10 @@ class HttpResponseBase:
     # See http://blog.dscpl.com.au/2012/10/obligations-for-calling-close-on.html
     def close(self):
         for closable in self._closable_objects:
-            with suppress(Exception):
+            try:
                 closable.close()
+            except Exception:
+                pass
         self.closed = True
         signals.request_finished.send(sender=self._handler_class)
 
@@ -304,8 +307,10 @@ class HttpResponse(HttpResponseBase):
         if hasattr(value, '__iter__') and not isinstance(value, (bytes, str)):
             content = b''.join(self.make_bytes(chunk) for chunk in value)
             if hasattr(value, 'close'):
-                with suppress(Exception):
+                try:
                     value.close()
+                except Exception:
+                    pass
         else:
             content = self.make_bytes(value)
         # Create a list of properly encoded bytestrings to support write().

+ 5 - 6
django/template/backends/base.py

@@ -1,5 +1,3 @@
-from contextlib import suppress
-
 from django.core.exceptions import (
     ImproperlyConfigured, SuspiciousFileOperation,
 )
@@ -75,8 +73,9 @@ class BaseEngine:
         directory traversal attacks.
         """
         for template_dir in self.template_dirs:
-            # SuspiciousFileOperation occurs if the jointed path is located
-            # outside of this template_dir (it might be inside another one,
-            # so this isn't fatal).
-            with suppress(SuspiciousFileOperation):
+            try:
                 yield safe_join(template_dir, template_name)
+            except SuspiciousFileOperation:
+                # The joined path was located outside of this template_dir
+                # (it might be inside another one, so this isn't fatal).
+                pass

+ 6 - 3
django/template/defaultfilters.py

@@ -1,7 +1,6 @@
 """Default variable filters."""
 import random as random_module
 import re
-from contextlib import suppress
 from decimal import ROUND_HALF_UP, Context, Decimal, InvalidOperation
 from functools import wraps
 from operator import itemgetter
@@ -609,7 +608,7 @@ def unordered_list(value, autoescape=True):
 
     def walk_items(item_list):
         item_iterator = iter(item_list)
-        with suppress(StopIteration):
+        try:
             item = next(item_iterator)
             while True:
                 try:
@@ -628,6 +627,8 @@ def unordered_list(value, autoescape=True):
                         continue
                 yield item, None
                 item = next_item
+        except StopIteration:
+            pass
 
     def list_formatter(item_list, tabs=1):
         indent = '\t' * tabs
@@ -877,9 +878,11 @@ def pluralize(value, arg='s'):
     except ValueError:  # Invalid string that's not a number.
         pass
     except TypeError:  # Value isn't a string or a number; maybe it's a list?
-        with suppress(TypeError):  # len() of unsized object.
+        try:
             if len(value) != 1:
                 return plural_suffix
+        except TypeError:  # len() of unsized object.
+            pass
     return singular_suffix
 
 

+ 9 - 4
django/test/signals.py

@@ -2,7 +2,6 @@ import os
 import threading
 import time
 import warnings
-from contextlib import suppress
 
 from django.apps import apps
 from django.core.exceptions import ImproperlyConfigured
@@ -64,10 +63,14 @@ def update_connections_time_zone(**kwargs):
     # Reset the database connections' time zone
     if kwargs['setting'] in {'TIME_ZONE', 'USE_TZ'}:
         for conn in connections.all():
-            with suppress(AttributeError):
+            try:
                 del conn.timezone
-            with suppress(AttributeError):
+            except AttributeError:
+                pass
+            try:
                 del conn.timezone_name
+            except AttributeError:
+                pass
             conn.ensure_timezone()
 
 
@@ -86,8 +89,10 @@ def reset_template_engines(**kwargs):
         'INSTALLED_APPS',
     }:
         from django.template import engines
-        with suppress(AttributeError):
+        try:
             del engines.templates
+        except AttributeError:
+            pass
         engines._templates = None
         engines._engines = {}
         from django.template.engine import Engine

+ 6 - 3
django/urls/base.py

@@ -1,4 +1,3 @@
-from contextlib import suppress
 from threading import local
 from urllib.parse import urlsplit, urlunsplit
 
@@ -54,7 +53,7 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
             ns = path.pop()
             current_ns = current_path.pop() if current_path else None
             # Lookup the name to see if it could be an app identifier.
-            with suppress(KeyError):
+            try:
                 app_list = resolver.app_dict[ns]
                 # Yes! Path part matches an app in the current Resolver.
                 if current_ns and current_ns in app_list:
@@ -65,6 +64,8 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None):
                     # The name isn't shared by one of the instances (i.e.,
                     # the default) so pick the first instance as the default.
                     ns = app_list[0]
+            except KeyError:
+                pass
 
             if ns != current_ns:
                 current_path = None
@@ -118,8 +119,10 @@ def clear_script_prefix():
     """
     Unset the script prefix for the current thread.
     """
-    with suppress(AttributeError):
+    try:
         del _prefixes.value
+    except AttributeError:
+        pass
 
 
 def set_urlconf(urlconf_name):

+ 15 - 6
django/utils/autoreload.py

@@ -34,7 +34,6 @@ import subprocess
 import sys
 import time
 import traceback
-from contextlib import suppress
 
 import _thread
 
@@ -44,8 +43,10 @@ from django.core.signals import request_finished
 
 # This import does nothing, but it's necessary to avoid some race conditions
 # in the threading module. See http://code.djangoproject.com/ticket/2330 .
-with suppress(ImportError):
+try:
     import threading  # NOQA
+except ImportError:
+    pass
 
 try:
     import termios
@@ -53,7 +54,7 @@ except ImportError:
     termios = None
 
 USE_INOTIFY = False
-with suppress(ImportError):
+try:
     # Test whether inotify is enabled and likely to work
     import pyinotify
 
@@ -61,6 +62,8 @@ with suppress(ImportError):
     if fd >= 0:
         USE_INOTIFY = True
         os.close(fd)
+except ImportError:
+    pass
 
 RUN_RELOADER = True
 
@@ -207,8 +210,10 @@ def code_changed():
             continue
         if mtime != _mtimes[filename]:
             _mtimes = {}
-            with suppress(ValueError):
+            try:
                 del _error_files[_error_files.index(filename)]
+            except ValueError:
+                pass
             return I18N_MODIFIED if filename.endswith('.mo') else FILE_MODIFIED
     return False
 
@@ -287,15 +292,19 @@ def restart_with_reloader():
 def python_reloader(main_func, args, kwargs):
     if os.environ.get("RUN_MAIN") == "true":
         _thread.start_new_thread(main_func, args, kwargs)
-        with suppress(KeyboardInterrupt):
+        try:
             reloader_thread()
+        except KeyboardInterrupt:
+            pass
     else:
-        with suppress(KeyboardInterrupt):
+        try:
             exit_code = restart_with_reloader()
             if exit_code < 0:
                 os.kill(os.getpid(), -exit_code)
             else:
                 sys.exit(exit_code)
+        except KeyboardInterrupt:
+            pass
 
 
 def jython_reloader(main_func, args, kwargs):

+ 3 - 2
django/utils/datastructures.py

@@ -1,6 +1,5 @@
 import copy
 from collections import OrderedDict
-from contextlib import suppress
 
 
 class OrderedSet:
@@ -19,8 +18,10 @@ class OrderedSet:
         del self.dict[item]
 
     def discard(self, item):
-        with suppress(KeyError):
+        try:
             self.remove(item)
+        except KeyError:
+            pass
 
     def __iter__(self):
         return iter(self.dict)

+ 7 - 4
django/utils/dateformat.py

@@ -14,7 +14,6 @@ import calendar
 import datetime
 import re
 import time
-from contextlib import suppress
 
 from django.utils.dates import (
     MONTHS, MONTHS_3, MONTHS_ALT, MONTHS_AP, WEEKDAYS, WEEKDAYS_ABBR,
@@ -82,9 +81,11 @@ class TimeFormat(Formatter):
         if not self.timezone:
             return ""
 
-        with suppress(NotImplementedError):
+        try:
             if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
                 return self.data.tzname() or ''
+        except NotImplementedError:
+            pass
         return ""
 
     def f(self):
@@ -165,11 +166,13 @@ class TimeFormat(Formatter):
             return ""
 
         name = None
-        with suppress(Exception):
+        try:
+            name = self.timezone.tzname(self.data)
+        except Exception:
             # pytz raises AmbiguousTimeError during the autumn DST change.
             # This happens mainly when __init__ receives a naive datetime
             # and sets self.timezone = get_default_timezone().
-            name = self.timezone.tzname(self.data)
+            pass
         if name is None:
             name = self.format('O')
         return str(name)

+ 6 - 3
django/utils/formats.py

@@ -1,7 +1,6 @@
 import datetime
 import decimal
 import unicodedata
-from contextlib import suppress
 from importlib import import_module
 
 from django.conf import settings
@@ -80,8 +79,10 @@ def iter_format_modules(lang, format_module_path=None):
         locales.append(locale.split('_')[0])
     for location in format_locations:
         for loc in locales:
-            with suppress(ImportError):
+            try:
                 yield import_module('%s.formats' % (location % loc))
+            except ImportError:
+                pass
 
 
 def get_format_modules(lang=None, reverse=False):
@@ -109,8 +110,10 @@ def get_format(format_type, lang=None, use_l10n=None):
     if use_l10n and lang is None:
         lang = get_language()
     cache_key = (format_type, lang)
-    with suppress(KeyError):
+    try:
         return _format_cache[cache_key]
+    except KeyError:
+        pass
 
     # The requested format_type has not been cached yet. Try to find it in any
     # of the format_modules for the given lang if l10n is enabled. If it's not

+ 3 - 2
django/utils/http.py

@@ -5,7 +5,6 @@ import re
 import unicodedata
 import warnings
 from binascii import Error as BinasciiError
-from contextlib import suppress
 from email.utils import formatdate
 from urllib.parse import (
     ParseResult, SplitResult, _coerce_args, _splitnetloc, _splitparams, quote,
@@ -166,8 +165,10 @@ def parse_http_date_safe(date):
     """
     Same as parse_http_date, but return None if the input is invalid.
     """
-    with suppress(Exception):
+    try:
         return parse_http_date(date)
+    except Exception:
+        pass
 
 
 # Base 36 functions: useful for generating compact URLs

+ 5 - 3
django/utils/translation/__init__.py

@@ -3,7 +3,7 @@ Internationalization support.
 """
 import re
 import warnings
-from contextlib import ContextDecorator, suppress
+from contextlib import ContextDecorator
 
 from django.utils.deprecation import RemovedInDjango21Warning
 from django.utils.functional import lazy
@@ -126,9 +126,11 @@ def lazy_number(func, resultclass, number=None, **kwargs):
                     number_value = rhs
                 kwargs['number'] = number_value
                 translated = func(**kwargs)
-                # String may not contain a placeholder for the number.
-                with suppress(TypeError):
+                try:
                     translated = translated % rhs
+                except TypeError:
+                    # String doesn't contain a placeholder for the number.
+                    pass
                 return translated
 
         proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs)

+ 9 - 4
django/utils/translation/trans_real.py

@@ -6,7 +6,6 @@ import re
 import sys
 import warnings
 from collections import OrderedDict
-from contextlib import suppress
 from threading import local
 
 from django.apps import apps
@@ -257,8 +256,10 @@ def get_language():
     """Return the currently selected language."""
     t = getattr(_active, "value", None)
     if t is not None:
-        with suppress(AttributeError):
+        try:
             return t.to_language()
+        except AttributeError:
+            pass
     # If we don't have a real translation object, assume it's the default language.
     return settings.LANGUAGE_CODE
 
@@ -424,8 +425,10 @@ def get_supported_language_variant(lang_code, strict=False):
     if lang_code:
         # If 'fr-ca' is not supported, try special fallback or language-only 'fr'.
         possible_lang_codes = [lang_code]
-        with suppress(KeyError):
+        try:
             possible_lang_codes.extend(LANG_INFO[lang_code]['fallback'])
+        except KeyError:
+            pass
         generic_lang_code = lang_code.split('-')[0]
         possible_lang_codes.append(generic_lang_code)
         supported_lang_codes = get_languages()
@@ -483,8 +486,10 @@ def get_language_from_request(request, check_path=False):
 
     lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
 
-    with suppress(LookupError):
+    try:
         return get_supported_language_variant(lang_code)
+    except LookupError:
+        pass
 
     accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
     for accept_lang, unused in parse_accept_lang_header(accept):

+ 6 - 3
django/views/debug.py

@@ -2,7 +2,6 @@ import functools
 import re
 import sys
 import types
-from contextlib import suppress
 from pathlib import Path
 
 from django.conf import settings
@@ -348,14 +347,18 @@ class ExceptionReporter:
         """
         source = None
         if loader is not None and hasattr(loader, "get_source"):
-            with suppress(ImportError):
+            try:
                 source = loader.get_source(module_name)
+            except ImportError:
+                pass
             if source is not None:
                 source = source.splitlines()
         if source is None:
-            with suppress(OSError, IOError):
+            try:
                 with open(filename, 'rb') as fp:
                     source = fp.read().splitlines()
+            except (OSError, IOError):
+                pass
         if source is None:
             return None, [], None, []
 

+ 6 - 3
tests/admin_scripts/tests.py

@@ -12,7 +12,6 @@ import subprocess
 import sys
 import tempfile
 import unittest
-from contextlib import suppress
 from io import StringIO
 from unittest import mock
 
@@ -96,10 +95,12 @@ class AdminScriptTestCase(unittest.TestCase):
 
         # Also try to remove the compiled file; if it exists, it could
         # mess up later tests that depend upon the .py file not existing
-        with suppress(OSError):
+        try:
             if sys.platform.startswith('java'):
                 # Jython produces module$py.class files
                 os.remove(re.sub(r'\.py$', '$py.class', full_name))
+        except OSError:
+            pass
         # Also remove a __pycache__ directory, if it exists
         cache_name = os.path.join(self.test_dir, '__pycache__')
         if os.path.isdir(cache_name):
@@ -165,8 +166,10 @@ class AdminScriptTestCase(unittest.TestCase):
 
     def run_manage(self, args, settings_file=None):
         def safe_remove(path):
-            with suppress(OSError):
+            try:
                 os.remove(path)
+            except OSError:
+                pass
 
         conf_dir = os.path.dirname(conf.__file__)
         template_manage_py = os.path.join(conf_dir, 'project_template', 'manage.py-tpl')

+ 3 - 2
tests/backends/tests.py

@@ -3,7 +3,6 @@ import datetime
 import threading
 import unittest
 import warnings
-from contextlib import suppress
 
 from django.core.management.color import no_style
 from django.db import (
@@ -390,8 +389,10 @@ class BackendTestCase(TransactionTestCase):
         finally:
             # Clean up the mess created by connection._close(). Since the
             # connection is already closed, this crashes on some backends.
-            with suppress(Exception):
+            try:
                 connection.close()
+            except Exception:
+                pass
 
     @override_settings(DEBUG=True)
     def test_queries(self):

+ 3 - 2
tests/bash_completion/tests.py

@@ -4,7 +4,6 @@ A series of tests to establish that the command-line bash completion works.
 import os
 import sys
 import unittest
-from contextlib import suppress
 
 from django.apps import apps
 from django.core.management import ManagementUtility
@@ -51,8 +50,10 @@ class BashCompletionTests(unittest.TestCase):
     def _run_autocomplete(self):
         util = ManagementUtility(argv=sys.argv)
         with captured_stdout() as stdout:
-            with suppress(SystemExit):
+            try:
                 util.autocomplete()
+            except SystemExit:
+                pass
         return stdout.getvalue().strip().split('\n')
 
     def test_django_admin_py(self):

+ 3 - 3
tests/handlers/views.py

@@ -1,12 +1,12 @@
-from contextlib import suppress
-
 from django.core.exceptions import SuspiciousOperation
 from django.db import connection, transaction
 from django.http import HttpResponse, StreamingHttpResponse
 from django.views.decorators.csrf import csrf_exempt
 
-with suppress(ImportError):  # Python < 3.5
+try:
     from http import HTTPStatus
+except ImportError:  # Python < 3.5
+    pass
 
 
 def regular(request):

+ 5 - 4
tests/mail/tests.py

@@ -8,7 +8,6 @@ import socket
 import sys
 import tempfile
 import threading
-from contextlib import suppress
 from email import message_from_binary_file, message_from_bytes
 from email.header import Header
 from email.mime.text import MIMEText
@@ -1135,10 +1134,12 @@ class ConsoleBackendTests(BaseEmailBackendTests, SimpleTestCase):
 class FakeSMTPChannel(smtpd.SMTPChannel):
 
     def collect_incoming_data(self, data):
-        # Ignore decode error in SSL/TLS connection tests as the test only
-        # cares whether the connection attempt was made.
-        with suppress(UnicodeDecodeError):
+        try:
             smtpd.SMTPChannel.collect_incoming_data(self, data)
+        except UnicodeDecodeError:
+            # Ignore decode error in SSL/TLS connection tests as the test only
+            # cares whether the connection attempt was made.
+            pass
 
     def smtp_AUTH(self, arg):
         if arg == 'CRAM-MD5':

+ 3 - 2
tests/postgres_tests/test_aggregates.py

@@ -1,5 +1,4 @@
 import json
-from contextlib import suppress
 
 from django.db.models.expressions import F, Value
 from django.test.testcases import skipUnlessDBFeature
@@ -8,12 +7,14 @@ from django.test.utils import Approximate
 from . import PostgreSQLTestCase
 from .models import AggregateTestModel, StatTestModel
 
-with suppress(ImportError):  # psycopg2 is not installed
+try:
     from django.contrib.postgres.aggregates import (
         ArrayAgg, BitAnd, BitOr, BoolAnd, BoolOr, Corr, CovarPop, JSONBAgg,
         RegrAvgX, RegrAvgY, RegrCount, RegrIntercept, RegrR2, RegrSlope,
         RegrSXX, RegrSXY, RegrSYY, StatAggregate, StringAgg,
     )
+except ImportError:
+    pass  # psycopg2 is not installed
 
 
 class TestGeneralAggregate(PostgreSQLTestCase):

+ 3 - 2
tests/postgres_tests/test_array.py

@@ -2,7 +2,6 @@ import decimal
 import json
 import unittest
 import uuid
-from contextlib import suppress
 
 from django import forms
 from django.core import exceptions, serializers, validators
@@ -20,11 +19,13 @@ from .models import (
     PostgreSQLModel, Tag,
 )
 
-with suppress(ImportError):
+try:
     from django.contrib.postgres.fields import ArrayField
     from django.contrib.postgres.forms import (
         SimpleArrayField, SplitArrayField, SplitArrayWidget,
     )
+except ImportError:
+    pass
 
 
 class TestSaveLoad(PostgreSQLTestCase):

+ 3 - 2
tests/postgres_tests/test_hstore.py

@@ -1,5 +1,4 @@
 import json
-from contextlib import suppress
 
 from django.core import exceptions, serializers
 from django.forms import Form
@@ -8,10 +7,12 @@ from django.test.utils import modify_settings
 from . import PostgreSQLTestCase
 from .models import HStoreModel
 
-with suppress(ImportError):
+try:
     from django.contrib.postgres import forms
     from django.contrib.postgres.fields import HStoreField
     from django.contrib.postgres.validators import KeysValidator
+except ImportError:
+    pass
 
 
 @modify_settings(INSTALLED_APPS={'append': 'django.contrib.postgres'})

+ 3 - 2
tests/postgres_tests/test_json.py

@@ -1,6 +1,5 @@
 import datetime
 import uuid
-from contextlib import suppress
 from decimal import Decimal
 
 from django.core import exceptions, serializers
@@ -12,9 +11,11 @@ from django.utils.html import escape
 from . import PostgreSQLTestCase
 from .models import JSONModel
 
-with suppress(ImportError):
+try:
     from django.contrib.postgres import forms
     from django.contrib.postgres.fields import JSONField
+except ImportError:
+    pass
 
 
 @skipUnlessDBFeature('has_jsonb_datatype')

+ 3 - 2
tests/postgres_tests/test_ranges.py

@@ -1,6 +1,5 @@
 import datetime
 import json
-from contextlib import suppress
 
 from django import forms
 from django.core import exceptions, serializers
@@ -11,12 +10,14 @@ from django.utils import timezone
 from . import PostgreSQLTestCase
 from .models import RangeLookupsModel, RangesModel
 
-with suppress(ImportError):
+try:
     from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange
     from django.contrib.postgres import fields as pg_fields, forms as pg_forms
     from django.contrib.postgres.validators import (
         RangeMaxValueValidator, RangeMinValueValidator,
     )
+except ImportError:
+    pass
 
 
 class TestSaveLoad(PostgreSQLTestCase):

+ 6 - 3
tests/runtests.py

@@ -8,7 +8,6 @@ import subprocess
 import sys
 import tempfile
 import warnings
-from contextlib import suppress
 
 import django
 from django.apps import apps
@@ -316,8 +315,10 @@ def bisect_tests(bisection_label, options, test_labels, parallel):
     # Make sure the bisection point isn't in the test list
     # Also remove tests that need to be run in specific combinations
     for label in [bisection_label, 'model_inheritance_same_model_name']:
-        with suppress(ValueError):
+        try:
             test_labels.remove(label)
+        except ValueError:
+            pass
 
     subprocess_args = get_subprocess_args(options)
 
@@ -365,8 +366,10 @@ def paired_tests(paired_test, options, test_labels, parallel):
     # Make sure the constant member of the pair isn't in the test list
     # Also remove tests that need to be run in specific combinations
     for label in [paired_test, 'model_inheritance_same_model_name']:
-        with suppress(ValueError):
+        try:
             test_labels.remove(label)
+        except ValueError:
+            pass
 
     subprocess_args = get_subprocess_args(options)
 

+ 3 - 2
tests/staticfiles_tests/storage.py

@@ -1,5 +1,4 @@
 import os
-from contextlib import suppress
 from datetime import datetime, timedelta
 
 from django.conf import settings
@@ -49,8 +48,10 @@ class PathNotImplementedStorage(storage.Storage):
 
     def delete(self, name):
         name = self._path(name)
-        with suppress(FileNotFoundError):
+        try:
             os.remove(name)
+        except FileNotFoundError:
+            pass
 
     def path(self, name):
         raise NotImplementedError

+ 24 - 10
tests/transaction_hooks/tests.py

@@ -1,5 +1,3 @@
-from contextlib import suppress
-
 from django.db import connection, transaction
 from django.test import TransactionTestCase, skipUnlessDBFeature
 
@@ -50,10 +48,12 @@ class TestConnectionOnCommit(TransactionTestCase):
         self.assertDone([1])
 
     def test_does_not_execute_if_transaction_rolled_back(self):
-        with suppress(ForcedError):
+        try:
             with transaction.atomic():
                 self.do(1)
                 raise ForcedError()
+        except ForcedError:
+            pass
 
         self.assertDone([])
 
@@ -71,10 +71,12 @@ class TestConnectionOnCommit(TransactionTestCase):
             with transaction.atomic():
                 self.do(1)
             # one failed savepoint
-            with suppress(ForcedError):
+            try:
                 with transaction.atomic():
                     self.do(2)
                     raise ForcedError()
+            except ForcedError:
+                pass
             # another successful savepoint
             with transaction.atomic():
                 self.do(3)
@@ -84,21 +86,25 @@ class TestConnectionOnCommit(TransactionTestCase):
 
     def test_no_hooks_run_from_failed_transaction(self):
         """If outer transaction fails, no hooks from within it run."""
-        with suppress(ForcedError):
+        try:
             with transaction.atomic():
                 with transaction.atomic():
                     self.do(1)
                 raise ForcedError()
+        except ForcedError:
+            pass
 
         self.assertDone([])
 
     def test_inner_savepoint_rolled_back_with_outer(self):
         with transaction.atomic():
-            with suppress(ForcedError):
+            try:
                 with transaction.atomic():
                     with transaction.atomic():
                         self.do(1)
                     raise ForcedError()
+            except ForcedError:
+                pass
             self.do(2)
 
         self.assertDone([2])
@@ -107,9 +113,11 @@ class TestConnectionOnCommit(TransactionTestCase):
         with transaction.atomic():
             with transaction.atomic():
                 self.do(1)
-                with suppress(ForcedError):
+                try:
                     with transaction.atomic(savepoint=False):
                         raise ForcedError()
+                except ForcedError:
+                    pass
 
         self.assertDone([])
 
@@ -117,9 +125,11 @@ class TestConnectionOnCommit(TransactionTestCase):
         with transaction.atomic():
             with transaction.atomic():
                 self.do(1)
-                with suppress(ForcedError):
+                try:
                     with transaction.atomic():
                         raise ForcedError()
+                except ForcedError:
+                    pass
 
         self.assertDone([1])
 
@@ -141,10 +151,12 @@ class TestConnectionOnCommit(TransactionTestCase):
         self.assertDone([1, 2])  # not [1, 1, 2]
 
     def test_hooks_cleared_after_rollback(self):
-        with suppress(ForcedError):
+        try:
             with transaction.atomic():
                 self.do(1)
                 raise ForcedError()
+        except ForcedError:
+            pass
 
         with transaction.atomic():
             self.do(2)
@@ -165,9 +177,11 @@ class TestConnectionOnCommit(TransactionTestCase):
         self.assertDone([2])
 
     def test_error_in_hook_doesnt_prevent_clearing_hooks(self):
-        with suppress(ForcedError):
+        try:
             with transaction.atomic():
                 transaction.on_commit(lambda: self.notify('error'))
+        except ForcedError:
+            pass
 
         with transaction.atomic():
             self.do(1)