diff options
author | David Cramer <dcramer@gmail.com> | 2016-08-02 15:21:45 -0700 |
---|---|---|
committer | David Cramer <dcramer@gmail.com> | 2016-08-04 11:10:59 -0700 |
commit | 5d7cc8cdaf1ba14e671282e725814ad24ba2792f (patch) | |
tree | 48dd7d033eec5da403736b290ed79184a582d03a | |
parent | f6e9219936dfa8e76668eda834c53878a9f78428 (diff) | |
download | raven-5d7cc8cdaf1ba14e671282e725814ad24ba2792f.tar.gz |
Support for Django 1.10
Refs GH-818
-rw-r--r-- | .travis.yml | 5 | ||||
-rw-r--r-- | conftest.py | 26 | ||||
-rw-r--r-- | raven/contrib/django/management/__init__.py | 58 | ||||
-rw-r--r-- | raven/contrib/django/models.py | 3 | ||||
-rw-r--r-- | raven/contrib/django/urls.py | 12 | ||||
-rw-r--r-- | tests/contrib/django/tests.py | 57 | ||||
-rw-r--r-- | tests/contrib/django/urls.py | 23 |
7 files changed, 75 insertions, 109 deletions
diff --git a/.travis.yml b/.travis.yml index 18de603..1f1e630 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ env: # - DJANGO=Django==1.7.11 - DJANGO=Django==1.8.7 - DJANGO=Django==1.9 + - DJANGO=Django==1.10 # - DJANGO="-e git+git://github.com/django/django.git#egg=Django" install: - time ci/setup @@ -52,6 +53,8 @@ matrix: # env: DJANGO=Django==1.4.20 - python: '3.3' env: DJANGO=Django==1.9 + - python: '3.3' + env: DJANGO=Django==1.10 # - python: '3.4' # env: DJANGO=Django==1.4.20 # - python: '3.5' @@ -69,6 +72,8 @@ matrix: - python: '3.2' env: DJANGO="-e git+git://github.com/django/django.git#egg=Django" - python: '2.6' + env: DJANGO=Django==1.10 + - python: '2.6' env: DJANGO=Django==1.9 - python: '2.6' env: DJANGO=Django==1.8.7 diff --git a/conftest.py b/conftest.py index e353523..55c641c 100644 --- a/conftest.py +++ b/conftest.py @@ -11,25 +11,22 @@ if sys.version_info[0] > 2: collect_ignore.append("tests/handlers/logbook") try: - import gevent + import gevent # NOQA except ImportError: collect_ignore.append("tests/transport/gevent") try: - import web + import web # NOQA except ImportError: collect_ignore.append("tests/contrib/webpy") INSTALLED_APPS = [ 'django.contrib.auth', - 'django.contrib.admin', + 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', - # Included to fix Disqus' test Django which solves IntegrityMessage case - 'django.contrib.contenttypes', - 'raven.contrib.django', 'tests.contrib.django', ] @@ -37,7 +34,7 @@ INSTALLED_APPS = [ use_djcelery = True try: - import djcelery + import djcelery # NOQA INSTALLED_APPS.append('djcelery') except ImportError: use_djcelery = False @@ -59,7 +56,7 @@ def pytest_configure(config): DATABASE_NAME=':memory:', TEST_DATABASE_NAME=':memory:', INSTALLED_APPS=INSTALLED_APPS, - ROOT_URLCONF='', + ROOT_URLCONF='tests.contrib.django.urls', DEBUG=False, SITE_ID=1, BROKER_HOST="localhost", @@ -70,7 +67,18 @@ def pytest_configure(config): SENTRY_ALLOW_ORIGIN='*', CELERY_ALWAYS_EAGER=True, TEMPLATE_DEBUG=True, + LANGUAGE_CODE='en', + LANGUAGES=(('en', 'English'),), PROJECT_ROOT=where_am_i, - TEMPLATE_DIRS=[os.path.join(where_am_i, 'tests', 'contrib', 'django', 'templates')], + TEMPLATE_DIRS=[ + os.path.join(where_am_i, 'tests', 'contrib', 'django', 'templates'), + ], + TEMPLATES=[{ + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + 'DIRS': [ + os.path.join(where_am_i, 'tests', 'contrib', 'django', 'templates'), + ], + }], ALLOWED_HOSTS=['*'], ) diff --git a/raven/contrib/django/management/__init__.py b/raven/contrib/django/management/__init__.py index 722f6db..b0860a4 100644 --- a/raven/contrib/django/management/__init__.py +++ b/raven/contrib/django/management/__init__.py @@ -1,59 +1 @@ -""" -raven.contrib.django.raven.management -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:copyright: (c) 2010-2013 by the Sentry Team, see AUTHORS for more details -:license: BSD, see LICENSE for more details. -""" from __future__ import absolute_import, print_function - -import sys -import warnings - -from functools import wraps - - -def patch_cli_runner(): - """ - Patches ``cls.execute``, returning a boolean describing if the - attempt was successful. - """ - from raven.base import get_excepthook_client - - try: - from django.core.management.base import BaseCommand - except ImportError: - warnings.warn('Unable to patch Django management commands') - return - else: - cls = BaseCommand - - try: - original_func = cls.execute - except AttributeError: - # must not be a capable version of Django - return False - - if hasattr(original_func, '__raven_patched'): - return False - - @wraps(original_func) - def new_execute(self, *args, **kwargs): - try: - return original_func(self, *args, **kwargs) - except Exception: - from raven.contrib.django.models import client - - # Since this is an unhandled exception that falls through - # we only want to log it if the given client is not the - # one that handles the global exceptions. - if get_excepthook_client() is not client: - client.captureException(extra={ - 'argv': sys.argv - }) - raise - - new_execute.__raven_patched = True - cls.execute = new_execute - - return True diff --git a/raven/contrib/django/models.py b/raven/contrib/django/models.py index 2e48d5f..8411ddd 100644 --- a/raven/contrib/django/models.py +++ b/raven/contrib/django/models.py @@ -18,7 +18,6 @@ import warnings from django.conf import settings from raven._compat import PY2, binary_type, text_type, string_types -from raven.contrib.django.management import patch_cli_runner from raven.utils.conf import convert_options from raven.utils.imports import import_string @@ -215,5 +214,3 @@ if ('raven.contrib.django' in settings.INSTALLED_APPS or 'raven.contrib.django.raven_compat' in settings.INSTALLED_APPS): register_handlers() register_serializers() - - patch_cli_runner() diff --git a/raven/contrib/django/urls.py b/raven/contrib/django/urls.py index c513e44..de3acec 100644 --- a/raven/contrib/django/urls.py +++ b/raven/contrib/django/urls.py @@ -8,12 +8,14 @@ raven.contrib.django.urls from __future__ import absolute_import try: - from django.conf.urls import patterns, url + from django.conf.urls import url except ImportError: # for Django version less than 1.4 - from django.conf.urls.defaults import patterns, url # NOQA + from django.conf.urls.defaults import url # NOQA -urlpatterns = patterns('', - url(r'^api/(?:(?P<project_id>[\w_-]+)/)?store/$', 'raven.contrib.django.views.report', name='raven-report'), - url(r'^report/', 'raven.contrib.django.views.report'), +import raven.contrib.django.views + +urlpatterns = ( + url(r'^api/(?:(?P<project_id>[\w_-]+)/)?store/$', raven.contrib.django.views.report, name='raven-report'), + url(r'^report/', raven.contrib.django.views.report), ) diff --git a/tests/contrib/django/tests.py b/tests/contrib/django/tests.py index 21a4a78..3aa6b74 100644 --- a/tests/contrib/django/tests.py +++ b/tests/contrib/django/tests.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- -from __future__ import absolute_import -from __future__ import with_statement +from __future__ import absolute_import, print_function, with_statement import datetime import django @@ -10,9 +9,7 @@ import mock import pytest import re import six -import sys # NOQA -from exam import fixture -from six import StringIO +import sys from django.conf import settings from django.contrib.auth.models import User @@ -24,6 +21,8 @@ from django.http import QueryDict from django.template import TemplateSyntaxError from django.test import TestCase from django.utils.translation import gettext_lazy +from exam import fixture +from six import StringIO from raven.base import Client from raven.contrib.django.client import DjangoClient @@ -42,6 +41,7 @@ from .models import TestModel settings.SENTRY_CLIENT = 'tests.contrib.django.tests.TempStoreClient' DJANGO_15 = django.VERSION >= (1, 5, 0) +DJANGO_18 = django.VERSION >= (1, 8, 0) def make_request(): @@ -157,7 +157,7 @@ class DjangoClientTest(TestCase): assert event['message'], "TypeError: int() argument must be a string or a number == not 'NoneType'" assert event['culprit'] == 'tests.contrib.django.tests in test_signal_integration' - @pytest.mark.skipif('sys.version_info[:2] == (2, 6)') + @pytest.mark.skipif(sys.version_info[:2] == (2, 6), reason='Python 2.6') def test_view_exception(self): self.assertRaises(Exception, self.client.get, reverse('sentry-raise-exc')) @@ -199,7 +199,7 @@ class DjangoClientTest(TestCase): 'email': user.email, } - @pytest.mark.skipif(str('not DJANGO_15')) + @pytest.mark.skipif(not DJANGO_15, reason='< Django 1.5') def test_get_user_info_abstract_user(self): from django.db import models from django.contrib.auth.models import AbstractBaseUser @@ -320,6 +320,7 @@ class DjangoClientTest(TestCase): assert event['culprit'].startswith('django.shortcuts in ') self.raven.include_paths = include_paths + @pytest.mark.skipif(DJANGO_18, reason='Django 1.8+ not supported') def test_template_name_as_view(self): self.assertRaises(TemplateSyntaxError, self.client.get, reverse('sentry-template-exc')) @@ -339,7 +340,7 @@ class DjangoClientTest(TestCase): # assert event['data']['META']['REMOTE_ADDR'] == '127.0.0.1' # TODO: Python bug #10805 - @pytest.mark.skipif(str('six.PY3')) + @pytest.mark.skipif(six.PY3, reason='Python 2') def test_record_none_exc_info(self): # sys.exc_info can return (None, None, None) if no exception is being # handled anywhere on the stack. See: @@ -630,62 +631,72 @@ class ReportViewTest(TestCase): urls = 'raven.contrib.django.urls' def setUp(self): - self.path = reverse('raven-report') + super(ReportViewTest, self).setUp() + self.path = reverse('raven-report', urlconf=self.urls) @mock.patch('raven.contrib.django.views.is_valid_origin') def test_calls_is_valid_origin_with_header(self, is_valid_origin): - self.client.post(self.path, HTTP_ORIGIN='http://example.com') + with self.settings(ROOT_URLCONF=self.urls): + self.client.post(self.path, HTTP_ORIGIN='http://example.com') is_valid_origin.assert_called_once_with('http://example.com') @mock.patch('raven.contrib.django.views.is_valid_origin') def test_calls_is_valid_origin_with_header_as_get(self, is_valid_origin): - self.client.get(self.path, HTTP_ORIGIN='http://example.com') + with self.settings(ROOT_URLCONF=self.urls): + self.client.get(self.path, HTTP_ORIGIN='http://example.com') is_valid_origin.assert_called_once_with('http://example.com') @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=False)) def test_fails_on_invalid_origin(self): - resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com') assert resp.status_code == 403 @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=True)) def test_options_call_sends_headers(self): - resp = self.client.options(self.path, HTTP_ORIGIN='http://example.com') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.options(self.path, HTTP_ORIGIN='http://example.com') assert resp.status_code == 200 assert resp['Access-Control-Allow-Origin'] == 'http://example.com' assert resp['Access-Control-Allow-Methods'], 'GET, POST == OPTIONS' @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=True)) def test_missing_data(self): - resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com') assert resp.status_code == 400 @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=True)) def test_invalid_data(self): - resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', - data='[1', content_type='application/octet-stream') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', + data='[1', content_type='application/octet-stream') assert resp.status_code == 400 @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=True)) def test_sends_data(self): - resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', - data='{}', content_type='application/octet-stream') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', + data='{}', content_type='application/octet-stream') assert resp.status_code == 200 event = client.events.pop(0) assert event == {'auth_header': None} @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=True)) def test_sends_authorization_header(self): - resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', - HTTP_AUTHORIZATION='Sentry foo/bar', data='{}', content_type='application/octet-stream') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', + HTTP_AUTHORIZATION='Sentry foo/bar', data='{}', content_type='application/octet-stream') assert resp.status_code == 200 event = client.events.pop(0) assert event == {'auth_header': 'Sentry foo/bar'} @mock.patch('raven.contrib.django.views.is_valid_origin', mock.Mock(return_value=True)) def test_sends_x_sentry_auth_header(self): - resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', - HTTP_X_SENTRY_AUTH='Sentry foo/bar', data='{}', - content_type='application/octet-stream') + with self.settings(ROOT_URLCONF=self.urls): + resp = self.client.post(self.path, HTTP_ORIGIN='http://example.com', + HTTP_X_SENTRY_AUTH='Sentry foo/bar', data='{}', + content_type='application/octet-stream') assert resp.status_code == 200 event = client.events.pop(0) assert event == {'auth_header': 'Sentry foo/bar'} diff --git a/tests/contrib/django/urls.py b/tests/contrib/django/urls.py index a1d2929..c4b3abf 100644 --- a/tests/contrib/django/urls.py +++ b/tests/contrib/django/urls.py @@ -19,14 +19,15 @@ def handler500(request): raise ValueError('handler500') return HttpResponse('', status=500) - -urlpatterns = [ - url(r'^no-error$', 'tests.contrib.django.views.no_error', name='sentry-no-error'), - url(r'^fake-login$', 'tests.contrib.django.views.fake_login', name='sentry-fake-login'), - url(r'^trigger-500$', 'tests.contrib.django.views.raise_exc', name='sentry-raise-exc'), - url(r'^trigger-500-ioerror$', 'tests.contrib.django.views.raise_ioerror', name='sentry-raise-ioerror'), - url(r'^trigger-500-decorated$', 'tests.contrib.django.views.decorated_raise_exc', name='sentry-raise-exc-decor'), - url(r'^trigger-500-django$', 'tests.contrib.django.views.django_exc', name='sentry-django-exc'), - url(r'^trigger-500-template$', 'tests.contrib.django.views.template_exc', name='sentry-template-exc'), - url(r'^trigger-500-log-request$', 'tests.contrib.django.views.logging_request_exc', name='sentry-log-request-exc'), -] +import tests.contrib.django.views + +urlpatterns = ( + url(r'^no-error$', tests.contrib.django.views.no_error, name='sentry-no-error'), + url(r'^fake-login$', tests.contrib.django.views.fake_login, name='sentry-fake-login'), + url(r'^trigger-500$', tests.contrib.django.views.raise_exc, name='sentry-raise-exc'), + url(r'^trigger-500-ioerror$', tests.contrib.django.views.raise_ioerror, name='sentry-raise-ioerror'), + url(r'^trigger-500-decorated$', tests.contrib.django.views.decorated_raise_exc, name='sentry-raise-exc-decor'), + url(r'^trigger-500-django$', tests.contrib.django.views.django_exc, name='sentry-django-exc'), + url(r'^trigger-500-template$', tests.contrib.django.views.template_exc, name='sentry-template-exc'), + url(r'^trigger-500-log-request$', tests.contrib.django.views.logging_request_exc, name='sentry-log-request-exc'), +) |