diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py index 4443f13dac..82b3cc0585 100644 --- a/django/contrib/admin/models.py +++ b/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 diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index e68dfa1e8b..c0767c15ee 100644 --- a/django/contrib/admin/sites.py +++ b/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) diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py index 0b3365cb3a..f0102c4455 100644 --- a/django/contrib/auth/middleware.py +++ b/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): diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 0884089d92..21367c4195 100644 --- a/django/contrib/contenttypes/fields.py +++ b/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 diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py index 066474e49f..ad2e0bc904 100644 --- a/django/contrib/contenttypes/models.py +++ b/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. diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py index c527687250..d67f071569 100644 --- a/django/contrib/contenttypes/views.py +++ b/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. diff --git a/django/contrib/gis/db/backends/spatialite/schema.py b/django/contrib/gis/db/backends/spatialite/schema.py index 3122b79e7e..6f4e3380db 100644 --- a/django/contrib/gis/db/backends/spatialite/schema.py +++ b/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): diff --git a/django/contrib/gis/db/models/fields.py b/django/contrib/gis/db/models/fields.py index 8265815c30..d165313468 100644 --- a/django/contrib/gis/db/models/fields.py +++ b/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) diff --git a/django/contrib/gis/gdal/layer.py b/django/contrib/gis/gdal/layer.py index a2b86c46bd..a2b7fe2211 100644 --- a/django/contrib/gis/gdal/layer.py +++ b/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. diff --git a/django/contrib/gis/utils/__init__.py b/django/contrib/gis/utils/__init__.py index 88de2a4773..800b2dbb89 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 -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 diff --git a/django/contrib/messages/storage/cookie.py b/django/contrib/messages/storage/cookie.py index 6d5df1af9d..49270cac17 100644 --- a/django/contrib/messages/storage/cookie.py +++ b/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 diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py index 3ff79b7a39..64955b8bb7 100644 --- a/django/contrib/sessions/backends/base.py +++ b/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 diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py index 540228b790..0a724f7e0a 100644 --- a/django/contrib/sessions/backends/file.py +++ b/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 diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py index 8f984ae3dc..bd1139ff70 100644 --- a/django/contrib/sitemaps/__init__.py +++ b/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 " diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py index 9112efbfb5..19f52e4487 100644 --- a/django/contrib/sites/models.py +++ b/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) diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py index 7e81ef19ee..e5ae48f9fe 100644 --- a/django/contrib/staticfiles/management/commands/collectstatic.py +++ b/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) diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py index f0dcdb3e62..a8b98c84ae 100644 --- a/django/contrib/syndication/views.py +++ b/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, diff --git a/django/core/cache/backends/filebased.py b/django/core/cache/backends/filebased.py index deceffaa0d..dccc3fdc65 100644 --- a/django/core/cache/backends/filebased.py +++ b/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): """ diff --git a/django/core/cache/backends/locmem.py b/django/core/cache/backends/locmem.py index 20b6dd4212..b2600d3169 100644 --- a/django/core/cache/backends/locmem.py +++ b/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) diff --git a/django/core/files/move.py b/django/core/files/move.py index 310e064a2d..4d791ac263 100644 --- a/django/core/files/move.py +++ b/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: diff --git a/django/core/files/storage.py b/django/core/files/storage.py index fa98bb198a..30788d6d75 100644 --- a/django/core/files/storage.py +++ b/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)) diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py index b68692d60a..77c060c21c 100644 --- a/django/core/management/__init__.py +++ b/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 diff --git a/django/core/management/base.py b/django/core/management/base.py index b53b414fdb..41b6b0fa91 100644 --- a/django/core/management/base.py +++ b/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): """ diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py index 0df5f67e39..f6ae83940a 100644 --- a/django/core/management/commands/flush.py +++ b/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, diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py index ce013bcec0..7c9a43434a 100644 --- a/django/core/management/commands/shell.py +++ b/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)) diff --git a/django/core/validators.py b/django/core/validators.py index c6d5e6e06a..b36ab60704 100644 --- a/django/core/validators.py +++ b/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): diff --git a/django/db/backends/postgresql/client.py b/django/db/backends/postgresql/client.py index 8d08b0d5cf..6d4cc9b692 100644 --- a/django/db/backends/postgresql/client.py +++ b/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) diff --git a/django/db/backends/sqlite3/operations.py b/django/db/backends/sqlite3/operations.py index 774d549461..408848c9ad 100644 --- a/django/db/backends/sqlite3/operations.py +++ b/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 ' diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py index e79e745978..ece58b9bab 100644 --- a/django/db/migrations/autodetector.py +++ b/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): diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py index 563f837c3b..dc644161fc 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, 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: diff --git a/django/db/migrations/writer.py b/django/db/migrations/writer.py index 00ff03e494..aa296db8c5 100644 --- a/django/db/migrations/writer.py +++ b/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) diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py index ff7921b520..db62541559 100644 --- a/django/db/models/expressions.py +++ b/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 diff --git a/django/db/models/options.py b/django/db/models/options.py index c81a61c916..9f0746bd58 100644 --- a/django/db/models/options.py +++ b/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 diff --git a/django/db/models/query.py b/django/db/models/query.py index a690ba4b72..42fb728190 100644 --- a/django/db/models/query.py +++ b/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 diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 509d97e65d..017edea873 100644 --- a/django/db/models/sql/query.py +++ b/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): diff --git a/django/forms/fields.py b/django/forms/fields.py index 805018786a..9246676527 100644 --- a/django/forms/fields.py +++ b/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 diff --git a/django/forms/forms.py b/django/forms/forms.py index 0b434b24f8..e2e7c645ff 100644 --- a/django/forms/forms.py +++ b/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 diff --git a/django/forms/formsets.py b/django/forms/formsets.py index 7332e4b2f4..5133164f7a 100644 --- a/django/forms/formsets.py +++ b/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: diff --git a/django/forms/models.py b/django/forms/models.py index ffa8982506..4435bf9722 100644 --- a/django/forms/models.py +++ b/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 diff --git a/django/forms/widgets.py b/django/forms/widgets.py index dbb3b2e851..47396213d9 100644 --- a/django/forms/widgets.py +++ b/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): diff --git a/django/http/response.py b/django/http/response.py index 384de9fb84..1083fd7dca 100644 --- a/django/http/response.py +++ b/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(). diff --git a/django/template/backends/base.py b/django/template/backends/base.py index 4156365b97..c47c95e51e 100644 --- a/django/template/backends/base.py +++ b/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 diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py index b18b41c293..b172be6239 100644 --- a/django/template/defaultfilters.py +++ b/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 diff --git a/django/test/signals.py b/django/test/signals.py index 3507c69add..a623e756ce 100644 --- a/django/test/signals.py +++ b/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 diff --git a/django/urls/base.py b/django/urls/base.py index 26084dbe3e..6dccdd2e7d 100644 --- a/django/urls/base.py +++ b/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): diff --git a/django/utils/autoreload.py b/django/utils/autoreload.py index a872d42d65..2784a89aeb 100644 --- a/django/utils/autoreload.py +++ b/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): diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index 7713b08e8c..127c6dc774 100644 --- a/django/utils/datastructures.py +++ b/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) diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py index d811e83965..d3f586aacf 100644 --- a/django/utils/dateformat.py +++ b/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) diff --git a/django/utils/formats.py b/django/utils/formats.py index 33865d93a8..f19449ec1e 100644 --- a/django/utils/formats.py +++ b/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 diff --git a/django/utils/http.py b/django/utils/http.py index 0870f1f180..07b6ae246a 100644 --- a/django/utils/http.py +++ b/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 diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py index 4a6840782c..b4586885c4 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, 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) diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index f36c21f0a1..6b3aeb127e 100644 --- a/django/utils/translation/trans_real.py +++ b/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): diff --git a/django/views/debug.py b/django/views/debug.py index 35cff6338f..a0af0c96f4 100644 --- a/django/views/debug.py +++ b/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, [] diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index b8bcea35f0..096984032f 100644 --- a/tests/admin_scripts/tests.py +++ b/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') diff --git a/tests/backends/tests.py b/tests/backends/tests.py index 30c1cbf86d..6d38625a98 100644 --- a/tests/backends/tests.py +++ b/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): diff --git a/tests/bash_completion/tests.py b/tests/bash_completion/tests.py index ba2a5ea773..1d35e1f28e 100644 --- a/tests/bash_completion/tests.py +++ b/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): diff --git a/tests/handlers/views.py b/tests/handlers/views.py index 3c1fa5b802..22b94de3b9 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 -with suppress(ImportError): # Python < 3.5 +try: 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 b759484e04..29a56d6e74 100644 --- a/tests/mail/tests.py +++ b/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': diff --git a/tests/postgres_tests/test_aggregates.py b/tests/postgres_tests/test_aggregates.py index 1fe8a1bf03..056d08441b 100644 --- a/tests/postgres_tests/test_aggregates.py +++ b/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): diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py index 7378b5c12d..e2e4ccdeb2 100644 --- a/tests/postgres_tests/test_array.py +++ b/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): diff --git a/tests/postgres_tests/test_hstore.py b/tests/postgres_tests/test_hstore.py index 55b179ba5e..069e570f51 100644 --- a/tests/postgres_tests/test_hstore.py +++ b/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'}) diff --git a/tests/postgres_tests/test_json.py b/tests/postgres_tests/test_json.py index 20650ae95b..2506fc36d6 100644 --- a/tests/postgres_tests/test_json.py +++ b/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') diff --git a/tests/postgres_tests/test_ranges.py b/tests/postgres_tests/test_ranges.py index da72240bf4..d87ad36438 100644 --- a/tests/postgres_tests/test_ranges.py +++ b/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): diff --git a/tests/runtests.py b/tests/runtests.py index 08e53f4cb1..7f4f1670c5 100755 --- a/tests/runtests.py +++ b/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) diff --git a/tests/staticfiles_tests/storage.py b/tests/staticfiles_tests/storage.py index 0dcfd77a70..7a1f72c130 100644 --- a/tests/staticfiles_tests/storage.py +++ b/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 diff --git a/tests/transaction_hooks/tests.py b/tests/transaction_hooks/tests.py index ed3cf18be2..81ff0066a1 100644 --- a/tests/transaction_hooks/tests.py +++ b/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)