diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index dc4a30297d..ff81005f0c 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -27,6 +27,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh ## Removed - The SDK no longer supports Python 3.6. The oldest supported version is now 3.7. +- Dropped support for Django versions below 2.0. - The `enable_tracing` option was removed. Use `traces_sample_rate=1.0` instead. - The deprecated `push_scope` and `configure_scope` APIs have been removed. Use `with new_scope():` to push a new scope and `scope = get_current_scope()` to retrieve the current scope instead. - Transaction profiling and related code was removed. diff --git a/scripts/populate_tox/releases.jsonl b/scripts/populate_tox/releases.jsonl index 91bb57b192..4614f4e385 100644 --- a/scripts/populate_tox/releases.jsonl +++ b/scripts/populate_tox/releases.jsonl @@ -1,9 +1,5 @@ -{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": "", "version": "1.10.8", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-1.10.8-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-1.10.8.tar.gz"}]} -{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": "", "version": "1.11.29", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-1.11.29-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-1.11.29.tar.gz"}]} -{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": "", "version": "1.8.19", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-1.8.19-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-1.8.19.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.4", "version": "2.0.13", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-2.0.13-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-2.0.13.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.5", "version": "2.2.28", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-2.2.28-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-2.2.28.tar.gz"}]} -{"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.6", "version": "3.1.14", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-3.1.14-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-3.1.14.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.6", "version": "3.2.25", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-3.2.25-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-3.2.25.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.8", "version": "4.2.30", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-4.2.30-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-4.2.30.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Django", "requires_python": ">=3.10", "version": "5.2.16", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-5.2.16-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-5.2.16.tar.gz"}]} diff --git a/sentry_sdk/integrations/__init__.py b/sentry_sdk/integrations/__init__.py index 7aa496cec2..9604755afe 100644 --- a/sentry_sdk/integrations/__init__.py +++ b/sentry_sdk/integrations/__init__.py @@ -135,7 +135,7 @@ def iter_default_integrations( "chalice": (1, 16, 0), "clickhouse_driver": (0, 2, 0), "cohere": (5, 4, 0), - "django": (1, 8), + "django": (2, 0), "dramatiq": (1, 9), "falcon": (1, 4), "fastapi": (0, 79, 0), diff --git a/sentry_sdk/integrations/django/__init__.py b/sentry_sdk/integrations/django/__init__.py index 0f8dfcd24a..7a488f7055 100644 --- a/sentry_sdk/integrations/django/__init__.py +++ b/sentry_sdk/integrations/django/__init__.py @@ -62,6 +62,9 @@ except ImportError: raise DidNotEnable("Django not installed") +from typing import TYPE_CHECKING + +from sentry_sdk.integrations.django.caching import patch_caching from sentry_sdk.integrations.django.middleware import patch_django_middlewares from sentry_sdk.integrations.django.signals_handlers import patch_signals from sentry_sdk.integrations.django.tasks import patch_tasks @@ -72,13 +75,6 @@ from sentry_sdk.integrations.django.transactions import LEGACY_RESOLVER from sentry_sdk.integrations.django.views import patch_views -if DJANGO_VERSION[:2] > (1, 8): - from sentry_sdk.integrations.django.caching import patch_caching -else: - patch_caching = None # type: ignore - -from typing import TYPE_CHECKING - if TYPE_CHECKING: from typing import Any, Callable, Dict, List, Optional, Union @@ -93,17 +89,6 @@ from sentry_sdk.tracing import Span -if DJANGO_VERSION < (1, 10): - - def is_authenticated(request_user: "Any") -> bool: - return request_user.is_authenticated() - -else: - - def is_authenticated(request_user: "Any") -> bool: - return request_user.is_authenticated - - TRANSACTION_STYLE_VALUES = ("function_name", "url") @@ -469,7 +454,7 @@ def _get_user_from_request_and_set_on_scope(request: "WSGIRequest") -> None: elif is_lazy: return - if user is None or not is_authenticated(user): + if user is None or not user.is_authenticated: return user_info = {} @@ -637,7 +622,7 @@ def _set_user_info(request: "WSGIRequest", event: "Event") -> None: user = getattr(request, "user", None) - if user is None or not is_authenticated(user): + if user is None or not user.is_authenticated: return try: @@ -658,27 +643,14 @@ def _set_user_info(request: "WSGIRequest", event: "Event") -> None: def install_sql_hook() -> None: """If installed this causes Django's queries to be captured.""" - try: - from django.db.backends.utils import CursorWrapper - except ImportError: - from django.db.backends.util import CursorWrapper - - try: - # django 1.6 and 1.7 compatability - from django.db.backends import BaseDatabaseWrapper - except ImportError: - # django 1.8 or later - from django.db.backends.base.base import BaseDatabaseWrapper - - try: - real_execute = CursorWrapper.execute - real_executemany = CursorWrapper.executemany - real_connect = BaseDatabaseWrapper.connect - real_commit = BaseDatabaseWrapper._commit - real_rollback = BaseDatabaseWrapper._rollback - except AttributeError: - # This won't work on Django versions < 1.6 - return + from django.db.backends.base.base import BaseDatabaseWrapper + from django.db.backends.utils import CursorWrapper + + real_execute = CursorWrapper.execute + real_executemany = CursorWrapper.executemany + real_connect = BaseDatabaseWrapper.connect + real_commit = BaseDatabaseWrapper._commit + real_rollback = BaseDatabaseWrapper._rollback @ensure_integration_enabled(DjangoIntegration, real_execute) def execute( diff --git a/sentry_sdk/integrations/django/templates.py b/sentry_sdk/integrations/django/templates.py index 1c0986dd9e..7b1dc438d9 100644 --- a/sentry_sdk/integrations/django/templates.py +++ b/sentry_sdk/integrations/django/templates.py @@ -1,8 +1,8 @@ import functools from typing import TYPE_CHECKING -from django import VERSION as DJANGO_VERSION from django.template import TemplateSyntaxError +from django.template.base import Origin from django.utils.safestring import mark_safe import sentry_sdk @@ -13,13 +13,6 @@ if TYPE_CHECKING: from typing import Any, Dict, Iterator, Optional, Tuple -try: - # support Django 1.9 - from django.template.base import Origin -except ImportError: - # backward compatibility - from django.template.loader import LoaderOrigin as Origin - def get_template_frame_from_exception( exc_value: "Optional[BaseException]", @@ -85,8 +78,6 @@ def rendered_content(self: "SimpleTemplateResponse") -> str: SimpleTemplateResponse.rendered_content = rendered_content - if DJANGO_VERSION < (1, 7): - return import django.shortcuts real_render = django.shortcuts.render diff --git a/sentry_sdk/integrations/django/transactions.py b/sentry_sdk/integrations/django/transactions.py index 192f0765e6..73b6afa76e 100644 --- a/sentry_sdk/integrations/django/transactions.py +++ b/sentry_sdk/integrations/django/transactions.py @@ -8,24 +8,15 @@ import re from typing import TYPE_CHECKING +from django.urls import get_resolver +from django.urls.resolvers import RoutePattern + if TYPE_CHECKING: from re import Pattern from typing import Dict, List, Optional, Tuple, Union from django.urls.resolvers import URLPattern, URLResolver -from django import VERSION as DJANGO_VERSION - -if DJANGO_VERSION >= (2, 0): - from django.urls.resolvers import RoutePattern -else: - RoutePattern = None - -try: - from django.urls import get_resolver -except ImportError: - from django.core.urlresolvers import get_resolver - def get_regex(resolver_or_pattern: "Union[URLPattern, URLResolver]") -> "Pattern[str]": """Utility method for django's deprecated resolver.regex""" @@ -61,11 +52,7 @@ def _simplify(self, pattern: "Union[URLPattern, URLResolver]") -> str: """ # "new-style" path patterns can be parsed directly without turning them # into regexes first - if ( - RoutePattern is not None - and hasattr(pattern, "pattern") - and isinstance(pattern.pattern, RoutePattern) - ): + if hasattr(pattern, "pattern") and isinstance(pattern.pattern, RoutePattern): return self._new_style_group_matcher.sub( lambda m: "{%s}" % m.group(2), str(pattern.pattern._route) ) diff --git a/tox.ini b/tox.ini index d5750d651b..1439ffdf72 100644 --- a/tox.ini +++ b/tox.ini @@ -284,7 +284,7 @@ envlist = # ~~~ Web 1 ~~~ - {py3.7}-django-v1.11.29 + {py3.7}-django-v2.0.13 {py3.7,py3.8,py3.9}-django-v2.2.28 {py3.7,py3.9,py3.10}-django-v3.2.25 {py3.8,py3.11,py3.12}-django-v4.2.30 @@ -14366,7 +14366,7 @@ deps = # ~~~ Web 1 ~~~ - django-v1.11.29: django==1.11.29 + django-v2.0.13: django==2.0.13 django-v2.2.28: django==2.2.28 @@ -15280,14 +15280,14 @@ deps = django-v5.2.16: pytest-asyncio django-v6.0.7: pytest-asyncio django-v6.1a1: pytest-asyncio - django-v1.11.29: djangorestframework>=3.0,<4.0 - django-v1.11.29: Werkzeug<2.1.0 + django-v2.0.13: djangorestframework>=3.0,<4.0 + django-v2.0.13: Werkzeug<2.1.0 django-v2.2.28: djangorestframework>=3.0,<4.0 django-v2.2.28: Werkzeug<2.1.0 django-v3.2.25: djangorestframework>=3.0,<4.0 django-v3.2.25: Werkzeug<2.1.0 - django-v1.11.29: pytest-django<4.0 - django-v1.11.29: six + django-v2.0.13: pytest-django<4.0 + django-v2.0.13: six django-v2.2.28: pytest-django<4.0 django-v2.2.28: six {py3.14,py3.14t}-django: coverage==7.11.0