From bc4111ba68e5eede1f68882a16d68441a845e30b Mon Sep 17 00:00:00 2001 From: konarkmodi Date: Tue, 19 Mar 2013 10:34:59 +0530 Subject: [PATCH] Fixed #18003 -- Preserved tracebacks when re-raising errors. Thanks jrothenbuhler for draft patch, Konark Modi for updates. --- django/contrib/admin/views/main.py | 3 ++- .../gis/db/backends/oracle/introspection.py | 9 +++++++-- .../contrib/gis/db/backends/spatialite/base.py | 8 ++++++-- .../gis/db/backends/spatialite/operations.py | 10 ++++++---- django/contrib/gis/utils/layermapping.py | 3 ++- django/core/management/commands/flush.py | 17 ++++++++++------- django/core/serializers/json.py | 3 ++- django/core/serializers/pyyaml.py | 3 ++- django/core/servers/basehttp.py | 3 ++- django/forms/fields.py | 3 ++- django/forms/util.py | 13 ++++++++----- django/http/multipartparser.py | 4 +++- django/templatetags/i18n.py | 7 +++++-- django/test/testcases.py | 4 ++-- django/utils/http.py | 2 +- 15 files changed, 60 insertions(+), 32 deletions(-) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index b7bf85ef9d..050d4776d0 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -1,4 +1,5 @@ import operator +import sys import warnings from functools import reduce @@ -173,7 +174,7 @@ class ChangeList(six.with_metaclass(RenameChangeListMethods)): lookup_needs_distinct(self.lookup_opts, key)) return filter_specs, bool(filter_specs), lookup_params, use_distinct except FieldDoesNotExist as e: - raise IncorrectLookupParameters(e) + six.reraise(IncorrectLookupParameters, IncorrectLookupParameters(e), sys.exc_info()[2]) def get_query_string(self, new_params=None, remove=None): if new_params is None: new_params = {} diff --git a/django/contrib/gis/db/backends/oracle/introspection.py b/django/contrib/gis/db/backends/oracle/introspection.py index 716f318d24..d6c8f452df 100644 --- a/django/contrib/gis/db/backends/oracle/introspection.py +++ b/django/contrib/gis/db/backends/oracle/introspection.py @@ -1,5 +1,7 @@ import cx_Oracle +import sys from django.db.backends.oracle.introspection import DatabaseIntrospection +from django.utils import six class OracleIntrospection(DatabaseIntrospection): # Associating any OBJECTVAR instances with GeometryField. Of course, @@ -17,8 +19,11 @@ class OracleIntrospection(DatabaseIntrospection): (table_name.upper(), geo_col.upper())) row = cursor.fetchone() except Exception as msg: - raise Exception('Could not find entry in USER_SDO_GEOM_METADATA corresponding to "%s"."%s"\n' - 'Error message: %s.' % (table_name, geo_col, msg)) + new_msg = ( + 'Could not find entry in USER_SDO_GEOM_METADATA ' + 'corresponding to "%s"."%s"\n' + 'Error message: %s.') % (table_name, geo_col, msg) + six.reraise(Exception, Exception(new_msg), sys.exc_info()[2]) # TODO: Research way to find a more specific geometry field type for # the column's contents. diff --git a/django/contrib/gis/db/backends/spatialite/base.py b/django/contrib/gis/db/backends/spatialite/base.py index e23dfc580a..7b49d71a61 100644 --- a/django/contrib/gis/db/backends/spatialite/base.py +++ b/django/contrib/gis/db/backends/spatialite/base.py @@ -1,3 +1,4 @@ +import sys from ctypes.util import find_library from django.conf import settings @@ -8,6 +9,7 @@ from django.contrib.gis.db.backends.spatialite.client import SpatiaLiteClient from django.contrib.gis.db.backends.spatialite.creation import SpatiaLiteCreation from django.contrib.gis.db.backends.spatialite.introspection import SpatiaLiteIntrospection from django.contrib.gis.db.backends.spatialite.operations import SpatiaLiteOperations +from django.utils import six class DatabaseWrapper(SQLiteDatabaseWrapper): def __init__(self, *args, **kwargs): @@ -50,7 +52,9 @@ class DatabaseWrapper(SQLiteDatabaseWrapper): try: cur.execute("SELECT load_extension(%s)", (self.spatialite_lib,)) except Exception as msg: - raise ImproperlyConfigured('Unable to load the SpatiaLite library extension ' - '"%s" because: %s' % (self.spatialite_lib, msg)) + new_msg = ( + 'Unable to load the SpatiaLite library extension ' + '"%s" because: %s') % (self.spatialite_lib, msg) + six.reraise(ImproperlyConfigured, ImproperlyConfigured(new_msg), sys.exc_info()[2]) cur.close() return conn diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py index d2d75c1fff..83745476a0 100644 --- a/django/contrib/gis/db/backends/spatialite/operations.py +++ b/django/contrib/gis/db/backends/spatialite/operations.py @@ -1,4 +1,5 @@ import re +import sys from decimal import Decimal from django.contrib.gis.db.backends.base import BaseSpatialOperations @@ -126,10 +127,11 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations): try: version = self.spatialite_version_tuple()[1:] except Exception as msg: - raise ImproperlyConfigured('Cannot determine the SpatiaLite version for the "%s" ' - 'database (error was "%s"). Was the SpatiaLite initialization ' - 'SQL loaded on this database?' % - (self.connection.settings_dict['NAME'], msg)) + new_msg = ( + 'Cannot determine the SpatiaLite version for the "%s" ' + 'database (error was "%s"). Was the SpatiaLite initialization ' + 'SQL loaded on this database?') % (self.connection.settings_dict['NAME'], msg) + six.reraise(ImproperlyConfigured, ImproperlyConfigured(new_msg), sys.exc_info()[2]) if version < (2, 3, 0): raise ImproperlyConfigured('GeoDjango only supports SpatiaLite versions ' '2.3.0 and above') diff --git a/django/contrib/gis/utils/layermapping.py b/django/contrib/gis/utils/layermapping.py index 248afb5808..282dbc7450 100644 --- a/django/contrib/gis/utils/layermapping.py +++ b/django/contrib/gis/utils/layermapping.py @@ -429,7 +429,8 @@ class LayerMapping(object): # Creating the CoordTransform object return CoordTransform(self.source_srs, target_srs) except Exception as msg: - raise LayerMapError('Could not translate between the data source and model geometry: %s' % msg) + new_msg = 'Could not translate between the data source and model geometry: %s' % msg + six.reraise(LayerMapError, LayerMapError(new_msg), sys.exc_info()[2]) def geometry_field(self): "Returns the GeometryField instance associated with the geographic column." diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py index 9bd65e735c..10066417a1 100644 --- a/django/core/management/commands/flush.py +++ b/django/core/management/commands/flush.py @@ -1,3 +1,4 @@ +import sys from optparse import make_option from django.conf import settings @@ -8,6 +9,7 @@ from django.core.management.color import no_style from django.core.management.sql import sql_flush, emit_post_sync_signal from django.utils.importlib import import_module from django.utils.six.moves import input +from django.utils import six class Command(NoArgsCommand): @@ -62,13 +64,14 @@ Are you sure you want to do this? for sql in sql_list: cursor.execute(sql) except Exception as e: - raise CommandError("""Database %s couldn't be flushed. Possible reasons: - * The database isn't running or isn't configured correctly. - * At least one of the expected database tables doesn't exist. - * The SQL was invalid. -Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run. -The full error: %s""" % (connection.settings_dict['NAME'], e)) - + new_msg = ( + "Database %s couldn't be flushed. Possible reasons:\n" + " * The database isn't running or isn't configured correctly.\n" + " * At least one of the expected database tables doesn't exist.\n" + " * The SQL was invalid.\n" + "Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.\n" + "The full error: %s") % (connection.settings_dict['NAME'], e) + six.reraise(CommandError, CommandError(new_msg), sys.exc_info()[2]) # Emit the post sync signal. This allows individual # applications to respond as if the database had been # sync'd from scratch. diff --git a/django/core/serializers/json.py b/django/core/serializers/json.py index ed65f2922c..64357bf9d5 100644 --- a/django/core/serializers/json.py +++ b/django/core/serializers/json.py @@ -8,6 +8,7 @@ from __future__ import absolute_import import datetime import decimal import json +import sys from django.core.serializers.base import DeserializationError from django.core.serializers.python import Serializer as PythonSerializer @@ -72,7 +73,7 @@ def Deserializer(stream_or_string, **options): raise except Exception as e: # Map to deserializer error - raise DeserializationError(e) + six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2]) class DjangoJSONEncoder(json.JSONEncoder): diff --git a/django/core/serializers/pyyaml.py b/django/core/serializers/pyyaml.py index 27239e0445..478f14b53f 100644 --- a/django/core/serializers/pyyaml.py +++ b/django/core/serializers/pyyaml.py @@ -6,6 +6,7 @@ Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__. import decimal import yaml +import sys from io import StringIO from django.db import models @@ -71,4 +72,4 @@ def Deserializer(stream_or_string, **options): raise except Exception as e: # Map to deserializer error - raise DeserializationError(e) + six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2]) diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 89ec2b35f2..8e390bce27 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -24,6 +24,7 @@ from wsgiref.util import FileWrapper # for backwards compatibility from django.core.management.color import color_style from django.core.wsgi import get_wsgi_application from django.utils.module_loading import import_by_path +from django.utils import six __all__ = ['WSGIServer', 'WSGIRequestHandler'] @@ -121,7 +122,7 @@ class WSGIServer(simple_server.WSGIServer, object): try: super(WSGIServer, self).server_bind() except Exception as e: - raise WSGIServerException(e) + six.reraise(WSGIServerException, WSGIServerException(e), sys.exc_info()[2]) self.setup_environ() diff --git a/django/forms/fields.py b/django/forms/fields.py index 11b7f44029..e708ef846e 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -8,6 +8,7 @@ import copy import datetime import os import re +import sys try: from urllib.parse import urlsplit, urlunsplit except ImportError: # Python 2 @@ -619,7 +620,7 @@ class ImageField(FileField): # raised. Catch and re-raise. raise except Exception: # Python Imaging Library doesn't recognize it as an image - raise ValidationError(self.error_messages['invalid_image']) + six.reraise(ValidationError, ValidationError(self.error_messages['invalid_image']), sys.exc_info()[2]) if hasattr(f, 'seek') and callable(f.seek): f.seek(0) return f diff --git a/django/forms/util.py b/django/forms/util.py index 724f256e40..f1b864e6b3 100644 --- a/django/forms/util.py +++ b/django/forms/util.py @@ -6,6 +6,8 @@ from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.safestring import mark_safe from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +from django.utils import six +import sys # Import ValidationError so that it can be imported from this # module to maintain backwards compatibility. @@ -78,11 +80,12 @@ def from_current_timezone(value): try: return timezone.make_aware(value, current_timezone) except Exception: - raise ValidationError(_('%(datetime)s couldn\'t be interpreted ' - 'in time zone %(current_timezone)s; it ' - 'may be ambiguous or it may not exist.') - % {'datetime': value, - 'current_timezone': current_timezone}) + msg = _( + '%(datetime)s couldn\'t be interpreted ' + 'in time zone %(current_timezone)s; it ' + 'may be ambiguous or it may not exist.') % {'datetime': value, 'current_timezone': + current_timezone} + six.reraise(ValidationError, ValidationError(msg), sys.exc_info()[2]) return value def to_current_timezone(value): diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py index 070874f234..0c07335f27 100644 --- a/django/http/multipartparser.py +++ b/django/http/multipartparser.py @@ -8,6 +8,7 @@ from __future__ import unicode_literals import base64 import cgi +import sys from django.conf import settings from django.core.exceptions import SuspiciousOperation @@ -209,7 +210,8 @@ class MultiPartParser(object): chunk = base64.b64decode(chunk) except Exception as e: # Since this is only a chunk, any error is an unfixable error. - raise MultiPartParserError("Could not decode base64 data: %r" % e) + msg = "Could not decode base64 data: %r" % e + six.reraise(MultiPartParserError, MultiPartParserError(msg), sys.exc_info()[2]) for i, handler in enumerate(handlers): chunk_length = len(chunk) diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py index d64efff9d3..14f0382fc7 100644 --- a/django/templatetags/i18n.py +++ b/django/templatetags/i18n.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals import re +import sys from django.conf import settings from django.template import (Node, Variable, TemplateSyntaxError, @@ -424,8 +425,10 @@ def do_block_translate(parser, token): value = remaining_bits.pop(0) value = parser.compile_filter(value) except Exception: - raise TemplateSyntaxError('"context" in %r tag expected ' - 'exactly one argument.' % bits[0]) + msg = ( + '"context" in %r tag expected ' + 'exactly one argument.') % bits[0] + six.reraise(TemplateSyntaxError, TemplateSyntaxError(msg), sys.exc_info()[2]) else: raise TemplateSyntaxError('Unknown argument for %r tag: %r.' % (bits[0], option)) diff --git a/django/test/testcases.py b/django/test/testcases.py index 87779eabfd..66026dd23e 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -1119,8 +1119,8 @@ class LiveServerTestCase(TransactionTestCase): for port in range(extremes[0], extremes[1] + 1): possible_ports.append(port) except Exception: - raise ImproperlyConfigured('Invalid address ("%s") for live ' - 'server.' % specified_address) + msg = 'Invalid address ("%s") for live server.' % specified_address + six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg), sys.exc_info()[2]) cls.server_thread = LiveServerThread( host, possible_ports, connections_override) cls.server_thread.daemon = True diff --git a/django/utils/http.py b/django/utils/http.py index 0ab5198804..73b6396286 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -144,7 +144,7 @@ def parse_http_date(date): result = datetime.datetime(year, month, day, hour, min, sec) return calendar.timegm(result.utctimetuple()) except Exception: - raise ValueError("%r is not a valid date" % date) + six.reraise(ValueError, ValueError("%r is not a valid date" % date), sys.exc_info()[2]) def parse_http_date_safe(date): """