[Python-modules-commits] [raven] 02/08: New upstream release.

Vincent Bernat bernat at moszumanska.debian.org
Sun Nov 12 19:55:32 UTC 2017


This is an automated email from the git hooks/post-receive script.

bernat pushed a commit to annotated tag debian/6.3.0-1
in repository raven.

commit 2de408d771d1e9a528916980be5ec038dedf9cd0
Author: Vincent Bernat <bernat at debian.org>
Date:   Sun Nov 12 20:35:39 2017 +0100

    New upstream release.
---
 MANIFEST.in                                       |   2 +-
 PKG-INFO                                          |   5 +-
 README.rst                                        | 124 ++++++++++++++--
 conftest.py                                       |  74 +++++++++
 raven.egg-info/PKG-INFO                           |   5 +-
 raven.egg-info/SOURCES.txt                        |   8 +
 raven.egg-info/requires.txt                       |  15 +-
 raven/__init__.py                                 |   2 +-
 raven/base.py                                     |  52 +++++--
 raven/breadcrumbs.py                              |   9 +-
 raven/conf/defaults.py                            |   2 +-
 raven/contrib/async.py                            |   1 +
 raven/contrib/awslambda/__init__.py               | 173 ++++++++++++++++++++++
 raven/contrib/bottle/__init__.py                  |   1 +
 raven/contrib/celery/__init__.py                  |   4 +-
 raven/contrib/django/__init__.py                  |   1 -
 raven/contrib/django/apps.py                      |   5 +
 raven/contrib/django/client.py                    |  45 +++---
 raven/contrib/django/management/commands/raven.py |   9 +-
 raven/contrib/django/middleware/__init__.py       |  21 +++
 raven/contrib/django/middleware/wsgi.py           |   1 +
 raven/contrib/django/models.py                    |  96 +++++++-----
 raven/contrib/django/resolver.py                  |   2 +-
 raven/contrib/flask.py                            |  46 ++++--
 raven/contrib/tornado/__init__.py                 |   4 +-
 raven/contrib/webpy/__init__.py                   |   1 +
 raven/contrib/zconfig/__init__.py                 |  39 +++++
 raven/contrib/zerorpc/__init__.py                 |  11 +-
 raven/contrib/zope/__init__.py                    |   4 +-
 raven/events.py                                   |   6 +
 raven/handlers/logging.py                         |   4 +-
 raven/middleware.py                               |   2 +
 raven/processors.py                               |  11 +-
 raven/utils/conf.py                               |   1 +
 raven/utils/encoding.py                           |   2 +-
 raven/utils/stacks.py                             |   5 +-
 raven/utils/wsgi.py                               |  14 ++
 setup.cfg                                         |   9 +-
 setup.py                                          |  26 ++--
 tests/base/tests.py                               |  53 +++++++
 tests/contrib/awslambda/conftest.py               | 106 +++++++++++++
 tests/contrib/awslambda/test_lambda.py            |  69 +++++++++
 tests/contrib/django/settings.py                  |  64 ++++++++
 tests/contrib/django/test_resolver.py             |  13 +-
 tests/contrib/django/test_tastypie.py             |   5 +-
 tests/contrib/django/tests.py                     | 130 ++++++++++++----
 tests/contrib/django/urls.py                      |   5 +-
 tests/contrib/django/views.py                     |   9 ++
 tests/contrib/flask/tests.py                      |  64 ++++++--
 tests/contrib/zconfig/__init__.py                 |   0
 tests/contrib/zconfig/tests.py                    |  76 ++++++++++
 tests/handlers/logging/tests.py                   |  11 ++
 tests/transport/gevent/tests.py                   |   5 +
 tests/utils/wsgi/tests.py                         |  12 +-
 tests/versioning/tests.py                         |   8 +-
 55 files changed, 1277 insertions(+), 195 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in
index 76ddd09..887e552 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
-include setup.py README.rst MANIFEST.in LICENSE *.txt
+include setup.py conftest.py README.rst MANIFEST.in LICENSE *.txt
 recursive-include raven/contrib/zope *.xml
 recursive-include raven/data *
 graft tests
diff --git a/PKG-INFO b/PKG-INFO
index d14e2db..a9105da 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: raven
-Version: 6.0.0
+Version: 6.3.0
 Summary: Raven is a client for Sentry (https://getsentry.com)
 Home-page: https://github.com/getsentry/raven-python
 Author: Sentry
@@ -21,10 +21,13 @@ Classifier: Intended Audience :: Developers
 Classifier: Intended Audience :: System Administrators
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python
 Classifier: Topic :: Software Development
diff --git a/README.rst b/README.rst
index 8d5d2bf..481a239 100644
--- a/README.rst
+++ b/README.rst
@@ -1,24 +1,128 @@
-Raven
-======
+.. raw:: html
+
+    <p align="center">
+
+.. image:: docs/_static/logo.png
+    :target: https://sentry.io
+    :align: center
+    :width: 116
+    :alt: Sentry website
+
+.. raw:: html
+
+    </p>
+
+Raven - Sentry for Python
+=========================
+
+.. image:: https://img.shields.io/pypi/v/raven.svg
+    :target: https://pypi.python.org/pypi/raven
+    :alt: PyPi page link -- version
 
 .. image:: https://travis-ci.org/getsentry/raven-python.svg?branch=master
     :target: https://travis-ci.org/getsentry/raven-python
 
-Raven is a Python client for `Sentry <http://getsentry.com/>`_. It provides
-full out-of-the-box support for many of the popular frameworks, including
+.. image:: https://img.shields.io/pypi/l/raven.svg
+    :target: https://pypi.python.org/pypi/raven
+    :alt: PyPi page link -- MIT licence
+
+.. image:: https://img.shields.io/pypi/pyversions/raven.svg
+    :target: https://pypi.python.org/pypi/raven
+    :alt: PyPi page link -- Python versions
+
+.. image:: https://codeclimate.com/github/getsentry/raven-python/badges/gpa.svg
+   :target: https://codeclimate.com/github/codeclimate/codeclimate
+   :alt: Code Climate
+
+
+Raven is the official Python client for `Sentry`_, officially supports
+Python 2.6–2.7 & 3.3–3.7, and runs on PyPy and Google App Engine.
+
+It tracks errors and exceptions that happen during the
+execution of your application and provides instant notification with detailed
+information needed to prioritize, identify, reproduce and fix each issue.
+
+It provides full out-of-the-box support for many of the popular python frameworks, including
 Django, and Flask. Raven also includes drop-in support for any WSGI-compatible
 web application.
 
 Your application doesn't live on the web? No problem! Raven is easy to use in
 any Python application.
 
+For more information, see our `Python Documentation`_ for framework integrations and other goodies.
+
+
+Features
+--------
+
+- Automatically report (un)handled exceptions and errors
+- Send customized diagnostic data
+- Process and sanitize data before sending it over the network
+
+
+Quickstart
+----------
+
+It's really easy to get started with Raven. After you complete setting up a project in Sentry,
+you’ll be given a value which we call a DSN, or Data Source Name. You will need it to configure the client.
+
+
+Install the latest package with *pip* and configure the client::
+
+    pip install raven --upgrade
+
+Create a client and capture an example exception:
+
+.. sourcecode:: python
+
+    from raven import Client
+
+    client = Client('___DSN___')
+
+    try:
+        1 / 0
+    except ZeroDivisionError:
+        client.captureException()
+
+
+Raven Python is more than that however. Checkout our `Python Documentation`_.
+
+
+Contributing
+------------
+
+Raven is under active development and contributions are more than welcome!
+There are many ways to contribute:
+
+* Join in on discussions on our `Mailing List`_ or in our `IRC Channel`_.
+
+* Report bugs on our `Issue Tracker`_.
+
+* Submit a pull request!
+
+
 Resources
 ---------
 
-* `Documentation <https://docs.getsentry.com/hosted/clients/python/>`_
-* `Bug Tracker <http://github.com/getsentry/raven-python/issues>`_
-* `Code <http://github.com/getsentry/raven-python>`_
-* `Mailing List <https://groups.google.com/group/getsentry>`_
-* `IRC <irc://irc.freenode.net/sentry>`_  (irc.freenode.net, #sentry)
-* `Travis CI <http://travis-ci.org/getsentry/raven-python>`_
+* `Sentry`_
+* `Python Documentation`_
+* `Issue Tracker`_
+* `Code`_ on Github
+* `Mailing List`_
+* `IRC Channel`_ (irc.freenode.net, #sentry)
+* `Travis CI`_
+
+.. _Sentry: https://getsentry.com/
+.. _Python Documentation: https://docs.getsentry.com/hosted/clients/python/
+.. _SDKs for other platforms: https://docs.sentry.io/#platforms
+.. _Issue Tracker: https://github.com/getsentry/raven-python/issues
+.. _Code: https://github.com/getsentry/raven-python
+.. _Mailing List: https://groups.google.com/group/getsentry
+.. _IRC Channel: irc://irc.freenode.net/sentry
+.. _Travis CI: http://travis-ci.org/getsentry/raven-python
+
+
+
+
 
+Not using Python? Check out our `SDKs for other platforms`_.
diff --git a/conftest.py b/conftest.py
new file mode 100644
index 0000000..70d582d
--- /dev/null
+++ b/conftest.py
@@ -0,0 +1,74 @@
+from __future__ import absolute_import
+
+import os.path
+import pytest
+import sys
+
+collect_ignore = [
+    'tests/contrib/awslambda'
+]
+
+if sys.version_info[0] > 2:
+    if sys.version_info[1] < 3:
+        collect_ignore.append('tests/contrib/flask')
+    if sys.version_info[1] == 2:
+        collect_ignore.append('tests/handlers/logbook')
+
+try:
+    import gevent  # NOQA
+except ImportError:
+    collect_ignore.append('tests/transport/gevent')
+
+try:
+    import web  # NOQA
+except ImportError:
+    collect_ignore.append('tests/contrib/webpy')
+
+try:
+    import django  # NOQA
+except ImportError:
+    django = None
+    collect_ignore.append('tests/contrib/django')
+
+try:
+    import tastypie  # NOQA
+except ImportError:
+    collect_ignore.append('tests/contrib/django/test_tastypie.py')
+
+
+use_djcelery = True
+try:
+    import djcelery  # NOQA
+    #INSTALLED_APPS.append('djcelery')
+except ImportError:
+    use_djcelery = False
+
+
+def pytest_runtest_teardown(item):
+    if django:
+        from raven.contrib.django.models import client
+        client.events = []
+
+
+ at pytest.fixture
+def project_root():
+    return os.path.dirname(os.path.abspath(__file__))
+
+
+ at pytest.fixture
+def mytest_model():
+
+    from tests.contrib.django.models import MyTestModel
+    return MyTestModel
+
+
+ at pytest.fixture(scope='function', autouse=False)
+def user_instance(request, admin_user):
+    request.cls.user = admin_user
+
+
+ at pytest.fixture(autouse=True)
+def has_git_requirements(request, project_root):
+    if request.node.get_marker('has_git_requirements'):
+        if not os.path.exists(os.path.join(project_root, '.git', 'refs', 'heads', 'master')):
+            pytest.skip('skipped test as project is not a git repo')
diff --git a/raven.egg-info/PKG-INFO b/raven.egg-info/PKG-INFO
index d14e2db..a9105da 100644
--- a/raven.egg-info/PKG-INFO
+++ b/raven.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: raven
-Version: 6.0.0
+Version: 6.3.0
 Summary: Raven is a client for Sentry (https://getsentry.com)
 Home-page: https://github.com/getsentry/raven-python
 Author: Sentry
@@ -21,10 +21,13 @@ Classifier: Intended Audience :: Developers
 Classifier: Intended Audience :: System Administrators
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python
 Classifier: Topic :: Software Development
diff --git a/raven.egg-info/SOURCES.txt b/raven.egg-info/SOURCES.txt
index 2b43023..75d4d4d 100644
--- a/raven.egg-info/SOURCES.txt
+++ b/raven.egg-info/SOURCES.txt
@@ -1,6 +1,7 @@
 LICENSE
 MANIFEST.in
 README.rst
+conftest.py
 setup.cfg
 setup.py
 raven/__init__.py
@@ -26,6 +27,7 @@ raven/contrib/__init__.py
 raven/contrib/async.py
 raven/contrib/flask.py
 raven/contrib/paste.py
+raven/contrib/awslambda/__init__.py
 raven/contrib/bottle/__init__.py
 raven/contrib/bottle/utils.py
 raven/contrib/celery/__init__.py
@@ -64,6 +66,7 @@ raven/contrib/pylons/__init__.py
 raven/contrib/tornado/__init__.py
 raven/contrib/webpy/__init__.py
 raven/contrib/webpy/utils.py
+raven/contrib/zconfig/__init__.py
 raven/contrib/zerorpc/__init__.py
 raven/contrib/zope/__init__.py
 raven/contrib/zope/component.xml
@@ -114,12 +117,15 @@ tests/contrib/__init__.py
 tests/contrib/test_celery.py
 tests/contrib/async/__init__.py
 tests/contrib/async/tests.py
+tests/contrib/awslambda/conftest.py
+tests/contrib/awslambda/test_lambda.py
 tests/contrib/bottle/__init__.py
 tests/contrib/bottle/tests.py
 tests/contrib/django/__init__.py
 tests/contrib/django/api.py
 tests/contrib/django/middleware.py
 tests/contrib/django/models.py
+tests/contrib/django/settings.py
 tests/contrib/django/test_resolver.py
 tests/contrib/django/test_tastypie.py
 tests/contrib/django/tests.py
@@ -139,6 +145,8 @@ tests/contrib/tornado/__init__.py
 tests/contrib/tornado/tests.py
 tests/contrib/webpy/__init__.py
 tests/contrib/webpy/tests.py
+tests/contrib/zconfig/__init__.py
+tests/contrib/zconfig/tests.py
 tests/contrib/zerorpc/__init__.py
 tests/contrib/zerorpc/tests.py
 tests/events/__init__.py
diff --git a/raven.egg-info/requires.txt b/raven.egg-info/requires.txt
index 2df2934..b15bd57 100644
--- a/raven.egg-info/requires.txt
+++ b/raven.egg-info/requires.txt
@@ -1,3 +1,5 @@
+
+[:python_version<"3.2"]
 contextlib2
 
 [flask]
@@ -8,19 +10,26 @@ blinker>=1.1
 bottle
 celery>=2.5
 exam>=0.5.2
-flake8>=2.6,<2.7
+flake8==3.5.0
 logbook
 mock
 nose
 pycodestyle
 pytz
-pytest>=3.0.0,<3.1.0
-pytest-timeout==0.4
+pytest<3.3.0,>=3.2.0
+pytest-timeout==1.2.0
+pytest-xdist==1.18.2
+pytest-pythonpath==0.7.1
+pytest-sugar==0.8
+pytest-assume
+pytest-cov
+pytest-flake8==0.9
 requests
 tornado>=4.1
 webob
 webtest
 anyjson
+ZConfig
 Flask>=0.8
 blinker>=1.1
 Flask-Login>=0.2.0
diff --git a/raven/__init__.py b/raven/__init__.py
index 550b8a8..1e8b754 100644
--- a/raven/__init__.py
+++ b/raven/__init__.py
@@ -12,7 +12,7 @@ import os.path
 
 __all__ = ('VERSION', 'Client', 'get_version')
 
-VERSION = '6.0.0'
+VERSION = '6.3.0'
 
 
 def _get_git_revision(path):
diff --git a/raven/base.py b/raven/base.py
index 6fadbce..652e5e4 100644
--- a/raven/base.py
+++ b/raven/base.py
@@ -17,6 +17,8 @@ import uuid
 import warnings
 
 from datetime import datetime
+from inspect import isclass
+from random import Random
 from types import FunctionType
 from threading import local
 
@@ -60,6 +62,9 @@ SDK_VALUE = {
 # singleton for the client
 Raven = None
 
+if sys.version_info >= (3, 2):
+    basestring = str
+
 
 def get_excepthook_client():
     hook = sys.excepthook
@@ -139,6 +144,7 @@ class Client(object):
     >>>     ident = client.get_ident(client.captureException())
     >>>     print "Exception caught; reference is %s" % ident
     """
+
     logger = logging.getLogger('raven')
     protocol_version = '6'
 
@@ -146,7 +152,8 @@ class Client(object):
 
     def __init__(self, dsn=None, raise_send_errors=False, transport=None,
                  install_sys_hook=True, install_logging_hook=True,
-                 hook_libraries=None, enable_breadcrumbs=True, **options):
+                 hook_libraries=None, enable_breadcrumbs=True,
+                 _random_seed=None, **options):
         global Raven
 
         o = options
@@ -191,12 +198,18 @@ class Client(object):
         self.environment = o.get('environment') or None
         self.release = o.get('release') or os.environ.get('HEROKU_SLUG_COMMIT')
         self.repos = self._format_repos(o.get('repos'))
+        self.sample_rate = (
+            o.get('sample_rate')
+            if o.get('sample_rate') is not None
+            else 1
+        )
         self.transaction = TransactionStack()
-
         self.ignore_exceptions = set(o.get('ignore_exceptions') or ())
 
         self.module_cache = ModuleProxyCache()
 
+        self._random = Random(_random_seed)
+
         if not self.is_enabled():
             self.logger.info(
                 'Raven is not configured (logging is disabled). Please see the'
@@ -362,7 +375,6 @@ class Client(object):
         The result of ``build_msg`` should be a standardized dict, with
         all default values available.
         """
-
         # create ID client-side so that it can be passed to application
         event_id = uuid.uuid4().hex
 
@@ -548,13 +560,15 @@ class Client(object):
         Update the tags context for future events.
 
         >>> client.tags_context({'version': '1.0'})
+
         """
         return self.context.merge({
             'tags': data,
         })
 
     def capture(self, event_type, data=None, date=None, time_spent=None,
-                extra=None, stack=None, tags=None, **kwargs):
+                extra=None, stack=None, tags=None, sample_rate=None,
+                **kwargs):
         """
         Captures and processes an event and pipes it off to SentryClient.send.
 
@@ -602,9 +616,9 @@ class Client(object):
         :param extra: a dictionary of additional standard metadata
         :param stack: a stacktrace for the event
         :param tags: dict of extra tags
+        :param sample_rate: a float in the range [0, 1] to sample this message
         :return: a tuple with a 32-length string identifying this event
         """
-
         if not self.is_enabled():
             return
 
@@ -623,7 +637,12 @@ class Client(object):
             event_type, data, date, time_spent, extra, stack, tags=tags,
             **kwargs)
 
-        self.send(**data)
+        # should this event be sampled?
+        if sample_rate is None:
+            sample_rate = self.sample_rate
+
+        if self._random.random() < sample_rate:
+            self.send(**data)
 
         self._local_state.last_event_id = data['event_id']
 
@@ -641,7 +660,7 @@ class Client(object):
             for frame in data['stacktrace']['frames']:
                 yield frame
         if 'exception' in data:
-            for frame in data['exception']['values'][-1]['stacktrace']['frames']:
+            for frame in data['exception']['values'][-1]['stacktrace'].get('frames', []):
                 yield frame
 
     def _successful_send(self):
@@ -675,7 +694,7 @@ class Client(object):
         output = [message]
         if 'exception' in data and 'stacktrace' in data['exception']['values'][-1]:
             # try to reconstruct a reasonable version of the exception
-            for frame in data['exception']['values'][-1]['stacktrace']['frames']:
+            for frame in data['exception']['values'][-1]['stacktrace'].get('frames', []):
                 output.append('  File "%(fn)s", line %(lineno)s, in %(func)s' % {
                     'fn': frame.get('filename', 'unknown_filename'),
                     'lineno': frame.get('lineno', -1),
@@ -802,12 +821,19 @@ class Client(object):
         exc_type = exc_info[0]
         exc_name = '%s.%s' % (exc_type.__module__, exc_type.__name__)
         exclusions = self.ignore_exceptions
+        string_exclusions = (e for e in exclusions if isinstance(e, basestring))
+        wildcard_exclusions = (e for e in string_exclusions if e.endswith('*'))
+        class_exclusions = (e for e in exclusions if isclass(e))
 
-        if exc_type.__name__ in exclusions:
+        if exc_type in exclusions:
+            return False
+        elif exc_type.__name__ in exclusions:
             return False
         elif exc_name in exclusions:
             return False
-        elif any(exc_name.startswith(e[:-1]) for e in exclusions if e.endswith('*')):
+        elif any(issubclass(exc_type, e) for e in class_exclusions):
+            return False
+        elif any(exc_name.startswith(e[:-1]) for e in wildcard_exclusions):
             return False
         return True
 
@@ -876,7 +902,8 @@ class Client(object):
         return self.context(**kwargs)
 
     def captureBreadcrumb(self, *args, **kwargs):
-        """Records a breadcrumb with the current context.  They will be
+        """
+        Records a breadcrumb with the current context.  They will be
         sent with the next event.
         """
         # Note: framework integration should not call this method but
@@ -896,6 +923,7 @@ class Client(object):
 
 
 class DummyClient(Client):
-    "Sends messages into an empty void"
+    """Sends messages into an empty void."""
+
     def send(self, **kwargs):
         return None
diff --git a/raven/breadcrumbs.py b/raven/breadcrumbs.py
index 812e96f..3980b88 100644
--- a/raven/breadcrumbs.py
+++ b/raven/breadcrumbs.py
@@ -1,5 +1,6 @@
 from __future__ import absolute_import
 
+import os
 import time
 import logging
 from types import FunctionType
@@ -154,6 +155,12 @@ def _wrap_logging_method(meth, level=None):
 
     code = get_code(func)
 
+    logging_srcfile = logging._srcfile
+    if logging_srcfile is None:
+        logging_srcfile = os.path.normpath(
+            logging.currentframe.__code__.co_filename
+        )
+
     # This requires a bit of explanation why we're doing this.  Due to how
     # logging itself works we need to pretend that the method actually was
     # created within the logging module.  There are a few ways to detect
@@ -183,7 +190,7 @@ def _wrap_logging_method(meth, level=None):
         'args': ', '.join(args),
         'fwd': fwd,
         'level': level,
-    }, logging._srcfile, 'exec'), logging.__dict__, ns)
+    }, logging_srcfile, 'exec'), logging.__dict__, ns)
 
     new_func = ns['factory'](meth, _record_log_breadcrumb)
     new_func.__doc__ = func.__doc__
diff --git a/raven/conf/defaults.py b/raven/conf/defaults.py
index 073e01a..3505a09 100644
--- a/raven/conf/defaults.py
+++ b/raven/conf/defaults.py
@@ -15,7 +15,7 @@ import socket
 
 ROOT = os.path.normpath(os.path.join(os.path.dirname(__file__), os.pardir))
 
-TIMEOUT = 1
+TIMEOUT = 5
 
 # TODO: this is specific to Django
 CLIENT = 'raven.contrib.django.DjangoClient'
diff --git a/raven/contrib/async.py b/raven/contrib/async.py
index 4f94abb..251e4f8 100644
--- a/raven/contrib/async.py
+++ b/raven/contrib/async.py
@@ -17,6 +17,7 @@ class AsyncClient(Client):
     """
     This client uses a single background thread to dispatch errors.
     """
+
     def __init__(self, worker=None, *args, **kwargs):
         warnings.warn('AsyncClient is deprecated. Use the threaded+http transport instead.', DeprecationWarning)
         self.worker = worker or AsyncWorker()
diff --git a/raven/contrib/awslambda/__init__.py b/raven/contrib/awslambda/__init__.py
new file mode 100644
index 0000000..7d6f2b8
--- /dev/null
+++ b/raven/contrib/awslambda/__init__.py
@@ -0,0 +1,173 @@
+"""
+raven.contrib.awslambda
+~~~~~~~~~~~~~~~~~~~~
+
+Raven wrapper for AWS Lambda handlers.
+
+:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
+:license: BSD, see LICENSE for more details.
+"""
+# flake8: noqa
+
+from __future__ import absolute_import
+
+import os
+import logging
+import functools
+from types import FunctionType
+
+from raven.base import Client
+from raven.transport.http import HTTPTransport
+
+logger = logging.getLogger('sentry.errors.client')
+
+
+def get_default_tags():
+    return {
+        'lambda': 'AWS_LAMBDA_FUNCTION_NAME',
+        'version': 'AWS_LAMBDA_FUNCTION_VERSION',
+        'memory_size': 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE',
+        'log_group': 'AWS_LAMBDA_LOG_GROUP_NAME',
+        'log_stream': 'AWS_LAMBDA_LOG_STREAM_NAME',
+        'region': 'AWS_REGION'
+    }
+
+
+class LambdaClient(Client):
+    """
+    Raven decorator for AWS Lambda.
+
+    By default, the lambda integration will capture unhandled exceptions and instrument logging.
+
+    Usage:
+
+    >>> from raven.contrib.awslambda import LambdaClient
+    >>>
+    >>>
+    >>> client = LambdaClient()
+    >>>
+    >>> @client.capture_exceptions
+    >>> def handler(event, context):
+    >>>    ...
+    >>>    raise Exception('I will be sent to sentry!')
+
+    """
+
+    def __init__(self, *args, **kwargs):
+        transport = kwargs.get('transport', HTTPTransport)
+        super(LambdaClient, self).__init__(*args, transport=transport, **kwargs)
+
+    def capture(self, *args, **kwargs):
+        if 'data' not in kwargs:
+            kwargs['data'] = data = {}
+        else:
+            data = kwargs['data']
+        event = kwargs.get('event', None)
+        context = kwargs.get('context', None)
+        user_info = self._get_user_interface(event)
+        if user_info:
+            data.update(user_info)
+        if event:
+            http_info = self._get_http_interface(event)
+            if http_info:
+                data.update(http_info)
+            data['extra'] = self._get_extra_data(event, context)
+        return super(LambdaClient, self).capture(*args, **kwargs)
+
+    def build_msg(self, *args, **kwargs):
+
+        data = super(LambdaClient, self).build_msg(*args, **kwargs)
+        for option, default in get_default_tags().items():
+            data['tags'].setdefault(option, os.environ.get(default))
+        data.setdefault('release', os.environ.get('SENTRY_RELEASE'))
+        data.setdefault('environment', os.environ.get('SENTRY_ENVIRONMENT'))
+        return data
+
+    def capture_exceptions(self, f=None, exceptions=None):  # TODO: Ash fix kwargs in base
+        """
+        Wrap a function or code block in try/except and automatically call
+        ``.captureException`` if it raises an exception, then the exception
+        is reraised.
+
+        By default, it will capture ``Exception``
+
+        >>> @client.capture_exceptions
+        >>> def foo():
+        >>>     raise Exception()
+
+        >>> with client.capture_exceptions():
+        >>>    raise Exception()
+
+        You can also specify exceptions to be caught specifically
+
+        >>> @client.capture_exceptions((IOError, LookupError))
+        >>> def bar():
+        >>>     ...
+
+        ``kwargs`` are passed through to ``.captureException``.
+        """
+        if not isinstance(f, FunctionType):
+            # when the decorator has args which is not a function we except
+            # f to be the exceptions tuple
+            return functools.partial(self.capture_exceptions, exceptions=f)
+
+        exceptions = exceptions or (Exception,)
+
+        @functools.wraps(f)
+        def wrapped(event, context, *args, **kwargs):
+            try:
+                return f(event, context, *args, **kwargs)
+            except exceptions:
+                self.captureException(event=event, context=context, **kwargs)
+                self.context.clear()
+                raise
+        return wrapped
+
+    @staticmethod
+    def _get_user_interface(event):
+        if event.get('requestContext'):
+            identity = event['requestContext']['identity']
+            if identity:
+                user = {
+                    'id': identity.get('cognitoIdentityId', None) or identity.get('user', None),
+                    'username': identity.get('user', None),
+                    'ip_address': identity.get('sourceIp', None),
+                    'cognito_identity_pool_id': identity.get('cognitoIdentityPoolId', None),
+                    'cognito_authentication_type': identity.get('cognitoAuthenticationType', None),
+                    'user_agent': identity.get('userAgent')
+                }
+                return {'user': user}
+
+    @staticmethod
+    def _get_http_interface(event):
+        if event.get('path') and event.get('httpMethod'):
+            request = {
+                "url": event.get('path'),
+                "method": event.get('httpMethod'),
+                "query_string": event.get('queryStringParameters', None),
+                "headers": event.get('headers', None) or [],
+            }
+            return {'request': request}
+
+    @staticmethod
+    def _get_extra_data(event, context):
+        extra_context = {
+            'event': event,
+            'aws_request_id': context.aws_request_id,
+            'context': vars(context),
+        }
+
+        if context.client_context:
+            extra_context['client_context'] = {
+                'client.installation_id': context.client_context.client.installation_id,
+                'client.app_title': context.client_context.client.app_title,
+                'client.app_version_name': context.client_context.client.app_version_name,
+                'client.app_version_code': context.client_context.client.app_version_code,
+                'client.app_package_name': context.client_context.client.app_package_name,
+                'custom': context.client_context.custom,
+                'env': context.client_context.env,
+            }
+        return extra_context
+
+
+
diff --git a/raven/contrib/bottle/__init__.py b/raven/contrib/bottle/__init__.py
index d9f845b..de82c85 100644
--- a/raven/contrib/bottle/__init__.py
+++ b/raven/contrib/bottle/__init__.py
@@ -37,6 +37,7 @@ class Sentry(object):
 
     >>> sentry.captureMessage('hello, world!')
     """
+
     def __init__(self, app, client, logging=False):
         self.app = app
         self.client = client
diff --git a/raven/contrib/celery/__init__.py b/raven/contrib/celery/__init__.py
index edf2c42..d4fd759 100644
--- a/raven/contrib/celery/__init__.py
+++ b/raven/contrib/celery/__init__.py
@@ -73,7 +73,7 @@ class SentryCeleryHandler(object):
 
         # This signal is fired inside the stack so let raven do its magic
         if isinstance(einfo.exception, SoftTimeLimitExceeded):
-            fingerprint = ['celery', 'SoftTimeLimitExceeded', sender]
+            fingerprint = ['celery', 'SoftTimeLimitExceeded', getattr(sender, 'name', sender)]
         else:
             fingerprint = None
 
@@ -88,7 +88,9 @@ class SentryCeleryHandler(object):
         )
 
     def handle_task_prerun(self, sender, task_id, task, **kw):
+        self.client.context.activate()
         self.client.transaction.push(task.name)
 
     def handle_task_postrun(self, sender, task_id, task, **kw):
         self.client.transaction.pop(task.name)
+        self.client.context.clear()
diff --git a/raven/contrib/django/__init__.py b/raven/contrib/django/__init__.py
index 23036a6..4ce0b95 100644
--- a/raven/contrib/django/__init__.py
+++ b/raven/contrib/django/__init__.py
@@ -9,5 +9,4 @@ from __future__ import absolute_import
 
 default_app_config = 'raven.contrib.django.apps.RavenConfig'
 
-
 from .client import DjangoClient  # NOQA
diff --git a/raven/contrib/django/apps.py b/raven/contrib/django/apps.py
index 7aaf4ff..db33b38 100644
--- a/raven/contrib/django/apps.py
+++ b/raven/contrib/django/apps.py
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 from __future__ import absolute_import
+
 from django.apps import AppConfig
 
 
@@ -7,3 +8,7 @@ class RavenConfig(AppConfig):
     name = 'raven.contrib.django'
     label = 'raven_contrib_django'
     verbose_name = 'Raven'
+
+    def ready(self):
+        from .models import initialize
+        initialize()
diff --git a/raven/contrib/django/client.py b/raven/contrib/django/client.py
index 6f81a62..a161342 100644
--- a/raven/contrib/django/client.py
+++ b/raven/contrib/django/client.py
@@ -12,6 +12,7 @@ from __future__ import absolute_import
 import time
 import logging
 
+from django import VERSION as DJANGO_VERSION
 from django.conf import settings
 from django.core.exceptions import SuspiciousOperation
 from django.http import HttpRequest
@@ -30,13 +31,21 @@ from raven.contrib.django.utils import get_data_from_template, get_host
 from raven.contrib.django.middleware import SentryMiddleware
 from raven.utils.compat import string_types, binary_type, iterlists
 from raven.contrib.django.resolver import RouteResolver
-from raven.utils.wsgi import get_headers, get_environ
+from raven.utils.wsgi import get_headers, get_environ, get_client_ip
 from raven.utils import once
 from raven import breadcrumbs
 
 __all__ = ('DjangoClient',)
 
 
+if DJANGO_VERSION < (1, 10):
+    def is_authenticated(request_user):
+        return request_user.is_authenticated()
+else:
+    def is_authenticated(request_user):
+        return request_user.is_authenticated
+
+
 class _FormatConverter(object):
 
     def __init__(self, param_mapping):
@@ -142,19 +151,19 @@ class DjangoClient(Client):
     def install_sql_hook(self):
         install_sql_hook()
 
-    def get_user_info(self, user):
-        try:
-            if hasattr(user, 'is_authenticated'):
-                # is_authenticated was a method in Django < 1.10
-                if callable(user.is_authenticated):
-                    authenticated = user.is_authenticated()
-                else:
-                    authenticated = user.is_authenticated
-                if not authenticated:
-                    return None
+    def get_user_info(self, request):
 
-            user_info = {}
+        user_info = {
+            'ip_address': get_client_ip(request.META),
+        }
+        user = getattr(request, 'user', None)
+        if user is None:
+            return user_info
 
+        try:
+            authenticated = is_authenticated(user)
+            if not authenticated:
+                return user_info
             user_info['id'] = user.pk
 
             if hasattr(user, 'email'):
@@ -164,22 +173,18 @@ class DjangoClient(Client):
                 user_info['username'] = user.get_username()
             elif hasattr(user, 'username'):
                 user_info['username'] = user.username
-
-            return user_info
         except Exception:
             # We expect that user objects can be somewhat broken at times
             # and try to just handle as much as possible and ignore errors
... 1803 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/raven.git



More information about the Python-modules-commits mailing list