summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMads Jensen <mje@inducks.org>2017-03-09 16:17:41 +0100
committerTim Graham <timograham@gmail.com>2017-06-28 14:07:55 -0400
commit550cb3a365dee4edfdd1563224d5304de2a57fda (patch)
treefb532f38774ff7619edd2a4532c3daae1ee0ac5a
parent43a4835edf32c57eb74c0eb207c276734a34abcf (diff)
Fixed #27818 -- Replaced try/except/pass with contextlib.suppress().
-rw-r--r--django/contrib/admin/models.py5
-rw-r--r--django/contrib/admin/sites.py9
-rw-r--r--django/contrib/auth/middleware.py6
-rw-r--r--django/contrib/contenttypes/fields.py5
-rw-r--r--django/contrib/contenttypes/models.py5
-rw-r--r--django/contrib/contenttypes/views.py10
-rw-r--r--django/contrib/gis/db/backends/spatialite/schema.py10
-rw-r--r--django/contrib/gis/db/models/fields.py5
-rw-r--r--django/contrib/gis/gdal/layer.py5
-rw-r--r--django/contrib/gis/geos/factory.py5
-rw-r--r--django/contrib/gis/utils/__init__.py8
-rw-r--r--django/contrib/messages/storage/cookie.py5
-rw-r--r--django/contrib/sessions/backends/base.py5
-rw-r--r--django/contrib/sessions/backends/file.py10
-rw-r--r--django/contrib/sitemaps/__init__.py9
-rw-r--r--django/contrib/sites/models.py10
-rw-r--r--django/contrib/staticfiles/management/commands/collectstatic.py5
-rw-r--r--django/contrib/syndication/views.py9
-rw-r--r--django/core/cache/backends/filebased.py15
-rw-r--r--django/core/cache/backends/locmem.py20
-rw-r--r--django/core/files/move.py10
-rw-r--r--django/core/files/storage.py19
-rw-r--r--django/core/management/__init__.py13
-rw-r--r--django/core/management/base.py9
-rw-r--r--django/core/management/commands/flush.py5
-rw-r--r--django/core/management/commands/shell.py9
-rw-r--r--django/core/validators.py10
-rw-r--r--django/db/backends/postgresql/client.py9
-rw-r--r--django/db/backends/sqlite3/operations.py9
-rw-r--r--django/db/migrations/autodetector.py5
-rw-r--r--django/db/migrations/questioner.py5
-rw-r--r--django/db/migrations/state.py6
-rw-r--r--django/db/migrations/writer.py5
-rw-r--r--django/db/models/expressions.py5
-rw-r--r--django/db/models/options.py17
-rw-r--r--django/db/models/query.py11
-rw-r--r--django/forms/fields.py5
-rw-r--r--django/forms/forms.py5
-rw-r--r--django/forms/formsets.py6
-rw-r--r--django/forms/models.py5
-rw-r--r--django/forms/widgets.py10
-rw-r--r--django/http/response.py13
-rw-r--r--django/template/backends/base.py11
-rw-r--r--django/template/defaultfilters.py9
-rw-r--r--django/test/signals.py13
-rw-r--r--django/urls/base.py9
-rw-r--r--django/utils/autoreload.py21
-rw-r--r--django/utils/datastructures.py5
-rw-r--r--django/utils/dateformat.py11
-rw-r--r--django/utils/formats.py18
-rw-r--r--django/utils/http.py5
-rw-r--r--django/utils/translation/__init__.py8
-rw-r--r--django/utils/translation/trans_real.py13
-rw-r--r--django/views/debug.py9
-rw-r--r--tests/admin_scripts/tests.py9
-rw-r--r--tests/backends/tests.py5
-rw-r--r--tests/bash_completion/tests.py5
-rw-r--r--tests/handlers/views.py6
-rw-r--r--tests/mail/tests.py9
-rw-r--r--tests/postgres_tests/test_aggregates.py5
-rw-r--r--tests/postgres_tests/test_array.py5
-rw-r--r--tests/postgres_tests/test_hstore.py5
-rw-r--r--tests/postgres_tests/test_json.py5
-rw-r--r--tests/postgres_tests/test_ranges.py5
-rwxr-xr-xtests/runtests.py9
-rw-r--r--tests/staticfiles_tests/storage.py5
-rw-r--r--tests/transaction_hooks/tests.py34
67 files changed, 223 insertions, 368 deletions
diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py
index 82b3cc0585..4443f13dac 100644
--- a/django/contrib/admin/models.py
+++ b/django/contrib/admin/models.py
@@ -1,4 +1,5 @@
import json
+from contextlib import suppress
from django.conf import settings
from django.contrib.admin.utils import quote
@@ -137,8 +138,6 @@ 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)
- try:
+ with suppress(NoReverseMatch):
return reverse(url_name, args=(quote(self.object_id),))
- except NoReverseMatch:
- pass
return None
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index 868c3f27f9..fcce8dba11 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -1,3 +1,4 @@
+from contextlib import suppress
from functools import update_wrapper
from weakref import WeakSet
@@ -427,15 +428,11 @@ class AdminSite:
'perms': perms,
}
if perms.get('change'):
- try:
+ with suppress(NoReverseMatch):
model_dict['admin_url'] = reverse('admin:%s_%s_changelist' % info, current_app=self.name)
- except NoReverseMatch:
- pass
if perms.get('add'):
- try:
+ with suppress(NoReverseMatch):
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)
diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py
index f0102c4455..0b3365cb3a 100644
--- a/django/contrib/auth/middleware.py
+++ b/django/contrib/auth/middleware.py
@@ -1,3 +1,5 @@
+from contextlib import suppress
+
from django.conf import settings
from django.contrib import auth
from django.contrib.auth import load_backend
@@ -89,10 +91,8 @@ class RemoteUserMiddleware(MiddlewareMixin):
"""
backend_str = request.session[auth.BACKEND_SESSION_KEY]
backend = auth.load_backend(backend_str)
- try:
+ with suppress(AttributeError): # Backend has no clean_username method.
username = backend.clean_username(username)
- except AttributeError: # Backend has no clean_username method.
- pass
return username
def _remove_invalid_user(self, request):
diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py
index 9394182aee..57022ad1ef 100644
--- a/django/contrib/contenttypes/fields.py
+++ b/django/contrib/contenttypes/fields.py
@@ -1,4 +1,5 @@
from collections import defaultdict
+from contextlib import suppress
from django.contrib.contenttypes.models import ContentType
from django.core import checks
@@ -237,10 +238,8 @@ class GenericForeignKey:
if ct_id is not None:
ct = self.get_content_type(id=ct_id, using=instance._state.db)
- try:
+ with suppress(ObjectDoesNotExist):
rel_obj = ct.get_object_for_this_type(pk=pk_val)
- except ObjectDoesNotExist:
- pass
setattr(instance, self.cache_attr, rel_obj)
return rel_obj
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
index ad2e0bc904..066474e49f 100644
--- a/django/contrib/contenttypes/models.py
+++ b/django/contrib/contenttypes/models.py
@@ -1,4 +1,5 @@
from collections import defaultdict
+from contextlib import suppress
from django.apps import apps
from django.db import models
@@ -38,10 +39,8 @@ class ContentTypeManager(models.Manager):
for the same model don't hit the database.
"""
opts = self._get_opts(model, for_concrete_model)
- try:
+ with suppress(KeyError):
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.
diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py
index d67f071569..c527687250 100644
--- a/django/contrib/contenttypes/views.py
+++ b/django/contrib/contenttypes/views.py
@@ -1,3 +1,5 @@
+from contextlib import suppress
+
from django.apps import apps
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.requests import RequestSite
@@ -53,12 +55,10 @@ 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:
- try:
+ with suppress(IndexError):
# 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,10 +77,8 @@ def shortcut(request, content_type_id, object_id):
# Fall back to the current site (if possible).
if object_domain is None:
- try:
+ with suppress(Site.DoesNotExist):
object_domain = Site.objects.get_current(request).domain
- except Site.DoesNotExist:
- pass
else:
# Fall back to the current request's site.
diff --git a/django/contrib/gis/db/backends/spatialite/schema.py b/django/contrib/gis/db/backends/spatialite/schema.py
index 6f4e3380db..3122b79e7e 100644
--- a/django/contrib/gis/db/backends/spatialite/schema.py
+++ b/django/contrib/gis/db/backends/spatialite/schema.py
@@ -1,3 +1,5 @@
+from contextlib import suppress
+
from django.db.backends.sqlite3.schema import DatabaseSchemaEditor
from django.db.utils import DatabaseError
@@ -89,15 +91,13 @@ class SpatialiteSchemaEditor(DatabaseSchemaEditor):
self.remove_geometry_metadata(model, field)
# Make sure all geom stuff is gone
for geom_table in self.geometry_tables:
- try:
+ with suppress(DatabaseError):
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:
- try:
+ with suppress(DatabaseError):
self.execute(
self.sql_update_geometry_columns % {
"geom_table": geom_table,
@@ -146,8 +146,6 @@ 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):
diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py
index 925087a4c7..b98c576c83 100644
--- a/django/contrib/gis/db/models/fields.py
+++ b/django/contrib/gis/db/models/fields.py
@@ -1,4 +1,5 @@
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
@@ -171,10 +172,8 @@ class BaseSpatialField(Field):
if isinstance(value, gdal.GDALRaster):
return value
elif is_candidate:
- try:
+ with suppress(GDALException):
return gdal.GDALRaster(value)
- except GDALException:
- pass
elif isinstance(value, dict):
try:
return gdal.GDALRaster(value)
diff --git a/django/contrib/gis/gdal/layer.py b/django/contrib/gis/gdal/layer.py
index fcb4d07a3d..384bc3a074 100644
--- a/django/contrib/gis/gdal/layer.py
+++ b/django/contrib/gis/gdal/layer.py
@@ -1,3 +1,4 @@
+from contextlib import suppress
from ctypes import byref, c_double
from django.contrib.gis.gdal.base import GDALBase
@@ -78,10 +79,8 @@ class Layer(GDALBase):
"""
if self._random_read:
# If the Layer supports random reading, return.
- try:
+ with suppress(GDALException):
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.
diff --git a/django/contrib/gis/geos/factory.py b/django/contrib/gis/geos/factory.py
index 3f46f259ee..46ed1f0c51 100644
--- a/django/contrib/gis/geos/factory.py
+++ b/django/contrib/gis/geos/factory.py
@@ -17,10 +17,11 @@ def fromfile(file_h):
if isinstance(buf, bytes):
try:
decoded = buf.decode()
- if wkt_regex.match(decoded) or hex_regex.match(decoded):
- return GEOSGeometry(decoded)
except UnicodeDecodeError:
pass
+ else:
+ if wkt_regex.match(decoded) or hex_regex.match(decoded):
+ return GEOSGeometry(decoded)
else:
return GEOSGeometry(buf)
diff --git a/django/contrib/gis/utils/__init__.py b/django/contrib/gis/utils/__init__.py
index e66d3b2bd2..88de2a4773 100644
--- a/django/contrib/gis/utils/__init__.py
+++ b/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
-try:
+with suppress(ImproperlyConfigured):
# LayerMapping requires DJANGO_SETTINGS_MODULE to be set,
- # so this needs to be in try/except.
+ # and ImproperlyConfigured is raised if that's not the case.
from django.contrib.gis.utils.layermapping import LayerMapping, LayerMapError # NOQA
-except ImproperlyConfigured:
- pass
diff --git a/django/contrib/messages/storage/cookie.py b/django/contrib/messages/storage/cookie.py
index 49270cac17..6d5df1af9d 100644
--- a/django/contrib/messages/storage/cookie.py
+++ b/django/contrib/messages/storage/cookie.py
@@ -1,4 +1,5 @@
import json
+from contextlib import suppress
from django.conf import settings
from django.contrib.messages.storage.base import BaseStorage, Message
@@ -153,12 +154,10 @@ class CookieStorage(BaseStorage):
if len(bits) == 2:
hash, value = bits
if constant_time_compare(hash, self._hash(value)):
- try:
+ with suppress(ValueError):
# 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
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index 64955b8bb7..3ff79b7a39 100644
--- a/django/contrib/sessions/backends/base.py
+++ b/django/contrib/sessions/backends/base.py
@@ -1,6 +1,7 @@
import base64
import logging
import string
+from contextlib import suppress
from datetime import datetime, timedelta
from django.conf import settings
@@ -262,10 +263,8 @@ class SessionBase:
"""
if value is None:
# Remove any custom expiration for this session.
- try:
+ with suppress(KeyError):
del self['_session_expiry']
- except KeyError:
- pass
return
if isinstance(value, timedelta):
value = timezone.now() + value
diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py
index 818c90e3ba..54ab4f2e4d 100644
--- a/django/contrib/sessions/backends/file.py
+++ b/django/contrib/sessions/backends/file.py
@@ -3,6 +3,7 @@ import logging
import os
import shutil
import tempfile
+from contextlib import suppress
from django.conf import settings
from django.contrib.sessions.backends.base import (
@@ -155,7 +156,7 @@ class SessionStore(SessionBase):
# See ticket #8616.
dir, prefix = os.path.split(session_file_name)
- try:
+ with suppress(OSError, IOError, EOFError):
output_file_fd, output_file_name = tempfile.mkstemp(dir=dir, prefix=prefix + '_out_')
renamed = False
try:
@@ -173,9 +174,6 @@ class SessionStore(SessionBase):
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))
@@ -184,10 +182,8 @@ class SessionStore(SessionBase):
if self.session_key is None:
return
session_key = self.session_key
- try:
+ with suppress(OSError):
os.unlink(self._key_to_file(session_key))
- except OSError:
- pass
def clean(self):
pass
diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py
index bd1139ff70..8f984ae3dc 100644
--- a/django/contrib/sitemaps/__init__.py
+++ b/django/contrib/sitemaps/__init__.py
@@ -1,3 +1,4 @@
+from contextlib import suppress
from urllib.parse import urlencode
from urllib.request import urlopen
@@ -36,11 +37,9 @@ 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:
- try:
+ with suppress(NoReverseMatch):
# 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.")
@@ -89,10 +88,8 @@ class Sitemap:
if site is None:
if django_apps.is_installed('django.contrib.sites'):
Site = django_apps.get_model('sites.Site')
- try:
+ with suppress(Site.DoesNotExist):
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 "
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
index 19f52e4487..9112efbfb5 100644
--- a/django/contrib/sites/models.py
+++ b/django/contrib/sites/models.py
@@ -1,4 +1,5 @@
import string
+from contextlib import suppress
from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.db import models
@@ -107,14 +108,11 @@ def clear_site_cache(sender, **kwargs):
"""
instance = kwargs['instance']
using = kwargs['using']
- try:
+ with suppress(KeyError):
del SITE_CACHE[instance.pk]
- except KeyError:
- pass
- try:
+
+ with suppress(KeyError, Site.DoesNotExist):
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)
diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py
index e5ae48f9fe..7e81ef19ee 100644
--- a/django/contrib/staticfiles/management/commands/collectstatic.py
+++ b/django/contrib/staticfiles/management/commands/collectstatic.py
@@ -1,5 +1,6 @@
import os
from collections import OrderedDict
+from contextlib import suppress
from django.apps import apps
from django.contrib.staticfiles.finders import get_finders
@@ -312,10 +313,8 @@ class Command(BaseCommand):
else:
self.log("Linking '%s'" % source_path, level=1)
full_path = self.storage.path(prefixed_path)
- try:
+ with suppress(OSError):
os.makedirs(os.path.dirname(full_path))
- except OSError:
- pass
try:
if os.path.lexists(full_path):
os.unlink(full_path)
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index a8b98c84ae..f0dcdb3e62 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -1,4 +1,5 @@
from calendar import timegm
+from contextlib import suppress
from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
@@ -152,17 +153,13 @@ class Feed:
title_tmp = None
if self.title_template is not None:
- try:
+ with suppress(TemplateDoesNotExist):
title_tmp = loader.get_template(self.title_template)
- except TemplateDoesNotExist:
- pass
description_tmp = None
if self.description_template is not None:
- try:
+ with suppress(TemplateDoesNotExist):
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,
diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py
index 56d2cf5b6d..09a68b34bb 100644
--- a/django/core/cache/backends/filebased.py
+++ b/django/core/cache/backends/filebased.py
@@ -7,6 +7,7 @@ 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
@@ -29,12 +30,10 @@ class FileBasedCache(BaseCache):
def get(self, key, default=None, version=None):
fname = self._key_to_file(key, version)
- try:
+ with suppress(FileNotFoundError):
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):
@@ -60,11 +59,9 @@ class FileBasedCache(BaseCache):
def _delete(self, fname):
if not fname.startswith(self._dir) or not os.path.exists(fname):
return
- try:
- os.remove(fname)
- except FileNotFoundError:
+ with suppress(FileNotFoundError):
# The file may have been removed by another process.
- pass
+ os.remove(fname)
def has_key(self, key, version=None):
fname = self._key_to_file(key, version)
@@ -93,10 +90,8 @@ class FileBasedCache(BaseCache):
def _createdir(self):
if not os.path.exists(self._dir):
- try:
+ with suppress(FileExistsError):
os.makedirs(self._dir, 0o700)
- except FileExistsError:
- pass
def _key_to_file(self, key, version=None):
"""
diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py
index cf86dcaa0c..20b6dd4212 100644
--- a/django/core/cache/backends/locmem.py
+++ b/django/core/cache/backends/locmem.py
@@ -1,8 +1,7 @@
"Thread-safe in-memory cache backend."
-
import pickle
import time
-from contextlib import contextmanager
+from contextlib import contextmanager, suppress
from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
from django.utils.synch import RWLock
@@ -51,11 +50,9 @@ class LocMemCache(BaseCache):
return default
with (self._lock.writer() if acquire_lock else dummy()):
- try:
+ with suppress(KeyError):
del self._cache[key]
del self._expire_info[key]
- except KeyError:
- pass
return default
def _set(self, key, value, timeout=DEFAULT_TIMEOUT):
@@ -90,11 +87,9 @@ class LocMemCache(BaseCache):
return True
with self._lock.writer():
- try:
+ with suppress(KeyError):
del self._cache[key]
del self._expire_info[key]
- except KeyError:
- pass
return False
def _has_expired(self, key):
@@ -112,14 +107,11 @@ class LocMemCache(BaseCache):
self._delete(k)
def _delete(self, key):
- try:
+ with suppress(KeyError):
del self._cache[key]
- except KeyError:
- pass
- try:
+
+ with suppress(KeyError):
del self._expire_info[key]
- except KeyError:
- pass
def delete(self, key, version=None):
key = self.make_key(key, version=version)
diff --git a/django/core/files/move.py b/django/core/files/move.py
index bf0f1fe4e8..310e064a2d 100644
--- a/django/core/files/move.py
+++ b/django/core/files/move.py
@@ -7,6 +7,7 @@ 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
@@ -41,17 +42,14 @@ 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
- try:
- # If the destination file exists and allow_overwrite is False then raise an IOError
+ # OSError happens with os.rename() if moving to another filesystem or when
+ # moving opened files on certain operating systems.
+ with suppress(OSError):
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:
- # This will happen 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:
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index ff51d89cfa..fa98bb198a 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -1,4 +1,5 @@
import os
+from contextlib import suppress
from datetime import datetime
from urllib.parse import urljoin
@@ -223,7 +224,10 @@ class FileSystemStorage(Storage):
# Create any intermediate directories that do not exist.
directory = os.path.dirname(full_path)
if not os.path.exists(directory):
- try:
+ # 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):
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.
@@ -234,11 +238,6 @@ 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)
@@ -294,15 +293,13 @@ 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.
- try:
+ # FileNotFoundError is raised if the file or directory was removed
+ # concurrently.
+ with suppress(FileNotFoundError):
if os.path.isdir(name):
os.rmdir(name)
else:
os.remove(name)
- except FileNotFoundError:
- # If removal fails, the file or directory may have been removed
- # concurrently.
- pass
def exists(self, name):
return os.path.exists(self.path(name))
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 872189d9f1..2599114489 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -3,6 +3,7 @@ import os
import pkgutil
import sys
from collections import OrderedDict, defaultdict
+from contextlib import suppress
from importlib import import_module
import django
@@ -258,14 +259,12 @@ 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'):
- try:
+ # Fail silently if DJANGO_SETTINGS_MODULE isn't set. The
+ # user will find out once they execute the command.
+ with suppress(ImportError):
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)
@@ -304,11 +303,9 @@ class ManagementUtility:
parser.add_argument('--settings')
parser.add_argument('--pythonpath')
parser.add_argument('args', nargs='*') # catch-all
- try:
+ with suppress(CommandError): # Ignore any option errors at this point.
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
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 41b6b0fa91..b53b414fdb 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -5,6 +5,7 @@ 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
@@ -297,12 +298,10 @@ class BaseCommand:
self.stderr.write('%s: %s' % (e.__class__.__name__, e))
sys.exit(1)
finally:
- try:
+ # Ignore if connections aren't setup at this point (e.g. no
+ # configured settings).
+ with suppress(ImproperlyConfigured):
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):
"""
diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py
index e188e4613c..3e9d9fefc9 100644
--- a/django/core/management/commands/flush.py
+++ b/django/core/management/commands/flush.py
@@ -1,3 +1,4 @@
+from contextlib import suppress
from importlib import import_module
from django.apps import apps
@@ -39,10 +40,8 @@ class Command(BaseCommand):
# Import the 'management' module within each installed app, to register
# dispatcher events.
for app_config in apps.get_app_configs():
- try:
+ with suppress(ImportError):
import_module('.management', app_config.name)
- except ImportError:
- pass
sql_list = sql_flush(self.style, connection, only_django=True,
reset_sequences=reset_sequences,
diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py
index 243680c591..1bf9197269 100644
--- a/django/core/management/commands/shell.py
+++ b/django/core/management/commands/shell.py
@@ -1,6 +1,7 @@
import os
import select
import sys
+from contextlib import suppress
from django.core.management import BaseCommand, CommandError
from django.utils.datastructures import OrderedSet
@@ -68,11 +69,9 @@ class Command(BaseCommand):
continue
if not os.path.isfile(pythonrc):
continue
- try:
+ with suppress(NameError):
with open(pythonrc) as handle:
exec(compile(handle.read(), pythonrc, 'exec'), imported_objects)
- except NameError:
- pass
code.interact(local=imported_objects)
def handle(self, **options):
@@ -90,8 +89,6 @@ class Command(BaseCommand):
available_shells = [options['interface']] if options['interface'] else self.shells
for shell in available_shells:
- try:
+ with suppress(ImportError):
return getattr(self, shell)(options)
- except ImportError:
- pass
raise CommandError("Couldn't import {} interface.".format(shell))
diff --git a/django/core/validators.py b/django/core/validators.py
index 1a36246171..bfeaa2c7dc 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -1,6 +1,7 @@
import ipaddress
import os
import re
+from contextlib import suppress
from urllib.parse import urlsplit, urlunsplit
from django.core.exceptions import ValidationError
@@ -200,10 +201,11 @@ class EmailValidator:
# Try for possible IDN domain-part
try:
domain_part = domain_part.encode('idna').decode('ascii')
- if self.validate_domain_part(domain_part):
- return
except UnicodeError:
pass
+ else:
+ if self.validate_domain_part(domain_part):
+ return
raise ValidationError(self.message, code=self.code)
def validate_domain_part(self, domain_part):
@@ -213,11 +215,9 @@ class EmailValidator:
literal_match = self.literal_regex.match(domain_part)
if literal_match:
ip_address = literal_match.group(1)
- try:
+ with suppress(ValidationError):
validate_ipv46_address(ip_address)
return True
- except ValidationError:
- pass
return False
def __eq__(self, other):
diff --git a/django/db/backends/postgresql/client.py b/django/db/backends/postgresql/client.py
index 466c2986d2..8d08b0d5cf 100644
--- a/django/db/backends/postgresql/client.py
+++ b/django/db/backends/postgresql/client.py
@@ -1,6 +1,7 @@
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
@@ -40,7 +41,9 @@ class DatabaseClient(BaseDatabaseClient):
if passwd:
# Create temporary .pgpass file.
temp_pgpass = NamedTemporaryFile(mode='w+')
- try:
+ # If the current locale can't encode the data, let the user
+ # input the password manually.
+ with suppress(UnicodeEncodeError):
print(
_escape_pgpass(host) or '*',
str(port) or '*',
@@ -52,10 +55,6 @@ class DatabaseClient(BaseDatabaseClient):
flush=True,
)
os.environ['PGPASSFILE'] = temp_pgpass.name
- except UnicodeEncodeError:
- # If the current locale can't encode the data, we 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)
diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py
index 040e148c34..5ffc65e08a 100644
--- a/django/db/backends/sqlite3/operations.py
+++ b/django/db/backends/sqlite3/operations.py
@@ -1,5 +1,6 @@
import datetime
import uuid
+from contextlib import suppress
from django.conf import settings
from django.core.exceptions import FieldError
@@ -33,7 +34,9 @@ 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():
- try:
+ # Not every subexpression has an output_field which is fine
+ # to ignore.
+ with suppress(FieldError):
output_field = expr.output_field
if isinstance(output_field, bad_fields):
raise NotImplementedError(
@@ -41,10 +44,6 @@ class DatabaseOperations(BaseDatabaseOperations):
'aggregations on date/time fields in sqlite3 '
'since date/time is saved as text.'
)
- except FieldError:
- # Not every subexpression has an output_field which is fine
- # to ignore.
- pass
def date_extract_sql(self, lookup_type, field_name):
"""
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index 3a49e26c92..2973995d40 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -1,5 +1,6 @@
import functools
import re
+from contextlib import suppress
from itertools import chain
from django.conf import settings
@@ -429,7 +430,7 @@ class MigrationAutodetector:
Place potential swappable models first in lists of created models (only
real way to solve #22783).
"""
- try:
+ with suppress(LookupError):
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])
@@ -440,8 +441,6 @@ 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):
diff --git a/django/db/migrations/questioner.py b/django/db/migrations/questioner.py
index b65a4f6709..9b5b9f3510 100644
--- a/django/db/migrations/questioner.py
+++ b/django/db/migrations/questioner.py
@@ -97,10 +97,11 @@ class InteractiveMigrationQuestioner(MigrationQuestioner):
while True:
try:
value = int(result)
- if 0 < value <= len(choices):
- return value
except ValueError:
pass
+ else:
+ if 0 < value <= len(choices):
+ return value
result = input("Please select a valid option: ")
def _ask_default(self, default=''):
diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py
index 0578badabe..3bbdf4633b 100644
--- a/django/db/migrations/state.py
+++ b/django/db/migrations/state.py
@@ -1,6 +1,6 @@
import copy
from collections import OrderedDict
-from contextlib import contextmanager
+from contextlib import contextmanager, suppress
from django.apps import AppConfig
from django.apps.registry import Apps, apps as global_apps
@@ -342,11 +342,9 @@ class StateApps(Apps):
self.clear_cache()
def unregister_model(self, app_label, model_name):
- try:
+ with suppress(KeyError):
del self.all_models[app_label][model_name]
del self.app_configs[app_label].models[model_name]
- except KeyError:
- pass
class ModelState:
diff --git a/django/db/migrations/writer.py b/django/db/migrations/writer.py
index aa296db8c5..00ff03e494 100644
--- a/django/db/migrations/writer.py
+++ b/django/db/migrations/writer.py
@@ -1,5 +1,6 @@
import os
import re
+from contextlib import suppress
from importlib import import_module
from django import get_version
@@ -222,10 +223,8 @@ class MigrationWriter:
except ImportError:
pass
else:
- try:
+ with suppress(ValueError):
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)
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 67de5adf74..fde506095c 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1,5 +1,6 @@
import copy
import datetime
+from contextlib import suppress
from django.core.exceptions import EmptyResultSet, FieldError
from django.db.backends import utils as backend_utils
@@ -577,11 +578,9 @@ class Func(Expression):
def as_sqlite(self, compiler, connection, **extra_context):
sql, params = self.as_sql(compiler, connection, **extra_context)
- try:
+ with suppress(FieldError):
if self.output_field.get_internal_type() == 'DecimalField':
sql = 'CAST(%s AS NUMERIC)' % sql
- except FieldError:
- pass
return sql, params
def copy(self):
diff --git a/django/db/models/options.py b/django/db/models/options.py
index 90462278d9..9ed2915edb 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -3,6 +3,7 @@ import inspect
import warnings
from bisect import bisect
from collections import OrderedDict, defaultdict
+from contextlib import suppress
from itertools import chain
from django.apps import apps
@@ -269,10 +270,8 @@ 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:
- try:
+ with suppress(AttributeError):
field.remote_field.model._meta._expire_cache(forward=False)
- except AttributeError:
- pass
self._expire_cache()
else:
self._expire_cache(reverse=False)
@@ -520,10 +519,8 @@ 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
- try:
+ with suppress(AttributeError):
res[field.attname] = field
- except AttributeError:
- pass
return res
@cached_property
@@ -535,10 +532,8 @@ 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
- try:
+ with suppress(AttributeError):
res[field.attname] = field
- except AttributeError:
- pass
return res
def get_field(self, field_name):
@@ -755,12 +750,10 @@ class Options:
# Creates a cache key composed of all arguments
cache_key = (forward, reverse, include_parents, include_hidden, topmost_call)
- try:
+ with suppress(KeyError):
# 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
diff --git a/django/db/models/query.py b/django/db/models/query.py
index b686fd6cab..b71e9a87d5 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -6,6 +6,7 @@ import copy
import sys
import warnings
from collections import OrderedDict, deque
+from contextlib import suppress
from django.conf import settings
from django.core import exceptions
@@ -488,10 +489,8 @@ class QuerySet:
return obj, True
except IntegrityError:
exc_info = sys.exc_info()
- try:
+ with suppress(self.model.DoesNotExist):
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):
@@ -1256,12 +1255,10 @@ class RawQuerySet:
columns = self.query.get_columns()
# Adjust any column names which don't match field names
for (query_name, model_name) in self.translations.items():
- try:
+ # Ignore translations for nonexistent column names
+ with suppress(ValueError):
index = columns.index(query_name)
columns[index] = model_name
- except ValueError:
- # Ignore translations for nonexistent column names
- pass
return columns
@cached_property
diff --git a/django/forms/fields.py b/django/forms/fields.py
index 1bc6953561..3a0609b915 100644
--- a/django/forms/fields.py
+++ b/django/forms/fields.py
@@ -8,6 +8,7 @@ import itertools
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
@@ -1086,7 +1087,7 @@ class FilePathField(ChoiceField):
f = os.path.join(root, f)
self.choices.append((f, f.replace(path, "", 1)))
else:
- try:
+ with suppress(OSError):
for f in sorted(os.listdir(self.path)):
if f == '__pycache__':
continue
@@ -1095,8 +1096,6 @@ 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
diff --git a/django/forms/forms.py b/django/forms/forms.py
index e2e7c645ff..0b434b24f8 100644
--- a/django/forms/forms.py
+++ b/django/forms/forms.py
@@ -4,6 +4,7 @@ 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
@@ -125,10 +126,8 @@ class BaseForm:
return
fields = OrderedDict()
for key in field_order:
- try:
+ with suppress(KeyError): # ignore unknown fields
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
diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index 49febc2b2e..0531d50204 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -1,3 +1,5 @@
+from contextlib import suppress
+
from django.core.exceptions import ValidationError
from django.forms import Form
from django.forms.fields import BooleanField, IntegerField
@@ -160,10 +162,8 @@ class BaseFormSet:
defaults['data'] = self.data
defaults['files'] = self.files
if self.initial and 'initial' not in kwargs:
- try:
+ with suppress(IndexError):
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:
diff --git a/django/forms/models.py b/django/forms/models.py
index f4467d2ebb..79e4452b17 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -4,6 +4,7 @@ and database field objects.
"""
from collections import OrderedDict
+from contextlib import suppress
from itertools import chain
from django.core.exceptions import (
@@ -588,10 +589,8 @@ class BaseModelFormSet(BaseFormSet):
kwargs['instance'] = self.get_queryset()[i]
if i >= self.initial_form_count() and self.initial_extra:
# Set initial values for extra forms
- try:
+ with suppress(IndexError):
kwargs['initial'] = self.initial_extra[i - self.initial_form_count()]
- except IndexError:
- pass
return super()._construct_form(i, **kwargs)
def get_queryset(self):
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 282ba0b481..599d1e8011 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -5,6 +5,7 @@ HTML Widget classes
import copy
import datetime
import re
+from contextlib import suppress
from itertools import chain
from django.conf import settings
@@ -618,10 +619,8 @@ class ChoiceWidget(Widget):
def value_from_datadict(self, data, files, name):
getter = data.get
if self.allow_multiple_selected:
- try:
+ with suppress(AttributeError):
getter = data.getlist
- except AttributeError:
- pass
return getter(name)
def format_value(self, value):
@@ -977,12 +976,13 @@ class SelectDateWidget(Widget):
year, month, day = value.year, value.month, value.day
elif isinstance(value, str):
if settings.USE_L10N:
+ input_format = get_format('DATE_INPUT_FORMATS')[0]
try:
- input_format = get_format('DATE_INPUT_FORMATS')[0]
d = datetime.datetime.strptime(value, input_format)
- year, month, day = d.year, d.month, d.day
except ValueError:
pass
+ else:
+ year, month, day = d.year, d.month, d.day
match = self.date_re.match(value)
if match:
year, month, day = [int(val) for val in match.groups()]
diff --git a/django/http/response.py b/django/http/response.py
index 1083fd7dca..384de9fb84 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -3,6 +3,7 @@ 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
@@ -136,10 +137,8 @@ class HttpResponseBase:
self._headers[header.lower()] = (header, value)
def __delitem__(self, header):
- try:
+ with suppress(KeyError):
del self._headers[header.lower()]
- except KeyError:
- pass
def __getitem__(self, header):
return self._headers[header.lower()][1]
@@ -238,10 +237,8 @@ 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:
- try:
+ with suppress(Exception):
closable.close()
- except Exception:
- pass
self.closed = True
signals.request_finished.send(sender=self._handler_class)
@@ -307,10 +304,8 @@ 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'):
- try:
+ with suppress(Exception):
value.close()
- except Exception:
- pass
else:
content = self.make_bytes(value)
# Create a list of properly encoded bytestrings to support write().
diff --git a/django/template/backends/base.py b/django/template/backends/base.py
index c47c95e51e..4156365b97 100644
--- a/django/template/backends/base.py
+++ b/django/template/backends/base.py
@@ -1,3 +1,5 @@
+from contextlib import suppress
+
from django.core.exceptions import (
ImproperlyConfigured, SuspiciousFileOperation,
)
@@ -73,9 +75,8 @@ class BaseEngine:
directory traversal attacks.
"""
for template_dir in self.template_dirs:
- try:
+ # 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):
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
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index e8e14fd923..6dafe70ba5 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -1,6 +1,7 @@
"""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
@@ -606,7 +607,7 @@ def unordered_list(value, autoescape=True):
def walk_items(item_list):
item_iterator = iter(item_list)
- try:
+ with suppress(StopIteration):
item = next(item_iterator)
while True:
try:
@@ -625,8 +626,6 @@ 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
@@ -876,11 +875,9 @@ 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?
- try:
+ with suppress(TypeError): # len() of unsized object.
if len(value) != 1:
return plural_suffix
- except TypeError: # len() of unsized object.
- pass
return singular_suffix
diff --git a/django/test/signals.py b/django/test/signals.py
index a623e756ce..3507c69add 100644
--- a/django/test/signals.py
+++ b/django/test/signals.py
@@ -2,6 +2,7 @@ import os
import threading
import time
import warnings
+from contextlib import suppress
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured
@@ -63,14 +64,10 @@ 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():
- try:
+ with suppress(AttributeError):
del conn.timezone
- except AttributeError:
- pass
- try:
+ with suppress(AttributeError):
del conn.timezone_name
- except AttributeError:
- pass
conn.ensure_timezone()
@@ -89,10 +86,8 @@ def reset_template_engines(**kwargs):
'INSTALLED_APPS',
}:
from django.template import engines
- try:
+ with suppress(AttributeError):
del engines.templates
- except AttributeError:
- pass
engines._templates = None
engines._engines = {}
from django.template.engine import Engine
diff --git a/django/urls/base.py b/django/urls/base.py
index 6dccdd2e7d..26084dbe3e 100644
--- a/django/urls/base.py
+++ b/django/urls/base.py
@@ -1,3 +1,4 @@
+from contextlib import suppress
from threading import local
from urllib.parse import urlsplit, urlunsplit
@@ -53,7 +54,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.
- try:
+ with suppress(KeyError):
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:
@@ -64,8 +65,6 @@ 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
@@ -119,10 +118,8 @@ def clear_script_prefix():
"""
Unset the script prefix for the current thread.
"""
- try:
+ with suppress(AttributeError):
del _prefixes.value
- except AttributeError:
- pass
def set_urlconf(urlconf_name):
diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py
index 2784a89aeb..a872d42d65 100644
--- a/django/utils/autoreload.py
+++ b/django/utils/autoreload.py
@@ -34,6 +34,7 @@ import subprocess
import sys
import time
import traceback
+from contextlib import suppress
import _thread
@@ -43,10 +44,8 @@ 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 .
-try:
+with suppress(ImportError):
import threading # NOQA
-except ImportError:
- pass
try:
import termios
@@ -54,7 +53,7 @@ except ImportError:
termios = None
USE_INOTIFY = False
-try:
+with suppress(ImportError):
# Test whether inotify is enabled and likely to work
import pyinotify
@@ -62,8 +61,6 @@ try:
if fd >= 0:
USE_INOTIFY = True
os.close(fd)
-except ImportError:
- pass
RUN_RELOADER = True
@@ -210,10 +207,8 @@ def code_changed():
continue
if mtime != _mtimes[filename]:
_mtimes = {}
- try:
+ with suppress(ValueError):
del _error_files[_error_files.index(filename)]
- except ValueError:
- pass
return I18N_MODIFIED if filename.endswith('.mo') else FILE_MODIFIED
return False
@@ -292,19 +287,15 @@ 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)
- try:
+ with suppress(KeyboardInterrupt):
reloader_thread()
- except KeyboardInterrupt:
- pass
else:
- try:
+ with suppress(KeyboardInterrupt):
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):
diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py
index 769637f1d3..b42f674eb0 100644
--- a/django/utils/datastructures.py
+++ b/django/utils/datastructures.py
@@ -1,5 +1,6 @@
import copy
from collections import OrderedDict
+from contextlib import suppress
class OrderedSet:
@@ -18,10 +19,8 @@ class OrderedSet:
del self.dict[item]
def discard(self, item):
- try:
+ with suppress(KeyError):
self.remove(item)
- except KeyError:
- pass
def __iter__(self):
return iter(self.dict)
diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py
index d3f586aacf..d811e83965 100644
--- a/django/utils/dateformat.py
+++ b/django/utils/dateformat.py
@@ -14,6 +14,7 @@ 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,
@@ -81,11 +82,9 @@ class TimeFormat(Formatter):
if not self.timezone:
return ""
- try:
+ with suppress(NotImplementedError):
if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
return self.data.tzname() or ''
- except NotImplementedError:
- pass
return ""
def f(self):
@@ -166,13 +165,11 @@ class TimeFormat(Formatter):
return ""
name = None
- try:
- name = self.timezone.tzname(self.data)
- except Exception:
+ with suppress(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().
- pass
+ name = self.timezone.tzname(self.data)
if name is None:
name = self.format('O')
return str(name)
diff --git a/django/utils/formats.py b/django/utils/formats.py
index b0c78f5ab2..33865d93a8 100644
--- a/django/utils/formats.py
+++ b/django/utils/formats.py
@@ -1,6 +1,7 @@
import datetime
import decimal
import unicodedata
+from contextlib import suppress
from importlib import import_module
from django.conf import settings
@@ -79,10 +80,8 @@ def iter_format_modules(lang, format_module_path=None):
locales.append(locale.split('_')[0])
for location in format_locations:
for loc in locales:
- try:
+ with suppress(ImportError):
yield import_module('%s.formats' % (location % loc))
- except ImportError:
- pass
def get_format_modules(lang=None, reverse=False):
@@ -110,10 +109,8 @@ 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)
- try:
+ with suppress(KeyError):
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
@@ -121,12 +118,9 @@ def get_format(format_type, lang=None, use_l10n=None):
val = None
if use_l10n:
for module in get_format_modules(lang):
- try:
- val = getattr(module, format_type)
- if val is not None:
- break
- except AttributeError:
- pass
+ val = getattr(module, format_type, None)
+ if val is not None:
+ break
if val is None:
if format_type not in FORMAT_SETTINGS:
return format_type
diff --git a/django/utils/http.py b/django/utils/http.py
index 07b6ae246a..0870f1f180 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -5,6 +5,7 @@ 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,
@@ -165,10 +166,8 @@ def parse_http_date_safe(date):
"""
Same as parse_http_date, but return None if the input is invalid.
"""
- try:
+ with suppress(Exception):
return parse_http_date(date)
- except Exception:
- pass
# Base 36 functions: useful for generating compact URLs
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py
index f342cf7227..4a6840782c 100644
--- a/django/utils/translation/__init__.py
+++ b/django/utils/translation/__init__.py
@@ -3,7 +3,7 @@ Internationalization support.
"""
import re
import warnings
-from contextlib import ContextDecorator
+from contextlib import ContextDecorator, suppress
from django.utils.deprecation import RemovedInDjango21Warning
from django.utils.functional import lazy
@@ -126,11 +126,9 @@ def lazy_number(func, resultclass, number=None, **kwargs):
number_value = rhs
kwargs['number'] = number_value
translated = func(**kwargs)
- try:
+ # String may not contain a placeholder for the number.
+ with suppress(TypeError):
translated = translated % rhs
- except TypeError:
- # String doesn't contain a placeholder for the number
- pass
return translated
proxy = lazy(lambda **kwargs: NumberAwareString(), NumberAwareString)(**kwargs)
diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py
index 6b3aeb127e..f36c21f0a1 100644
--- a/django/utils/translation/trans_real.py
+++ b/django/utils/translation/trans_real.py
@@ -6,6 +6,7 @@ import re
import sys
import warnings
from collections import OrderedDict
+from contextlib import suppress
from threading import local
from django.apps import apps
@@ -256,10 +257,8 @@ def get_language():
"""Return the currently selected language."""
t = getattr(_active, "value", None)
if t is not None:
- try:
+ with suppress(AttributeError):
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
@@ -425,10 +424,8 @@ 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]
- try:
+ with suppress(KeyError):
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()
@@ -486,10 +483,8 @@ def get_language_from_request(request, check_path=False):
lang_code = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME)
- try:
+ with suppress(LookupError):
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):
diff --git a/django/views/debug.py b/django/views/debug.py
index 5fa412d436..15566a25cd 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -2,6 +2,7 @@ import functools
import re
import sys
import types
+from contextlib import suppress
from pathlib import Path
from django.conf import settings
@@ -344,18 +345,14 @@ class ExceptionReporter:
"""
source = None
if loader is not None and hasattr(loader, "get_source"):
- try:
+ with suppress(ImportError):
source = loader.get_source(module_name)
- except ImportError:
- pass
if source is not None:
source = source.splitlines()
if source is None:
- try:
+ with suppress(OSError, IOError):
with open(filename, 'rb') as fp:
source = fp.read().splitlines()
- except (OSError, IOError):
- pass
if source is None:
return None, [], None, []
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index e2d2a3bca1..d90456ac13 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -12,6 +12,7 @@ import subprocess
import sys
import tempfile
import unittest
+from contextlib import suppress
from io import StringIO
from unittest import mock
@@ -95,12 +96,10 @@ 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
- try:
+ with suppress(OSError):
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):
@@ -166,10 +165,8 @@ class AdminScriptTestCase(unittest.TestCase):
def run_manage(self, args, settings_file=None):
def safe_remove(path):
- try:
+ with suppress(OSError):
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')
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index 6d38625a98..30c1cbf86d 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -3,6 +3,7 @@ import datetime
import threading
import unittest
import warnings
+from contextlib import suppress
from django.core.management.color import no_style
from django.db import (
@@ -389,10 +390,8 @@ class BackendTestCase(TransactionTestCase):
finally:
# Clean up the mess created by connection._close(). Since the
# connection is already closed, this crashes on some backends.
- try:
+ with suppress(Exception):
connection.close()
- except Exception:
- pass
@override_settings(DEBUG=True)
def test_queries(self):
diff --git a/tests/bash_completion/tests.py b/tests/bash_completion/tests.py
index 1d35e1f28e..ba2a5ea773 100644
--- a/tests/bash_completion/tests.py
+++ b/tests/bash_completion/tests.py
@@ -4,6 +4,7 @@ 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
@@ -50,10 +51,8 @@ class BashCompletionTests(unittest.TestCase):
def _run_autocomplete(self):
util = ManagementUtility(argv=sys.argv)
with captured_stdout() as stdout:
- try:
+ with suppress(SystemExit):
util.autocomplete()
- except SystemExit:
- pass
return stdout.getvalue().strip().split('\n')
def test_django_admin_py(self):
diff --git a/tests/handlers/views.py b/tests/handlers/views.py
index 22b94de3b9..3c1fa5b802 100644
--- a/tests/handlers/views.py
+++ b/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
-try:
+with suppress(ImportError): # Python < 3.5
from http import HTTPStatus
-except ImportError: # Python < 3.5
- pass
def regular(request):
diff --git a/tests/mail/tests.py b/tests/mail/tests.py
index 50922e21d7..e1a7feb1f9 100644
--- a/tests/mail/tests.py
+++ b/tests/mail/tests.py
@@ -8,6 +8,7 @@ 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
@@ -1123,12 +1124,10 @@ class ConsoleBackendTests(BaseEmailBackendTests, SimpleTestCase):
class FakeSMTPChannel(smtpd.SMTPChannel):
def collect_incoming_data(self, data):
- try:
+ # Ignore decode error in SSL/TLS connection tests as the test only
+ # cares whether the connection attempt was made.
+ with suppress(UnicodeDecodeError):
smtpd.SMTPChannel.collect_incoming_data(self, data)
- except UnicodeDecodeError:
- # ignore decode error in SSL/TLS connection tests as we only care
- # whether the connection attempt was made
- pass
def smtp_AUTH(self, arg):
if arg == 'CRAM-MD5':
diff --git a/tests/postgres_tests/test_aggregates.py b/tests/postgres_tests/test_aggregates.py
index 056d08441b..1fe8a1bf03 100644
--- a/tests/postgres_tests/test_aggregates.py
+++ b/tests/postgres_tests/test_aggregates.py
@@ -1,4 +1,5 @@
import json
+from contextlib import suppress
from django.db.models.expressions import F, Value
from django.test.testcases import skipUnlessDBFeature
@@ -7,14 +8,12 @@ from django.test.utils import Approximate
from . import PostgreSQLTestCase
from .models import AggregateTestModel, StatTestModel
-try:
+with suppress(ImportError): # psycopg2 is not installed
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):
diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py
index e2e4ccdeb2..7378b5c12d 100644
--- a/tests/postgres_tests/test_array.py
+++ b/tests/postgres_tests/test_array.py
@@ -2,6 +2,7 @@ import decimal
import json
import unittest
import uuid
+from contextlib import suppress
from django import forms
from django.core import exceptions, serializers, validators
@@ -19,13 +20,11 @@ from .models import (
PostgreSQLModel, Tag,
)
-try:
+with suppress(ImportError):
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.forms import (
SimpleArrayField, SplitArrayField, SplitArrayWidget,
)
-except ImportError:
- pass
class TestSaveLoad(PostgreSQLTestCase):
diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py
index 069e570f51..55b179ba5e 100644
--- a/tests/postgres_tests/test_hstore.py
+++ b/tests/postgres_tests/test_hstore.py
@@ -1,4 +1,5 @@
import json
+from contextlib import suppress
from django.core import exceptions, serializers
from django.forms import Form
@@ -7,12 +8,10 @@ from django.test.utils import modify_settings
from . import PostgreSQLTestCase
from .models import HStoreModel
-try:
+with suppress(ImportError):
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'})
diff --git a/tests/postgres_tests/test_json.py b/tests/postgres_tests/test_json.py
index 2506fc36d6..20650ae95b 100644
--- a/tests/postgres_tests/test_json.py
+++ b/tests/postgres_tests/test_json.py
@@ -1,5 +1,6 @@
import datetime
import uuid
+from contextlib import suppress
from decimal import Decimal
from django.core import exceptions, serializers
@@ -11,11 +12,9 @@ from django.utils.html import escape
from . import PostgreSQLTestCase
from .models import JSONModel
-try:
+with suppress(ImportError):
from django.contrib.postgres import forms
from django.contrib.postgres.fields import JSONField
-except ImportError:
- pass
@skipUnlessDBFeature('has_jsonb_datatype')
diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py
index d87ad36438..da72240bf4 100644
--- a/tests/postgres_tests/test_ranges.py
+++ b/tests/postgres_tests/test_ranges.py
@@ -1,5 +1,6 @@
import datetime
import json
+from contextlib import suppress
from django import forms
from django.core import exceptions, serializers
@@ -10,14 +11,12 @@ from django.utils import timezone
from . import PostgreSQLTestCase
from .models import RangeLookupsModel, RangesModel
-try:
+with suppress(ImportError):
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):
diff --git a/tests/runtests.py b/tests/runtests.py
index 7f4f1670c5..08e53f4cb1 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -8,6 +8,7 @@ import subprocess
import sys
import tempfile
import warnings
+from contextlib import suppress
import django
from django.apps import apps
@@ -315,10 +316,8 @@ 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']:
- try:
+ with suppress(ValueError):
test_labels.remove(label)
- except ValueError:
- pass
subprocess_args = get_subprocess_args(options)
@@ -366,10 +365,8 @@ 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']:
- try:
+ with suppress(ValueError):
test_labels.remove(label)
- except ValueError:
- pass
subprocess_args = get_subprocess_args(options)
diff --git a/tests/staticfiles_tests/storage.py b/tests/staticfiles_tests/storage.py
index 7a1f72c130..0dcfd77a70 100644
--- a/tests/staticfiles_tests/storage.py
+++ b/tests/staticfiles_tests/storage.py
@@ -1,4 +1,5 @@
import os
+from contextlib import suppress
from datetime import datetime, timedelta
from django.conf import settings
@@ -48,10 +49,8 @@ class PathNotImplementedStorage(storage.Storage):
def delete(self, name):
name = self._path(name)
- try:
+ with suppress(FileNotFoundError):
os.remove(name)
- except FileNotFoundError:
- pass
def path(self, name):
raise NotImplementedError
diff --git a/tests/transaction_hooks/tests.py b/tests/transaction_hooks/tests.py
index 000de4104c..049211139d 100644
--- a/tests/transaction_hooks/tests.py
+++ b/tests/transaction_hooks/tests.py
@@ -1,3 +1,5 @@
+from contextlib import suppress
+
from django.db import connection, transaction
from django.test import TransactionTestCase, skipUnlessDBFeature
@@ -48,12 +50,10 @@ class TestConnectionOnCommit(TransactionTestCase):
self.assertDone([1])
def test_does_not_execute_if_transaction_rolled_back(self):
- try:
+ with suppress(ForcedError):
with transaction.atomic():
self.do(1)
raise ForcedError()
- except ForcedError:
- pass
self.assertDone([])
@@ -71,12 +71,10 @@ class TestConnectionOnCommit(TransactionTestCase):
with transaction.atomic():
self.do(1)
# one failed savepoint
- try:
+ with suppress(ForcedError):
with transaction.atomic():
self.do(2)
raise ForcedError()
- except ForcedError:
- pass
# another successful savepoint
with transaction.atomic():
self.do(3)
@@ -86,25 +84,21 @@ class TestConnectionOnCommit(TransactionTestCase):
def test_no_hooks_run_from_failed_transaction(self):
"""If outer transaction fails, no hooks from within it run."""
- try:
+ with suppress(ForcedError):
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():
- try:
+ with suppress(ForcedError):
with transaction.atomic():
with transaction.atomic():
self.do(1)
raise ForcedError()
- except ForcedError:
- pass
self.do(2)
self.assertDone([2])
@@ -113,11 +107,9 @@ class TestConnectionOnCommit(TransactionTestCase):
with transaction.atomic():
with transaction.atomic():
self.do(1)
- try:
+ with suppress(ForcedError):
with transaction.atomic(savepoint=False):
raise ForcedError()
- except ForcedError:
- pass
self.assertDone([])
@@ -125,11 +117,9 @@ class TestConnectionOnCommit(TransactionTestCase):
with transaction.atomic():
with transaction.atomic():
self.do(1)
- try:
+ with suppress(ForcedError):
with transaction.atomic():
raise ForcedError()
- except ForcedError:
- pass
self.assertDone([1])
@@ -151,12 +141,10 @@ class TestConnectionOnCommit(TransactionTestCase):
self.assertDone([1, 2]) # not [1, 1, 2]
def test_hooks_cleared_after_rollback(self):
- try:
+ with suppress(ForcedError):
with transaction.atomic():
self.do(1)
raise ForcedError()
- except ForcedError:
- pass
with transaction.atomic():
self.do(2)
@@ -177,11 +165,9 @@ class TestConnectionOnCommit(TransactionTestCase):
self.assertDone([2])
def test_error_in_hook_doesnt_prevent_clearing_hooks(self):
- try:
+ with suppress(ForcedError):
with transaction.atomic():
transaction.on_commit(lambda: self.notify('error'))
- except ForcedError:
- pass
with transaction.atomic():
self.do(1)