Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-sentry-sdk for openSUSE:Factory checked in at 2021-11-20 02:39:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-sentry-sdk (Old) and /work/SRC/openSUSE:Factory/.python-sentry-sdk.new.1895 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-sentry-sdk" Sat Nov 20 02:39:16 2021 rev:18 rq:932485 version:1.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-sentry-sdk/python-sentry-sdk.changes 2021-10-27 22:21:34.715210129 +0200 +++ /work/SRC/openSUSE:Factory/.python-sentry-sdk.new.1895/python-sentry-sdk.changes 2021-11-20 02:40:28.592515576 +0100 @@ -1,0 +2,13 @@ +Fri Nov 19 08:41:01 UTC 2021 - ecsos <ec...@opensuse.org> + +- Update to 1.5.0 + - Also record client outcomes for before send #1211 + - Add support for implicitly sized envelope items #1229 + - Fix integration with Apache Beam 2.32, 2.33 #1233 + - Remove Python 2.7 support for AWS Lambda layers in craft config #1241 + - Refactor Sanic integration for v21.9 support #1212 + - AWS Lambda Python 3.9 runtime support #1239 + - Fix "shutdown_timeout" typing #1256 +- Disable of python36 build, because out of support at 2021-12-23. + +------------------------------------------------------------------- Old: ---- sentry-python-1.4.1.tar.gz New: ---- sentry-python-1.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-sentry-sdk.spec ++++++ --- /var/tmp/diff_new_pack.EX7pwz/_old 2021-11-20 02:40:29.052514058 +0100 +++ /var/tmp/diff_new_pack.EX7pwz/_new 2021-11-20 02:40:29.056514045 +0100 @@ -19,8 +19,9 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} # nothing provides python2-venusian >= 1.0 needed by python2-pyramid %define skip_python2 1 +%define skip_python36 1 Name: python-sentry-sdk -Version: 1.4.1 +Version: 1.5.0 Release: 0 Summary: Python SDK for Sentry.io License: BSD-2-Clause @@ -37,10 +38,11 @@ BuildRequires: %{python_module certifi} BuildRequires: %{python_module executing} BuildRequires: %{python_module falcon >= 1.4} +BuildRequires: %{python_module httpx >= 0.16.0} BuildRequires: %{python_module rq >= 0.6} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module tornado >= 5} -BuildRequires: %{python_module urllib3} +BuildRequires: %{python_module urllib3 >= 1.10.0} BuildRequires: fdupes BuildRequires: python-rpm-macros # SECTION test requirements @@ -50,7 +52,7 @@ BuildRequires: %{python_module hypothesis} BuildRequires: %{python_module jsonschema >= 3.2.0} BuildRequires: %{python_module pyramid} -BuildRequires: %{python_module pyrsistent} +BuildRequires: %{python_module pyrsistent >= 0.16.0} BuildRequires: %{python_module pytest-cov >= 2.8.1} BuildRequires: %{python_module pytest-forked >= 1.1.3} BuildRequires: %{python_module pytest-localserver >= 0.5.0} @@ -75,10 +77,11 @@ Requires: python-certifi Requires: python-executing Requires: python-falcon >= 1.4 +Requires: python-httpx >= 0.16.0 Requires: python-jsonschema Requires: python-rq >= 0.6 Requires: python-tornado >= 5 -Requires: python-urllib3 +Requires: python-urllib3 >= 1.10.0 # SECTION extra requirements - which rise up buildtime error or missing in openSUSE #Requires: python-Django >= 1.8 #Requires: python-sanic >= 0.8 ++++++ sentry-python-1.4.1.tar.gz -> sentry-python-1.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/.craft.yml new/sentry-python-1.5.0/.craft.yml --- old/sentry-python-1.4.1/.craft.yml 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/.craft.yml 2021-11-16 19:57:37.000000000 +0100 @@ -18,10 +18,10 @@ # On the other hand, AWS Lambda does not support every Python runtime. # The supported runtimes are available in the following link: # https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html - - python2.7 - python3.6 - python3.7 - python3.8 + - python3.9 license: MIT changelog: CHANGELOG.md changelogPolicy: simple diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/CHANGELOG.md new/sentry-python-1.5.0/CHANGELOG.md --- old/sentry-python-1.4.1/CHANGELOG.md 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/CHANGELOG.md 2021-11-16 19:57:37.000000000 +0100 @@ -22,7 +22,25 @@ ## Unreleased -- TBA +## 1.5.0 + +- Also record client outcomes for before send #1211 +- Add support for implicitly sized envelope items #1229 +- Fix integration with Apache Beam 2.32, 2.33 #1233 +- Remove Python 2.7 support for AWS Lambda layers in craft config #1241 +- Refactor Sanic integration for v21.9 support #1212 +- AWS Lambda Python 3.9 runtime support #1239 +- Fix "shutdown_timeout" typing #1256 + +Work in this release contributed by @galuszkak, @kianmeng, @ahopkins, @razumeiko, @tomscytale, and @seedofjoy. Thank you for your contribution! + +## 1.4.3 + +- Turned client reports on by default. + +## 1.4.2 + +- Made envelope modifications in the HTTP transport non observable #1206 ## 1.4.1 @@ -46,7 +64,7 @@ ## 1.2.0 - Fix for `AWSLambda` Integration to handle other path formats for function initial handler #1139 -- Fix for worker to set deamon attribute instead of deprecated setDaemon method #1093 +- Fix for worker to set daemon attribute instead of deprecated setDaemon method #1093 - Fix for `bottle` Integration that discards `-dev` for version extraction #1085 - Fix for transport that adds a unified hook for capturing metrics about dropped events #1100 - Add `Httpx` Integration #1119 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/docs/conf.py new/sentry-python-1.5.0/docs/conf.py --- old/sentry-python-1.4.1/docs/conf.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/docs/conf.py 2021-11-16 19:57:37.000000000 +0100 @@ -29,7 +29,7 @@ copyright = u"2019, Sentry Team and Contributors" author = u"Sentry Team and Contributors" -release = "1.4.1" +release = "1.5.0" version = ".".join(release.split(".")[:2]) # The short X.Y version. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/client.py new/sentry-python-1.5.0/sentry_sdk/client.py --- old/sentry-python-1.4.1/sentry_sdk/client.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/client.py 2021-11-16 19:57:37.000000000 +0100 @@ -201,6 +201,10 @@ new_event = before_send(event, hint or {}) if new_event is None: logger.info("before send dropped event (%s)", event) + if self.transport: + self.transport.record_lost_event( + "before_send", data_category="error" + ) event = new_event # type: ignore return event diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/consts.py new/sentry-python-1.5.0/sentry_sdk/consts.py --- old/sentry-python-1.4.1/sentry_sdk/consts.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/consts.py 2021-11-16 19:57:37.000000000 +0100 @@ -52,7 +52,7 @@ release=None, # type: Optional[str] environment=None, # type: Optional[str] server_name=None, # type: Optional[str] - shutdown_timeout=2, # type: int + shutdown_timeout=2, # type: float integrations=[], # type: Sequence[Integration] # noqa: B006 in_app_include=[], # type: List[str] # noqa: B006 in_app_exclude=[], # type: List[str] # noqa: B006 @@ -76,7 +76,7 @@ traces_sampler=None, # type: Optional[TracesSampler] auto_enabling_integrations=True, # type: bool auto_session_tracking=True, # type: bool - send_client_reports=False, # type: bool + send_client_reports=True, # type: bool _experiments={}, # type: Experiments # noqa: B006 ): # type: (...) -> None @@ -101,7 +101,7 @@ del _get_default_options -VERSION = "1.4.1" +VERSION = "1.5.0" SDK_INFO = { "name": "sentry.python", "version": VERSION, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/envelope.py new/sentry-python-1.5.0/sentry_sdk/envelope.py --- old/sentry-python-1.4.1/sentry_sdk/envelope.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/envelope.py 2021-11-16 19:57:37.000000000 +0100 @@ -295,13 +295,18 @@ if not line: return None headers = parse_json(line) - length = headers["length"] - payload = f.read(length) - if headers.get("type") in ("event", "transaction"): + length = headers.get("length") + if length is not None: + payload = f.read(length) + f.readline() + else: + # if no length was specified we need to read up to the end of line + # and remove it (if it is present, i.e. not the very last char in an eof terminated envelope) + payload = f.readline().rstrip(b"\n") + if headers.get("type") in ("event", "transaction", "metric_buckets"): rv = cls(headers=headers, payload=PayloadRef(json=parse_json(payload))) else: rv = cls(headers=headers, payload=payload) - f.readline() return rv @classmethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/integrations/aiohttp.py new/sentry-python-1.5.0/sentry_sdk/integrations/aiohttp.py --- old/sentry-python-1.4.1/sentry_sdk/integrations/aiohttp.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/integrations/aiohttp.py 2021-11-16 19:57:37.000000000 +0100 @@ -65,9 +65,7 @@ try: version = tuple(map(int, AIOHTTP_VERSION.split(".")[:2])) except (TypeError, ValueError): - raise DidNotEnable( - "AIOHTTP version unparseable: {}".format(AIOHTTP_VERSION) - ) + raise DidNotEnable("AIOHTTP version unparsable: {}".format(AIOHTTP_VERSION)) if version < (3, 4): raise DidNotEnable("AIOHTTP 3.4 or newer required.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/integrations/aws_lambda.py new/sentry-python-1.5.0/sentry_sdk/integrations/aws_lambda.py --- old/sentry-python-1.4.1/sentry_sdk/integrations/aws_lambda.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/integrations/aws_lambda.py 2021-11-16 19:57:37.000000000 +0100 @@ -284,12 +284,14 @@ # Python 3.7: If the bootstrap module is *already imported*, it is the # one we actually want to use (no idea what's in __main__) # - # On Python 3.8 bootstrap is also importable, but will be the same file + # Python 3.8: bootstrap is also importable, but will be the same file # as __main__ imported under a different name: # # sys.modules['__main__'].__file__ == sys.modules['bootstrap'].__file__ # sys.modules['__main__'] is not sys.modules['bootstrap'] # + # Python 3.9: bootstrap is in __main__.awslambdaricmain + # # On container builds using the `aws-lambda-python-runtime-interface-client` # (awslamdaric) module, bootstrap is located in sys.modules['__main__'].bootstrap # @@ -297,10 +299,18 @@ if "bootstrap" in sys.modules: return sys.modules["bootstrap"] elif "__main__" in sys.modules: - if hasattr(sys.modules["__main__"], "bootstrap"): + module = sys.modules["__main__"] + # python3.9 runtime + if hasattr(module, "awslambdaricmain") and hasattr( + module.awslambdaricmain, "bootstrap" # type: ignore + ): + return module.awslambdaricmain.bootstrap # type: ignore + elif hasattr(module, "bootstrap"): # awslambdaric python module in container builds - return sys.modules["__main__"].bootstrap # type: ignore - return sys.modules["__main__"] + return module.bootstrap # type: ignore + + # python3.8 runtime + return module else: return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/integrations/beam.py new/sentry-python-1.5.0/sentry_sdk/integrations/beam.py --- old/sentry-python-1.4.1/sentry_sdk/integrations/beam.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/integrations/beam.py 2021-11-16 19:57:37.000000000 +0100 @@ -80,7 +80,6 @@ def _wrap_inspect_call(cls, func_name): # type: (Any, Any) -> Any - from apache_beam.typehints.decorators import getfullargspec # type: ignore if not hasattr(cls, func_name): return None @@ -105,6 +104,8 @@ return get_function_args_defaults(process_func) except ImportError: + from apache_beam.typehints.decorators import getfullargspec # type: ignore + return getfullargspec(process_func) setattr(_inspect, USED_FUNC, True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/integrations/sanic.py new/sentry-python-1.5.0/sentry_sdk/integrations/sanic.py --- old/sentry-python-1.4.1/sentry_sdk/integrations/sanic.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/integrations/sanic.py 2021-11-16 19:57:37.000000000 +0100 @@ -27,6 +27,7 @@ from sanic.request import Request, RequestParameters from sentry_sdk._types import Event, EventProcessor, Hint + from sanic.router import Route try: from sanic import Sanic, __version__ as SANIC_VERSION @@ -36,19 +37,31 @@ except ImportError: raise DidNotEnable("Sanic not installed") +old_error_handler_lookup = ErrorHandler.lookup +old_handle_request = Sanic.handle_request +old_router_get = Router.get + +try: + # This method was introduced in Sanic v21.9 + old_startup = Sanic._startup +except AttributeError: + pass + class SanicIntegration(Integration): identifier = "sanic" + version = (0, 0) # type: Tuple[int, ...] @staticmethod def setup_once(): # type: () -> None + try: - version = tuple(map(int, SANIC_VERSION.split("."))) + SanicIntegration.version = tuple(map(int, SANIC_VERSION.split("."))) except (TypeError, ValueError): raise DidNotEnable("Unparsable Sanic version: {}".format(SANIC_VERSION)) - if version < (0, 8): + if SanicIntegration.version < (0, 8): raise DidNotEnable("Sanic 0.8 or newer required.") if not HAS_REAL_CONTEXTVARS: @@ -71,89 +84,194 @@ # https://github.com/huge-success/sanic/issues/1332 ignore_logger("root") - old_handle_request = Sanic.handle_request + if SanicIntegration.version < (21, 9): + _setup_legacy_sanic() + return - async def sentry_handle_request(self, request, *args, **kwargs): - # type: (Any, Request, *Any, **Any) -> Any - hub = Hub.current - if hub.get_integration(SanicIntegration) is None: - return old_handle_request(self, request, *args, **kwargs) - - weak_request = weakref.ref(request) - - with Hub(hub) as hub: - with hub.configure_scope() as scope: - scope.clear_breadcrumbs() - scope.add_event_processor(_make_request_processor(weak_request)) - - response = old_handle_request(self, request, *args, **kwargs) - if isawaitable(response): - response = await response - - return response - - Sanic.handle_request = sentry_handle_request - - old_router_get = Router.get - - def sentry_router_get(self, *args): - # type: (Any, Union[Any, Request]) -> Any - rv = old_router_get(self, *args) - hub = Hub.current - if hub.get_integration(SanicIntegration) is not None: - with capture_internal_exceptions(): - with hub.configure_scope() as scope: - if version >= (21, 3): - # Sanic versions above and including 21.3 append the app name to the - # route name, and so we need to remove it from Route name so the - # transaction name is consistent across all versions - sanic_app_name = self.ctx.app.name - sanic_route = rv[0].name - - if sanic_route.startswith("%s." % sanic_app_name): - # We add a 1 to the len of the sanic_app_name because there is a dot - # that joins app name and the route name - # Format: app_name.route_name - sanic_route = sanic_route[len(sanic_app_name) + 1 :] - - scope.transaction = sanic_route - else: - scope.transaction = rv[0].__name__ - return rv - - Router.get = sentry_router_get - - old_error_handler_lookup = ErrorHandler.lookup - - def sentry_error_handler_lookup(self, exception): - # type: (Any, Exception) -> Optional[object] - _capture_exception(exception) - old_error_handler = old_error_handler_lookup(self, exception) + _setup_sanic() - if old_error_handler is None: - return None - if Hub.current.get_integration(SanicIntegration) is None: - return old_error_handler +class SanicRequestExtractor(RequestExtractor): + def content_length(self): + # type: () -> int + if self.request.body is None: + return 0 + return len(self.request.body) + + def cookies(self): + # type: () -> Dict[str, str] + return dict(self.request.cookies) + + def raw_data(self): + # type: () -> bytes + return self.request.body + + def form(self): + # type: () -> RequestParameters + return self.request.form + + def is_json(self): + # type: () -> bool + raise NotImplementedError() + + def json(self): + # type: () -> Optional[Any] + return self.request.json + + def files(self): + # type: () -> RequestParameters + return self.request.files + + def size_of_file(self, file): + # type: (Any) -> int + return len(file.body or ()) + + +def _setup_sanic(): + # type: () -> None + Sanic._startup = _startup + ErrorHandler.lookup = _sentry_error_handler_lookup + + +def _setup_legacy_sanic(): + # type: () -> None + Sanic.handle_request = _legacy_handle_request + Router.get = _legacy_router_get + ErrorHandler.lookup = _sentry_error_handler_lookup + + +async def _startup(self): + # type: (Sanic) -> None + # This happens about as early in the lifecycle as possible, just after the + # Request object is created. The body has not yet been consumed. + self.signal("http.lifecycle.request")(_hub_enter) + + # This happens after the handler is complete. In v21.9 this signal is not + # dispatched when there is an exception. Therefore we need to close out + # and call _hub_exit from the custom exception handler as well. + # See https://github.com/sanic-org/sanic/issues/2297 + self.signal("http.lifecycle.response")(_hub_exit) + + # This happens inside of request handling immediately after the route + # has been identified by the router. + self.signal("http.routing.after")(_set_transaction) + + # The above signals need to be declared before this can be called. + await old_startup(self) + + +async def _hub_enter(request): + # type: (Request) -> None + hub = Hub.current + request.ctx._sentry_do_integration = ( + hub.get_integration(SanicIntegration) is not None + ) + + if not request.ctx._sentry_do_integration: + return + + weak_request = weakref.ref(request) + request.ctx._sentry_hub = Hub(hub) + request.ctx._sentry_hub.__enter__() + + with request.ctx._sentry_hub.configure_scope() as scope: + scope.clear_breadcrumbs() + scope.add_event_processor(_make_request_processor(weak_request)) + - async def sentry_wrapped_error_handler(request, exception): - # type: (Request, Exception) -> Any - try: - response = old_error_handler(request, exception) - if isawaitable(response): - response = await response - return response - except Exception: - # Report errors that occur in Sanic error handler. These - # exceptions will not even show up in Sanic's - # `sanic.exceptions` logger. - exc_info = sys.exc_info() - _capture_exception(exc_info) - reraise(*exc_info) +async def _hub_exit(request, **_): + # type: (Request, **Any) -> None + request.ctx._sentry_hub.__exit__(None, None, None) - return sentry_wrapped_error_handler - ErrorHandler.lookup = sentry_error_handler_lookup +async def _set_transaction(request, route, **kwargs): + # type: (Request, Route, **Any) -> None + hub = Hub.current + if hub.get_integration(SanicIntegration) is not None: + with capture_internal_exceptions(): + with hub.configure_scope() as scope: + route_name = route.name.replace(request.app.name, "").strip(".") + scope.transaction = route_name + + +def _sentry_error_handler_lookup(self, exception, *args, **kwargs): + # type: (Any, Exception, *Any, **Any) -> Optional[object] + _capture_exception(exception) + old_error_handler = old_error_handler_lookup(self, exception, *args, **kwargs) + + if old_error_handler is None: + return None + + if Hub.current.get_integration(SanicIntegration) is None: + return old_error_handler + + async def sentry_wrapped_error_handler(request, exception): + # type: (Request, Exception) -> Any + try: + response = old_error_handler(request, exception) + if isawaitable(response): + response = await response + return response + except Exception: + # Report errors that occur in Sanic error handler. These + # exceptions will not even show up in Sanic's + # `sanic.exceptions` logger. + exc_info = sys.exc_info() + _capture_exception(exc_info) + reraise(*exc_info) + finally: + # As mentioned in previous comment in _startup, this can be removed + # after https://github.com/sanic-org/sanic/issues/2297 is resolved + if SanicIntegration.version >= (21, 9): + await _hub_exit(request) + + return sentry_wrapped_error_handler + + +async def _legacy_handle_request(self, request, *args, **kwargs): + # type: (Any, Request, *Any, **Any) -> Any + hub = Hub.current + if hub.get_integration(SanicIntegration) is None: + return old_handle_request(self, request, *args, **kwargs) + + weak_request = weakref.ref(request) + + with Hub(hub) as hub: + with hub.configure_scope() as scope: + scope.clear_breadcrumbs() + scope.add_event_processor(_make_request_processor(weak_request)) + + response = old_handle_request(self, request, *args, **kwargs) + if isawaitable(response): + response = await response + + return response + + +def _legacy_router_get(self, *args): + # type: (Any, Union[Any, Request]) -> Any + rv = old_router_get(self, *args) + hub = Hub.current + if hub.get_integration(SanicIntegration) is not None: + with capture_internal_exceptions(): + with hub.configure_scope() as scope: + if SanicIntegration.version and SanicIntegration.version >= (21, 3): + # Sanic versions above and including 21.3 append the app name to the + # route name, and so we need to remove it from Route name so the + # transaction name is consistent across all versions + sanic_app_name = self.ctx.app.name + sanic_route = rv[0].name + + if sanic_route.startswith("%s." % sanic_app_name): + # We add a 1 to the len of the sanic_app_name because there is a dot + # that joins app name and the route name + # Format: app_name.route_name + sanic_route = sanic_route[len(sanic_app_name) + 1 :] + + scope.transaction = sanic_route + else: + scope.transaction = rv[0].__name__ + return rv def _capture_exception(exception): @@ -211,39 +329,3 @@ return event return sanic_processor - - -class SanicRequestExtractor(RequestExtractor): - def content_length(self): - # type: () -> int - if self.request.body is None: - return 0 - return len(self.request.body) - - def cookies(self): - # type: () -> Dict[str, str] - return dict(self.request.cookies) - - def raw_data(self): - # type: () -> bytes - return self.request.body - - def form(self): - # type: () -> RequestParameters - return self.request.form - - def is_json(self): - # type: () -> bool - raise NotImplementedError() - - def json(self): - # type: () -> Optional[Any] - return self.request.json - - def files(self): - # type: () -> RequestParameters - return self.request.files - - def size_of_file(self, file): - # type: (Any) -> int - return len(file.body or ()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/tracing.py new/sentry-python-1.5.0/sentry_sdk/tracing.py --- old/sentry-python-1.4.1/sentry_sdk/tracing.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/tracing.py 2021-11-16 19:57:37.000000000 +0100 @@ -617,7 +617,7 @@ 1. If a sampling decision is passed to `start_transaction` (`start_transaction(name: "my transaction", sampled: True)`), that - decision will be used, regardlesss of anything else + decision will be used, regardless of anything else 2. If `traces_sampler` is defined, its decision will be used. It can choose to keep or ignore any parent sampling decision, or use the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/tracing_utils.py new/sentry-python-1.5.0/sentry_sdk/tracing_utils.py --- old/sentry-python-1.4.1/sentry_sdk/tracing_utils.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/tracing_utils.py 2021-11-16 19:57:37.000000000 +0100 @@ -65,7 +65,7 @@ # of the form `sentry=xxxx` SENTRY_TRACESTATE_ENTRY_REGEX = re.compile( # either sentry is the first entry or there's stuff immediately before it, - # ending in a commma (this prevents matching something like `coolsentry=xxx`) + # ending in a comma (this prevents matching something like `coolsentry=xxx`) "(?:^|.+,)" # sentry's part, not including the potential comma "(sentry=[^,]*)" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/sentry_sdk/transport.py new/sentry-python-1.5.0/sentry_sdk/transport.py --- old/sentry-python-1.4.1/sentry_sdk/transport.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/sentry_sdk/transport.py 2021-11-16 19:57:37.000000000 +0100 @@ -356,7 +356,10 @@ else: new_items.append(item) - envelope.items[:] = new_items + # Since we're modifying the envelope here make a copy so that others + # that hold references do not see their envelope modified. + envelope = Envelope(headers=envelope.headers, items=new_items) + if not envelope.items: return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/setup.py new/sentry-python-1.5.0/setup.py --- old/sentry-python-1.4.1/setup.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/setup.py 2021-11-16 19:57:37.000000000 +0100 @@ -21,7 +21,7 @@ setup( name="sentry-sdk", - version="1.4.1", + version="1.5.0", author="Sentry Team and Contributors", author_email="he...@sentry.io", url="https://github.com/getsentry/sentry-python", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tests/integrations/aws_lambda/test_aws.py new/sentry-python-1.5.0/tests/integrations/aws_lambda/test_aws.py --- old/sentry-python-1.4.1/tests/integrations/aws_lambda/test_aws.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tests/integrations/aws_lambda/test_aws.py 2021-11-16 19:57:37.000000000 +0100 @@ -105,7 +105,9 @@ return get_boto_client() -@pytest.fixture(params=["python3.6", "python3.7", "python3.8", "python2.7"]) +@pytest.fixture( + params=["python3.6", "python3.7", "python3.8", "python3.9", "python2.7"] +) def lambda_runtime(request): return request.param diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tests/integrations/beam/test_beam.py new/sentry-python-1.5.0/tests/integrations/beam/test_beam.py --- old/sentry-python-1.4.1/tests/integrations/beam/test_beam.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tests/integrations/beam/test_beam.py 2021-11-16 19:57:37.000000000 +0100 @@ -152,7 +152,9 @@ class _OutputProcessor(OutputProcessor): - def process_outputs(self, windowed_input_element, results): + def process_outputs( + self, windowed_input_element, results, watermark_estimator=None + ): print(windowed_input_element) try: for result in results: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tests/integrations/sanic/test_sanic.py new/sentry-python-1.5.0/tests/integrations/sanic/test_sanic.py --- old/sentry-python-1.4.1/tests/integrations/sanic/test_sanic.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tests/integrations/sanic/test_sanic.py 2021-11-16 19:57:37.000000000 +0100 @@ -173,11 +173,6 @@ kwargs["app"] = app if SANIC_VERSION >= (21, 3): - try: - app.router.reset() - app.router.finalize() - except AttributeError: - ... class MockAsyncStreamer: def __init__(self, request_body): @@ -203,6 +198,13 @@ patched_request = request.Request(**kwargs) patched_request.stream = MockAsyncStreamer([b"hello", b"foo"]) + if SANIC_VERSION >= (21, 9): + await app.dispatch( + "http.lifecycle.request", + context={"request": patched_request}, + inline=True, + ) + await app.handle_request( patched_request, ) @@ -217,6 +219,15 @@ assert r.status == 200 async def runner(): + if SANIC_VERSION >= (21, 3): + if SANIC_VERSION >= (21, 9): + await app._startup() + else: + try: + app.router.reset() + app.router.finalize() + except AttributeError: + ... await asyncio.gather(*(task(i) for i in range(1000))) if sys.version_info < (3, 7): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tests/test_basics.py new/sentry-python-1.5.0/tests/test_basics.py --- old/sentry-python-1.4.1/tests/test_basics.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tests/test_basics.py 2021-11-16 19:57:37.000000000 +0100 @@ -77,9 +77,13 @@ assert Hub.current.last_event_id() == event_id -def test_option_callback(sentry_init, capture_events): +def test_option_callback(sentry_init, capture_events, monkeypatch): drop_events = False drop_breadcrumbs = False + reports = [] + + def record_lost_event(reason, data_category=None, item=None): + reports.append((reason, data_category)) def before_send(event, hint): assert isinstance(hint["exc_info"][1], ValueError) @@ -96,6 +100,10 @@ sentry_init(before_send=before_send, before_breadcrumb=before_breadcrumb) events = capture_events() + monkeypatch.setattr( + Hub.current.client.transport, "record_lost_event", record_lost_event + ) + def do_this(): add_breadcrumb(message="Hello", hint={"foo": 42}) try: @@ -106,8 +114,10 @@ do_this() drop_breadcrumbs = True do_this() + assert not reports drop_events = True do_this() + assert reports == [("before_send", "error")] normal, no_crumbs = events diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tests/test_envelope.py new/sentry-python-1.5.0/tests/test_envelope.py --- old/sentry-python-1.4.1/tests/test_envelope.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tests/test_envelope.py 2021-11-16 19:57:37.000000000 +0100 @@ -132,3 +132,135 @@ "event_id": "15210411201320122115110420122013", "sent_at": "2012-11-21T12:31:12.415908Z", } + + +def test_envelope_with_sized_items(): + """ + Tests that it successfully parses envelopes with + the item size specified in the header + """ + envelope_raw = ( + b'{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n' + + b'{"type":"type1","length":4 }\n1234\n' + + b'{"type":"type2","length":4 }\nabcd\n' + + b'{"type":"type3","length":0}\n\n' + + b'{"type":"type4","length":4 }\nab12\n' + ) + envelope_raw_eof_terminated = envelope_raw[:-1] + + for envelope_raw in (envelope_raw, envelope_raw_eof_terminated): + actual = Envelope.deserialize(envelope_raw) + + items = [item for item in actual] + + assert len(items) == 4 + + assert items[0].type == "type1" + assert items[0].get_bytes() == b"1234" + + assert items[1].type == "type2" + assert items[1].get_bytes() == b"abcd" + + assert items[2].type == "type3" + assert items[2].get_bytes() == b"" + + assert items[3].type == "type4" + assert items[3].get_bytes() == b"ab12" + + assert actual.headers["event_id"] == "9ec79c33ec9942ab8353589fcb2e04dc" + + +def test_envelope_with_implicitly_sized_items(): + """ + Tests that it successfully parses envelopes with + the item size not specified in the header + """ + envelope_raw = ( + b'{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n' + + b'{"type":"type1"}\n1234\n' + + b'{"type":"type2"}\nabcd\n' + + b'{"type":"type3"}\n\n' + + b'{"type":"type4"}\nab12\n' + ) + envelope_raw_eof_terminated = envelope_raw[:-1] + + for envelope_raw in (envelope_raw, envelope_raw_eof_terminated): + actual = Envelope.deserialize(envelope_raw) + assert actual.headers["event_id"] == "9ec79c33ec9942ab8353589fcb2e04dc" + + items = [item for item in actual] + + assert len(items) == 4 + + assert items[0].type == "type1" + assert items[0].get_bytes() == b"1234" + + assert items[1].type == "type2" + assert items[1].get_bytes() == b"abcd" + + assert items[2].type == "type3" + assert items[2].get_bytes() == b"" + + assert items[3].type == "type4" + assert items[3].get_bytes() == b"ab12" + + +def test_envelope_with_two_attachments(): + """ + Test that items are correctly parsed in an envelope with to size specified items + """ + two_attachments = ( + b'{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc","dsn":"https://e12d836b15bb49d7bbf99e64295d995b:@sentry.io/42"}\n' + + b'{"type":"attachment","length":10,"content_type":"text/plain","filename":"hello.txt"}\n' + + b"\xef\xbb\xbfHello\r\n\n" + + b'{"type":"event","length":41,"content_type":"application/json","filename":"application.log"}\n' + + b'{"message":"hello world","level":"error"}\n' + ) + two_attachments_eof_terminated = two_attachments[ + :-1 + ] # last \n is optional, without it should still be a valid envelope + + for envelope_raw in (two_attachments, two_attachments_eof_terminated): + actual = Envelope.deserialize(envelope_raw) + items = [item for item in actual] + + assert len(items) == 2 + assert items[0].get_bytes() == b"\xef\xbb\xbfHello\r\n" + assert items[1].payload.json == {"message": "hello world", "level": "error"} + + +def test_envelope_with_empty_attachments(): + """ + Test that items are correctly parsed in an envelope with two 0 length items (with size specified in the header + """ + two_empty_attachments = ( + b'{"event_id":"9ec79c33ec9942ab8353589fcb2e04dc"}\n' + + b'{"type":"attachment","length":0}\n\n' + + b'{"type":"attachment","length":0}\n\n' + ) + + two_empty_attachments_eof_terminated = two_empty_attachments[ + :-1 + ] # last \n is optional, without it should still be a valid envelope + + for envelope_raw in (two_empty_attachments, two_empty_attachments_eof_terminated): + actual = Envelope.deserialize(envelope_raw) + items = [item for item in actual] + + assert len(items) == 2 + assert items[0].get_bytes() == b"" + assert items[1].get_bytes() == b"" + + +def test_envelope_without_headers(): + """ + Test that an envelope without headers is parsed successfully + """ + envelope_without_headers = ( + b"{}\n" + b'{"type":"session"}\n' + b'{"started": "2020-02-07T14:16:00Z"}' + ) + actual = Envelope.deserialize(envelope_without_headers) + items = [item for item in actual] + + assert len(items) == 1 + assert items[0].payload.get_bytes() == b'{"started": "2020-02-07T14:16:00Z"}' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tests/test_transport.py new/sentry-python-1.5.0/tests/test_transport.py --- old/sentry-python-1.4.1/tests/test_transport.py 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tests/test_transport.py 2021-11-16 19:57:37.000000000 +0100 @@ -279,7 +279,7 @@ client.flush() # this goes out with an extra envelope because it's flushed after the last item - # that is normally in the queue. This is quite funny in a way beacuse it means + # that is normally in the queue. This is quite funny in a way because it means # that the envelope that caused its own over quota report (an error with an # attachment) will include its outcome since it's pending. assert len(capturing_server.captured) == 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sentry-python-1.4.1/tox.ini new/sentry-python-1.5.0/tox.ini --- old/sentry-python-1.4.1/tox.ini 2021-09-22 14:34:25.000000000 +0200 +++ new/sentry-python-1.5.0/tox.ini 2021-11-16 19:57:37.000000000 +0100 @@ -46,7 +46,7 @@ {pypy,py2.7,py3.5,py3.6,py3.7,py3.8}-celery-{4.3,4.4} {py3.6,py3.7,py3.8}-celery-5.0 - py3.7-beam-{2.12,2.13} + py3.7-beam-{2.12,2.13,2.32,2.33} # The aws_lambda tests deploy to the real AWS and have their own matrix of Python versions. py3.7-aws_lambda @@ -140,6 +140,8 @@ beam-2.12: apache-beam>=2.12.0, <2.13.0 beam-2.13: apache-beam>=2.13.0, <2.14.0 + beam-2.32: apache-beam>=2.32.0, <2.33.0 + beam-2.33: apache-beam>=2.33.0, <2.34.0 beam-master: git+https://github.com/apache/beam#egg=apache-beam&subdirectory=sdks/python celery: redis @@ -300,6 +302,9 @@ {py3.5,py3.6,py3.7,py3.8,py3.9}-flask-{0.10,0.11,0.12}: pip install pytest<5 {py3.6,py3.7,py3.8,py3.9}-flask-{0.11}: pip install Werkzeug<2 + ; https://github.com/more-itertools/more-itertools/issues/578 + py3.5-flask-{0.10,0.11,0.12}: pip install more-itertools<8.11.0 + py.test {env:TESTPATH} {posargs} [testenv:linters]