From 97e93ea7baf4aadecbe3f14ba1b87f3b0917c2af Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Tue, 12 Jan 2016 21:40:51 +0100 Subject: [PATCH] Strip six module and rename to raven._compat We're seeing some odd issues with our six module interacting badly with the six module from other libraries for some users. The suspicion is that our six module in some cases gets unvendored. We thus rename it to `raven._compat` (which is also what some other Python modules do). We still use six normally for the tests. --- hooks/pre-commit.flake8 | 8 +- raven/_compat.py | 177 ++++++++++++ raven/base.py | 23 +- raven/conf/remote.py | 6 +- raven/context.py | 6 +- raven/contrib/django/models.py | 12 +- raven/contrib/django/serializers.py | 11 +- raven/contrib/django/views.py | 4 +- raven/contrib/flask.py | 16 +- raven/exceptions.py | 4 +- raven/handlers/logbook.py | 4 +- raven/handlers/logging.py | 28 +- raven/processors.py | 8 +- raven/transport/http.py | 6 +- raven/utils/__init__.py | 15 +- raven/utils/encoding.py | 31 ++- raven/utils/imports.py | 4 +- raven/utils/serializer/base.py | 41 +-- raven/utils/serializer/manager.py | 12 +- raven/utils/six.py | 406 ---------------------------- raven/utils/stacks.py | 16 +- raven/utils/wsgi.py | 4 +- raven/versioning.py | 19 +- setup.py | 1 + tests/base/tests.py | 2 +- tests/contrib/django/tests.py | 4 +- tests/contrib/tornado/tests.py | 2 +- tests/handlers/logbook/tests.py | 2 +- tests/handlers/logging/tests.py | 2 +- tests/utils/encoding/tests.py | 3 +- tests/utils/stacks/tests.py | 3 +- tests/utils/test_imports.py | 3 +- tests/versioning/tests.py | 2 +- 33 files changed, 350 insertions(+), 535 deletions(-) create mode 100644 raven/_compat.py delete mode 100644 raven/utils/six.py diff --git a/hooks/pre-commit.flake8 b/hooks/pre-commit.flake8 index 76932680..1850e908 100755 --- a/hooks/pre-commit.flake8 +++ b/hooks/pre-commit.flake8 @@ -20,13 +20,17 @@ def main(): from flake8.main import DEFAULT_CONFIG from flake8.engine import get_style_guide from flake8.hooks import run - from raven.utils import six gitcmd = "git diff-index --cached --name-only HEAD" _, files_modified, _ = run(gitcmd) - files_modified = [six.text_type(x) for x in files_modified] + try: + text_type = unicode + except NameError: + text_type = str + + files_modified = [text_type(x) for x in files_modified] # remove non-py files and files which no longer exist files_modified = filter( diff --git a/raven/_compat.py b/raven/_compat.py new file mode 100644 index 00000000..bd5c5e79 --- /dev/null +++ b/raven/_compat.py @@ -0,0 +1,177 @@ +"""Utilities for writing code that runs on Python 2 and 3""" +# flake8: noqa + +# Copyright (c) 2010-2013 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from __future__ import absolute_import + +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.3.0" + + +PY2 = sys.version_info[0] == 2 + +if not PY2: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +if not PY2: + _iterkeys = "keys" + _itervalues = "values" + _iteritems = "items" + _iterlists = "lists" +else: + _iterkeys = "iterkeys" + _itervalues = "itervalues" + _iteritems = "iteritems" + _iterlists = "iterlists" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +def iterkeys(d, **kw): + """Return an iterator over the keys of a dictionary.""" + return iter(getattr(d, _iterkeys)(**kw)) + + +def itervalues(d, **kw): + """Return an iterator over the values of a dictionary.""" + return iter(getattr(d, _itervalues)(**kw)) + + +def iteritems(d, **kw): + """Return an iterator over the (key, value) pairs of a dictionary.""" + return iter(getattr(d, _iteritems)(**kw)) + + +def iterlists(d, **kw): + """Return an iterator over the (key, [values]) pairs of a dictionary.""" + return iter(getattr(d, _iterlists)(**kw)) + + +if not PY2: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + if sys.version_info[1] <= 1: + def int2byte(i): + return bytes((i,)) + else: + # This is about 2x faster than the implementation above on 3.2+ + int2byte = operator.methodcaller("to_bytes", 1, "big") + import io + StringIO = io.StringIO + BytesIO = io.BytesIO +else: + def b(s): # NOQA + return s + + def u(s): # NOQA + return unicode(s, "unicode_escape") + int2byte = chr + import StringIO + StringIO = BytesIO = StringIO.StringIO + + +if not PY2: + import builtins + exec_ = getattr(builtins, "exec") + + def reraise(tp, value, tb=None): + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + + del builtins + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + +def with_metaclass(meta, base=object): + """Create a base class with a metaclass.""" + return meta("NewBase", (base,), {}) diff --git a/raven/base.py b/raven/base.py index 5065bca1..21d7a178 100644 --- a/raven/base.py +++ b/raven/base.py @@ -30,7 +30,8 @@ from raven.conf import defaults from raven.conf.remote import RemoteConfig from raven.context import Context from raven.exceptions import APIError, RateLimited -from raven.utils import six, json, get_versions, get_auth_header, merge_dicts +from raven.utils import json, get_versions, get_auth_header, merge_dicts +from raven._compat import text_type, iteritems from raven.utils.encoding import to_unicode from raven.utils.serializer import transform from raven.utils.stacks import get_stack_info, iter_stack_frames, get_culprit @@ -145,7 +146,7 @@ class Client(object): self.include_paths = set(o.get('include_paths') or []) self.exclude_paths = set(o.get('exclude_paths') or []) - self.name = six.text_type(o.get('name') or o.get('machine') or defaults.NAME) + self.name = text_type(o.get('name') or o.get('machine') or defaults.NAME) self.auto_log_stacks = bool( o.get('auto_log_stacks') or defaults.AUTO_LOG_STACKS) self.capture_locals = bool( @@ -252,7 +253,8 @@ class Client(object): >>> result = client.capture(**kwargs) >>> ident = client.get_ident(result) """ - warnings.warn('Client.get_ident is deprecated. The event ID is now returned as the result of capture.', + warnings.warn('Client.get_ident is deprecated. The event ID is now ' + 'returned as the result of capture.', DeprecationWarning) return result @@ -306,7 +308,7 @@ class Client(object): if data.get('culprit'): culprit = data['culprit'] - for k, v in six.iteritems(result): + for k, v in iteritems(result): if k not in data: data[k] = v @@ -394,11 +396,11 @@ class Client(object): data['message'] = kwargs.get('message', handler.to_string(data)) # tags should only be key=>u'value' - for key, value in six.iteritems(data['tags']): + for key, value in iteritems(data['tags']): data['tags'][key] = to_unicode(value) # extra data can be any arbitrary value - for k, v in six.iteritems(data['extra']): + for k, v in iteritems(data['extra']): data['extra'][k] = self.transform(v) # It's important date is added **after** we serialize @@ -556,7 +558,8 @@ class Client(object): if isinstance(exc, RateLimited): retry_after = exc.retry_after self.error_logger.error( - 'Sentry responded with an API error: %s(%s)', type(exc).__name__, exc.message) + 'Sentry responded with an API error: %s(%s)', + type(exc).__name__, exc.message) else: self.error_logger.error( 'Sentry responded with an error: %s (url: %s)\n%s', @@ -577,10 +580,10 @@ class Client(object): if 'exception' in data and 'stacktrace' in data['exception']['values'][0]: # try to reconstruct a reasonable version of the exception for frame in data['exception']['values'][0]['stacktrace']['frames']: - output.append(' File "%(filename)s", line %(lineno)s, in %(function)s' % { - 'filename': frame['filename'], + output.append(' File "%(fn)s", line %(lineno)s, in %(func)s' % { + 'fn': frame['filename'], 'lineno': frame['lineno'], - 'function': frame['function'], + 'func': frame['function'], }) self.uncaught_logger.error(output) diff --git a/raven/conf/remote.py b/raven/conf/remote.py index e720bfd9..f0918315 100644 --- a/raven/conf/remote.py +++ b/raven/conf/remote.py @@ -2,9 +2,9 @@ from __future__ import absolute_import import warnings +from raven._compat import PY2, text_type from raven.exceptions import InvalidDsn from raven.transport.threaded import ThreadedHTTPTransport -from raven.utils import six from raven.utils.encoding import to_string from raven.utils.urlparse import parse_qsl, urlparse @@ -32,7 +32,7 @@ class RemoteConfig(object): self._transport_cls = transport or DEFAULT_TRANSPORT def __unicode__(self): - return six.text_type(self.base_url) + return text_type(self.base_url) def is_active(self): return all([self.base_url, self.project, self.public_key, self.secret_key]) @@ -58,7 +58,7 @@ class RemoteConfig(object): def from_string(cls, value, transport=None, transport_registry=None): # in Python 2.x sending the DSN as a unicode value will eventually # cause issues in httplib - if not six.PY3: + if PY2: value = to_string(value) url = urlparse(value) diff --git a/raven/context.py b/raven/context.py index 5d939392..e941360c 100644 --- a/raven/context.py +++ b/raven/context.py @@ -10,7 +10,7 @@ from __future__ import absolute_import from collections import Mapping, Iterable from threading import local -from raven.utils import six +from raven._compat import iteritems class Context(local, Mapping, Iterable): @@ -42,10 +42,10 @@ class Context(local, Mapping, Iterable): def merge(self, data): d = self.data - for key, value in six.iteritems(data): + for key, value in iteritems(data): if key in ('tags', 'extra'): d.setdefault(key, {}) - for t_key, t_value in six.iteritems(value): + for t_key, t_value in iteritems(value): d[key][t_key] = t_value else: d[key] = value diff --git a/raven/contrib/django/models.py b/raven/contrib/django/models.py index 5172fcf1..62f2de8f 100644 --- a/raven/contrib/django/models.py +++ b/raven/contrib/django/models.py @@ -19,7 +19,7 @@ import warnings from django.conf import settings from hashlib import md5 -from raven.utils import six +from raven._compat import PY2, binary_type, text_type from raven.utils.imports import import_string from raven.contrib.django.management import patch_cli_runner @@ -61,7 +61,7 @@ class ProxyClient(object): __ne__ = lambda x, o: get_client() != o __gt__ = lambda x, o: get_client() > o __ge__ = lambda x, o: get_client() >= o - if not six.PY3: + if PY2: __cmp__ = lambda x, o: cmp(get_client(), o) # NOQA __hash__ = lambda x: hash(get_client()) # attributes are currently not callable @@ -92,11 +92,11 @@ class ProxyClient(object): __invert__ = lambda x: ~(get_client()) __complex__ = lambda x: complex(get_client()) __int__ = lambda x: int(get_client()) - if not six.PY3: + if PY2: __long__ = lambda x: long(get_client()) # NOQA __float__ = lambda x: float(get_client()) - __str__ = lambda x: six.binary_type(get_client()) - __unicode__ = lambda x: six.text_type(get_client()) + __str__ = lambda x: binary_type(get_client()) + __unicode__ = lambda x: text_type(get_client()) __oct__ = lambda x: oct(get_client()) __hex__ = lambda x: hex(get_client()) __index__ = lambda x: get_client().__index__() @@ -139,7 +139,7 @@ def get_client(client=None, reset=False): options.setdefault('release', ga('RELEASE')) transport = ga('TRANSPORT') or options.get('transport') - if isinstance(transport, six.string_types): + if isinstance(transport, string_types): transport = import_string(transport) options['transport'] = transport diff --git a/raven/contrib/django/serializers.py b/raven/contrib/django/serializers.py index f0110791..50c02362 100644 --- a/raven/contrib/django/serializers.py +++ b/raven/contrib/django/serializers.py @@ -12,7 +12,7 @@ from django.conf import settings from django.http import HttpRequest from django.utils.functional import Promise from raven.utils.serializer import Serializer, register -from raven.utils import six +from raven._compat import text_type __all__ = ('PromiseSerializer',) @@ -34,12 +34,15 @@ class PromiseSerializer(Serializer): def serialize(self, value, **kwargs): # EPIC HACK - # handles lazy model instances (which are proxy values that don't easily give you the actual function) + # handles lazy model instances (which are proxy values that don't + # easily give you the actual function) pre = value.__class__.__name__[1:] if hasattr(value, '%s__func' % pre): - value = getattr(value, '%s__func' % pre)(*getattr(value, '%s__args' % pre), **getattr(value, '%s__kw' % pre)) + value = getattr(value, '%s__func' % pre)( + *getattr(value, '%s__args' % pre), + **getattr(value, '%s__kw' % pre)) else: - return self.recurse(six.text_type(value)) + return self.recurse(text_type(value)) return self.recurse(value, **kwargs) register(PromiseSerializer) diff --git a/raven/contrib/django/views.py b/raven/contrib/django/views.py index bba95e22..aabbd71e 100644 --- a/raven/contrib/django/views.py +++ b/raven/contrib/django/views.py @@ -15,9 +15,9 @@ from django.views.decorators.cache import never_cache from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_http_methods +from raven._compat import string_types from raven.contrib.django.models import client from raven.utils import json -from raven.utils import six def is_valid_origin(origin): @@ -32,7 +32,7 @@ def is_valid_origin(origin): origin = origin.lower() for value in settings.SENTRY_ALLOW_ORIGIN: - if isinstance(value, six.string_types): + if isinstance(value, string_types): if value.lower() == origin: return True else: diff --git a/raven/contrib/flask.py b/raven/contrib/flask.py index 0ab48989..d1781779 100644 --- a/raven/contrib/flask.py +++ b/raven/contrib/flask.py @@ -23,11 +23,11 @@ from flask import request, current_app, g from flask.signals import got_request_exception, request_finished from werkzeug.exceptions import ClientDisconnected +from raven._compat import string_types from raven.conf import setup_logging from raven.base import Client from raven.middleware import Sentry as SentryMiddleware from raven.handlers.logging import SentryHandler -from raven.utils import six from raven.utils.compat import _urlparse from raven.utils.encoding import to_unicode from raven.utils.imports import import_string @@ -38,13 +38,14 @@ def make_client(client_cls, app, dsn=None): # TODO(dcramer): django and Flask share very similar concepts here, and # should be refactored transport = app.config.get('SENTRY_TRANSPORT') - if isinstance(transport, six.string_types): + if isinstance(transport, string_types): transport = import_string(transport) return client_cls( dsn=dsn or app.config.get('SENTRY_DSN') or os.environ.get('SENTRY_DSN'), transport=transport, - include_paths=set(app.config.get('SENTRY_INCLUDE_PATHS', [])) | set([app.import_name]), + include_paths=set(app.config.get( + 'SENTRY_INCLUDE_PATHS', [])) | set([app.import_name]), exclude_paths=app.config.get('SENTRY_EXCLUDE_PATHS'), name=app.config.get('SENTRY_NAME'), site=app.config.get('SENTRY_SITE_NAME'), @@ -131,17 +132,20 @@ class Sentry(object): if not self.client: return - ignored_exc_type_list = current_app.config.get('RAVEN_IGNORE_EXCEPTIONS', []) + ignored_exc_type_list = current_app.config.get( + 'RAVEN_IGNORE_EXCEPTIONS', []) exc = sys.exc_info()[1] - if any((isinstance(exc, ignored_exc_type) for ignored_exc_type in ignored_exc_type_list)): + if any((isinstance(exc, ignored_exc_type) + for ignored_exc_type in ignored_exc_type_list)): return self.captureException(exc_info=kwargs.get('exc_info')) def get_user_info(self, request): """ - Requires Flask-Login (https://pypi.python.org/pypi/Flask-Login/) to be installed + Requires Flask-Login (https://pypi.python.org/pypi/Flask-Login/) + to be installed and setup """ if not has_flask_login: diff --git a/raven/exceptions.py b/raven/exceptions.py index 4130839b..ddf5f601 100644 --- a/raven/exceptions.py +++ b/raven/exceptions.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -from raven.utils import six +from raven._compat import text_type class APIError(Exception): @@ -9,7 +9,7 @@ class APIError(Exception): self.message = message def __unicode__(self): - return six.text_type("%s: %s" % (self.message, self.code)) + return text_type("%s: %s" % (self.message, self.code)) class RateLimited(APIError): diff --git a/raven/handlers/logbook.py b/raven/handlers/logbook.py index cae177c1..1edd2de1 100644 --- a/raven/handlers/logbook.py +++ b/raven/handlers/logbook.py @@ -13,16 +13,16 @@ import logbook import sys import traceback +from raven._compat import string_types from raven.base import Client from raven.utils.encoding import to_string -from raven.utils import six class SentryHandler(logbook.Handler): def __init__(self, *args, **kwargs): if len(args) == 1: arg = args[0] - if isinstance(arg, six.string_types): + if isinstance(arg, string_types): self.client = kwargs.pop('client_cls', Client)(dsn=arg, **kwargs) elif isinstance(arg, Client): self.client = arg diff --git a/raven/handlers/logging.py b/raven/handlers/logging.py index ad2e912b..cc82550c 100644 --- a/raven/handlers/logging.py +++ b/raven/handlers/logging.py @@ -14,8 +14,8 @@ import logging import sys import traceback +from raven._compat import string_types, iteritems, text_type from raven.base import Client -from raven.utils import six from raven.utils.encoding import to_string from raven.utils.stacks import iter_stack_frames, label_from_frame @@ -31,15 +31,14 @@ class SentryHandler(logging.Handler, object): client = kwargs.get('client_cls', Client) if len(args) == 1: arg = args[0] - if isinstance(arg, six.string_types): + if isinstance(arg, string_types): self.client = client(dsn=arg, **kwargs) elif isinstance(arg, Client): self.client = arg else: - raise ValueError('The first argument to %s must be either a Client instance or a DSN, got %r instead.' % ( - self.__class__.__name__, - arg, - )) + raise ValueError('The first argument to %s must be either a ' + 'Client instance or a DSN, got %r instead.' % + (self.__class__.__name__, arg,)) elif 'client' in kwargs: self.client = kwargs['client'] else: @@ -68,7 +67,8 @@ class SentryHandler(logging.Handler, object): except Exception: if self.client.raise_send_errors: raise - print("Top level Sentry exception caught - failed creating log record", file=sys.stderr) + print("Top level Sentry exception caught - failed " + "creating log record", file=sys.stderr) print(to_string(record.msg), file=sys.stderr) print(to_string(traceback.format_exc()), file=sys.stderr) @@ -113,7 +113,7 @@ class SentryHandler(logging.Handler, object): else: extra = {} - for k, v in six.iteritems(vars(record)): + for k, v in iteritems(vars(record)): if k in RESERVED: continue if k.startswith('_'): @@ -136,13 +136,13 @@ class SentryHandler(logging.Handler, object): 'params': record.args, } try: - handler_kwargs['message'] = six.text_type(record.msg) + handler_kwargs['message'] = text_type(record.msg) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['message'] = repr(record.msg)[1:-1] try: - handler_kwargs['formatted'] = six.text_type(record.message) + handler_kwargs['formatted'] = text_type(record.message) except UnicodeDecodeError: # Handle binary strings where it should be unicode... handler_kwargs['formatted'] = repr(record.message)[1:-1] @@ -160,8 +160,12 @@ class SentryHandler(logging.Handler, object): handler_kwargs = {'exc_info': record.exc_info} # HACK: discover a culprit when we normally couldn't - elif not (data.get('stacktrace') or data.get('culprit')) and (record.name or record.funcName): - culprit = label_from_frame({'module': record.name, 'function': record.funcName}) + elif not (data.get('stacktrace') or data.get('culprit')) \ + and (record.name or record.funcName): + culprit = label_from_frame({ + 'module': record.name, + 'function': record.funcName + }) if culprit: data['culprit'] = culprit diff --git a/raven/processors.py b/raven/processors.py index bf4e69d6..3f1a74b6 100644 --- a/raven/processors.py +++ b/raven/processors.py @@ -9,8 +9,8 @@ from __future__ import absolute_import import re +from raven._compat import string_types, text_type from raven.utils import varmap -from raven.utils import six class Processor(object): @@ -88,13 +88,13 @@ class SanitizePasswordsProcessor(Processor): if value is None: return - if isinstance(value, six.string_types) and self.VALUES_RE.match(value): + if isinstance(value, string_types) and self.VALUES_RE.match(value): return self.MASK if not key: # key can be a NoneType return value - key = six.text_type(key).lower() + key = text_type(key).lower() for field in self.FIELDS: if field in key: # store mask as a fixed length for security @@ -112,7 +112,7 @@ class SanitizePasswordsProcessor(Processor): if n not in data: continue - if isinstance(data[n], six.string_types) and '=' in data[n]: + if isinstance(data[n], string_types) and '=' in data[n]: # at this point we've assumed it's a standard HTTP query # or cookie if n == 'cookies': diff --git a/raven/transport/http.py b/raven/transport/http.py index a2b968ba..fd840569 100644 --- a/raven/transport/http.py +++ b/raven/transport/http.py @@ -7,10 +7,10 @@ raven.transport.http """ from __future__ import absolute_import +from raven._compat import string_types from raven.conf import defaults from raven.exceptions import APIError, RateLimited from raven.transport.base import Transport -from raven.utils import six from raven.utils.http import urlopen from raven.utils.compat import urllib2 @@ -23,9 +23,9 @@ class HTTPTransport(Transport): self._parsed_url = parsed_url self._url = parsed_url.geturl().rsplit('+', 1)[-1] - if isinstance(timeout, six.string_types): + if isinstance(timeout, string_types): timeout = int(timeout) - if isinstance(verify_ssl, six.string_types): + if isinstance(verify_ssl, string_types): verify_ssl = bool(int(verify_ssl)) self.timeout = timeout diff --git a/raven/utils/__init__.py b/raven/utils/__init__.py index 4477ba36..b4916932 100644 --- a/raven/utils/__init__.py +++ b/raven/utils/__init__.py @@ -7,7 +7,7 @@ raven.utils """ from __future__ import absolute_import -from raven.utils import six +from raven._compat import iteritems, string_types import logging try: import pkg_resources @@ -24,7 +24,7 @@ def merge_dicts(*dicts): if not d: continue - for k, v in six.iteritems(d): + for k, v in iteritems(d): out[k] = v return out @@ -42,7 +42,8 @@ def varmap(func, var, context=None, name=None): return func(name, '<...>') context[objid] = 1 if isinstance(var, dict): - ret = dict((k, varmap(func, v, context, k)) for k, v in six.iteritems(var)) + ret = dict((k, varmap(func, v, context, k)) + for k, v in iteritems(var)) elif isinstance(var, (list, tuple)): ret = [varmap(func, f, context, name) for f in var] else: @@ -79,7 +80,7 @@ def get_version_from_app(module_name, app): if callable(version): version = version() - if not isinstance(version, (six.string_types, list, tuple)): + if not isinstance(version, (string_types, list, tuple)): version = None if version is None: @@ -98,7 +99,8 @@ def get_versions(module_list=None): ext_module_list = set() for m in module_list: parts = m.split('.') - ext_module_list.update('.'.join(parts[:idx]) for idx in range(1, len(parts) + 1)) + ext_module_list.update('.'.join(parts[:idx]) + for idx in range(1, len(parts) + 1)) versions = {} for module_name in ext_module_list: @@ -128,7 +130,8 @@ def get_versions(module_list=None): return versions -def get_auth_header(protocol, timestamp, client, api_key, api_secret=None, **kwargs): +def get_auth_header(protocol, timestamp, client, api_key, + api_secret=None, **kwargs): header = [ ('sentry_timestamp', timestamp), ('sentry_client', client), diff --git a/raven/utils/encoding.py b/raven/utils/encoding.py index 3bb98291..cf8bca5d 100644 --- a/raven/utils/encoding.py +++ b/raven/utils/encoding.py @@ -8,7 +8,9 @@ raven.utils.encoding from __future__ import absolute_import, unicode_literals import warnings -from raven.utils import six + +from raven._compat import integer_types, text_type, binary_type, \ + string_types, PY2 def is_protected_type(obj): @@ -19,7 +21,7 @@ def is_protected_type(obj): """ import Decimal import datetime - return isinstance(obj, six.integer_types + (type(None), float, Decimal, + return isinstance(obj, integer_types + (type(None), float, Decimal, datetime.datetime, datetime.date, datetime.time)) @@ -31,25 +33,25 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'): If strings_only is True, don't convert (some) non-string-like objects. """ # Handle the common case first, saves 30-40% when s is an instance of - # six.text_type. This function gets called often in that setting. - if isinstance(s, six.text_type): + # text_type. This function gets called often in that setting. + if isinstance(s, text_type): return s if strings_only and is_protected_type(s): return s try: - if not isinstance(s, six.string_types): + if not isinstance(s, string_types): if hasattr(s, '__unicode__'): s = s.__unicode__() else: - if six.PY3: + if not PY2: if isinstance(s, bytes): - s = six.text_type(s, encoding, errors) + s = text_type(s, encoding, errors) else: - s = six.text_type(s) + s = text_type(s) else: - s = six.text_type(bytes(s), encoding, errors) + s = text_type(bytes(s), encoding, errors) else: - # Note: We use .decode() here, instead of six.text_type(s, encoding, + # Note: We use .decode() here, instead of text_type(s, encoding, # errors), so that if s is a SafeBytes, it ends up being a # SafeText at the end. s = s.decode(encoding, errors) @@ -69,19 +71,20 @@ def force_text(s, encoding='utf-8', strings_only=False, errors='strict'): def transform(value): from raven.utils.serializer import transform - warnings.warn('You should switch to raven.utils.serializer.transform', DeprecationWarning) + warnings.warn('You should switch to raven.utils.serializer.' + 'transform', DeprecationWarning) return transform(value) def to_unicode(value): try: - value = six.text_type(force_text(value)) + value = text_type(force_text(value)) except (UnicodeEncodeError, UnicodeDecodeError): value = '(Error decoding value)' except Exception: # in some cases we get a different exception try: - value = six.binary_type(repr(type(value))) + value = binary_type(repr(type(value))) except Exception: value = '(Error decoding value)' return value @@ -89,6 +92,6 @@ def to_unicode(value): def to_string(value): try: - return six.binary_type(value.decode('utf-8').encode('utf-8')) + return binary_type(value.decode('utf-8').encode('utf-8')) except: return to_unicode(value).encode('utf-8') diff --git a/raven/utils/imports.py b/raven/utils/imports.py index 56ef18a7..8086fc3d 100644 --- a/raven/utils/imports.py +++ b/raven/utils/imports.py @@ -1,11 +1,11 @@ from __future__ import absolute_import -from . import six +from raven._compat import PY2 def import_string(key): # HACK(dcramer): Ensure a unicode key is still importable - if not six.PY3: + if PY2: key = str(key) if '.' not in key: diff --git a/raven/utils/serializer/base.py b/raven/utils/serializer/base.py index ab569dce..1a5f32e8 100644 --- a/raven/utils/serializer/base.py +++ b/raven/utils/serializer/base.py @@ -11,7 +11,8 @@ from __future__ import absolute_import import itertools import types -from raven.utils import six +from raven._compat import text_type, binary_type, string_types, iteritems, \ + class_types, PY2 from raven.utils.encoding import to_unicode from .manager import manager as serialization_manager @@ -54,13 +55,14 @@ class Serializer(object): _depth += 1 if _depth >= max_depth: try: - value = six.text_type(repr(value))[:string_max_length] + value = text_type(repr(value))[:string_max_length] except Exception as e: import traceback traceback.print_exc() self.manager.logger.exception(e) - return six.text_type(type(value)) - return self.manager.transform(value, max_depth=max_depth, _depth=_depth, **kwargs) + return text_type(type(value)) + return self.manager.transform(value, max_depth=max_depth, + _depth=_depth, **kwargs) class IterableSerializer(Serializer): @@ -71,7 +73,8 @@ class IterableSerializer(Serializer): return tuple( self.recurse(o, **kwargs) for n, o - in itertools.takewhile(lambda x: x[0] < list_max_length, enumerate(value)) + in itertools.takewhile(lambda x: x[0] < list_max_length, + enumerate(value)) ) @@ -79,7 +82,7 @@ class DictSerializer(Serializer): types = (dict,) def make_key(self, key): - if not isinstance(key, six.string_types): + if not isinstance(key, string_types): return to_unicode(key) return key @@ -88,12 +91,13 @@ class DictSerializer(Serializer): return dict( (self.make_key(self.recurse(k, **kwargs)), self.recurse(v, **kwargs)) for n, (k, v) - in itertools.takewhile(lambda x: x[0] < list_max_length, enumerate(six.iteritems(value))) + in itertools.takewhile(lambda x: x[0] < list_max_length, enumerate( + iteritems(value))) ) class UnicodeSerializer(Serializer): - types = (six.text_type,) + types = (text_type,) def serialize(self, value, **kwargs): # try to return a reasonable string that can be decoded @@ -101,21 +105,22 @@ class UnicodeSerializer(Serializer): # unicode character # e.g. we want the output to be like: "u'רונית מגן'" string_max_length = kwargs.get('string_max_length', None) - return repr(six.text_type('%s')) % (value[:string_max_length],) + return repr(text_type('%s')) % (value[:string_max_length],) class StringSerializer(Serializer): - types = (six.binary_type,) + types = (binary_type,) def serialize(self, value, **kwargs): string_max_length = kwargs.get('string_max_length', None) - if six.PY3: + if not PY2: return repr(value[:string_max_length]) try: # Python2 madness: let's try to recover from developer's issues # Try to process the string as if it was a unicode. - return "'" + value.decode('utf8')[:string_max_length].encode('utf8') + "'" + return "'" + value.decode('utf8')[:string_max_length] \ + .encode('utf8') + "'" except UnicodeDecodeError: pass @@ -123,10 +128,11 @@ class StringSerializer(Serializer): class TypeSerializer(Serializer): - types = six.class_types + types = class_types def can(self, value): - return not super(TypeSerializer, self).can(value) and has_sentry_metadata(value) + return not super(TypeSerializer, self).can(value) \ + and has_sentry_metadata(value) def serialize(self, value, **kwargs): return self.recurse(value.__sentry__(), **kwargs) @@ -157,10 +163,11 @@ class FunctionSerializer(Serializer): types = (types.FunctionType,) def serialize(self, value, **kwargs): - return '' % (value.__name__, value.__module__, id(value)) + return '' % ( + value.__name__, value.__module__, id(value)) -if not six.PY3: +if PY2: class LongSerializer(Serializer): types = (long,) # noqa @@ -178,5 +185,5 @@ serialization_manager.register(BooleanSerializer) serialization_manager.register(FloatSerializer) serialization_manager.register(IntegerSerializer) serialization_manager.register(FunctionSerializer) -if not six.PY3: +if PY2: serialization_manager.register(LongSerializer) diff --git a/raven/utils/serializer/manager.py b/raven/utils/serializer/manager.py index 652508d3..7343111c 100644 --- a/raven/utils/serializer/manager.py +++ b/raven/utils/serializer/manager.py @@ -9,7 +9,7 @@ from __future__ import absolute_import import logging from contextlib import closing -from raven.utils import six +from raven._compat import text_type __all__ = ('register', 'transform') @@ -69,16 +69,18 @@ class Serializer(object): return serializer.serialize(value, **kwargs) except Exception as e: logger.exception(e) - return six.text_type(type(value)) + return text_type(type(value)) # if all else fails, lets use the repr of the object try: return repr(value) except Exception as e: logger.exception(e) - # It's common case that a model's __unicode__ definition may try to query the database - # which if it was not cleaned up correctly, would hit a transaction aborted exception - return six.text_type(type(value)) + # It's common case that a model's __unicode__ definition + # may try to query the database which if it was not + # cleaned up correctly, would hit a transaction aborted + # exception + return text_type(type(value)) finally: self.context.remove(objid) diff --git a/raven/utils/six.py b/raven/utils/six.py deleted file mode 100644 index 966d36fb..00000000 --- a/raven/utils/six.py +++ /dev/null @@ -1,406 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" -# flake8: noqa - -# Copyright (c) 2010-2013 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -# the Software, and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -from __future__ import absolute_import - -import operator -import sys -import types - -__author__ = "Benjamin Peterson " -__version__ = "1.3.0" - - -# True if we are running on Python 3. -PY3 = sys.version_info[0] == 3 - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) - # This is a bit ugly, but it avoids running this again. - delattr(tp, self.name) - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _MovedItems(types.ModuleType): - """Lazy loading of moved objects""" - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("reload_module", "__builtin__", "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("winreg", "_winreg"), -] -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) -del attr - -moves = sys.modules[__name__ + ".moves"] = _MovedItems("moves") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" - - _iterkeys = "keys" - _itervalues = "values" - _iteritems = "items" - _iterlists = "lists" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - _iterkeys = "iterkeys" - _itervalues = "itervalues" - _iteritems = "iteritems" - _iterlists = "iterlists" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - -if PY3: - def get_unbound_function(unbound): - return unbound - - Iterator = object -else: - def get_unbound_function(unbound): # NOQA - return unbound.im_func - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -def iterkeys(d, **kw): - """Return an iterator over the keys of a dictionary.""" - return iter(getattr(d, _iterkeys)(**kw)) - - -def itervalues(d, **kw): - """Return an iterator over the values of a dictionary.""" - return iter(getattr(d, _itervalues)(**kw)) - - -def iteritems(d, **kw): - """Return an iterator over the (key, value) pairs of a dictionary.""" - return iter(getattr(d, _iteritems)(**kw)) - - -def iterlists(d, **kw): - """Return an iterator over the (key, [values]) pairs of a dictionary.""" - return iter(getattr(d, _iterlists)(**kw)) - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - if sys.version_info[1] <= 1: - def int2byte(i): - return bytes((i,)) - else: - # This is about 2x faster than the implementation above on 3.2+ - int2byte = operator.methodcaller("to_bytes", 1, "big") - import io - StringIO = io.StringIO - BytesIO = io.BytesIO -else: - def b(s): # NOQA - return s - - def u(s): # NOQA - return unicode(s, "unicode_escape") - int2byte = chr - import StringIO - StringIO = BytesIO = StringIO.StringIO -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -if PY3: - import builtins - exec_ = getattr(builtins, "exec") - - def reraise(tp, value, tb=None): - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - - print_ = getattr(builtins, "print") - del builtins - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - def print_(*args, **kwargs): - """The new-style print function.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - -_add_doc(reraise, """Reraise an exception.""") - - -def with_metaclass(meta, base=object): - """Create a base class with a metaclass.""" - return meta("NewBase", (base,), {}) diff --git a/raven/utils/stacks.py b/raven/utils/stacks.py index 62791ff6..518af012 100644 --- a/raven/utils/stacks.py +++ b/raven/utils/stacks.py @@ -14,13 +14,14 @@ import sys import warnings from raven.utils.serializer import transform -from raven.utils import six +from raven._compat import iteritems _coding_re = re.compile(r'coding[:=]\s*([-\w.]+)') -def get_lines_from_file(filename, lineno, context_lines, loader=None, module_name=None): +def get_lines_from_file(filename, lineno, context_lines, + loader=None, module_name=None): """ Returns context_lines before and after lineno from file. Returns (pre_context_lineno, pre_context, context_line, post_context). @@ -63,7 +64,8 @@ def get_lines_from_file(filename, lineno, context_lines, loader=None, module_nam try: pre_context = [line.strip('\r\n') for line in source[lower_bound:lineno]] context_line = source[lineno].strip('\r\n') - post_context = [line.strip('\r\n') for line in source[(lineno + 1):upper_bound]] + post_context = [line.strip('\r\n') for line in + source[(lineno + 1):upper_bound]] except IndexError: # the file may have changed since it was loaded into memory return None, None, None @@ -178,7 +180,7 @@ def get_frame_locals(frame, transformer=transform, max_var_size=4096): f_vars = {} f_size = 0 - for k, v in six.iteritems(f_locals): + for k, v in iteritems(f_locals): v = transformer(v) v_size = len(repr(v)) if v_size + f_size < 4096: @@ -253,7 +255,8 @@ def get_stack_info(frames, transformer=transform, capture_locals=True, lineno -= 1 if lineno is not None and abs_path: - pre_context, context_line, post_context = get_lines_from_file(abs_path, lineno, 5, loader, module_name) + pre_context, context_line, post_context = \ + get_lines_from_file(abs_path, lineno, 5, loader, module_name) else: pre_context, context_line, post_context = None, None, None @@ -261,7 +264,8 @@ def get_stack_info(frames, transformer=transform, capture_locals=True, # This changes /foo/site-packages/baz/bar.py into baz/bar.py try: base_filename = sys.modules[module_name.split('.', 1)[0]].__file__ - filename = abs_path.split(base_filename.rsplit('/', 2)[0], 1)[-1].lstrip("/") + filename = abs_path.split( + base_filename.rsplit('/', 2)[0], 1)[-1].lstrip("/") except: filename = abs_path diff --git a/raven/utils/wsgi.py b/raven/utils/wsgi.py index ad83bde3..24a8e812 100644 --- a/raven/utils/wsgi.py +++ b/raven/utils/wsgi.py @@ -6,7 +6,7 @@ This module implements WSGI related helpers adapted from ``werkzeug.wsgi`` """ from __future__ import absolute_import -from raven.utils import six +from raven._compat import iteritems from raven.utils.compat import urllib_quote @@ -15,7 +15,7 @@ def get_headers(environ): """ Returns only proper HTTP headers. """ - for key, value in six.iteritems(environ): + for key, value in iteritems(environ): key = str(key) if key.startswith('HTTP_') and key not in \ ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'): diff --git a/raven/versioning.py b/raven/versioning.py index 5efa7e88..c36b7191 100644 --- a/raven/versioning.py +++ b/raven/versioning.py @@ -8,8 +8,7 @@ except ImportError: # pkg_resource is not available on Google App Engine pkg_resources = None -from raven.utils import six - +from raven._compat import text_type from .exceptions import InvalidGitRepository __all__ = ('fetch_git_sha', 'fetch_package_version') @@ -22,10 +21,11 @@ def fetch_git_sha(path, head=None): if not head: head_path = os.path.join(path, '.git', 'HEAD') if not os.path.exists(head_path): - raise InvalidGitRepository('Cannot identify HEAD for git repository at %s' % (path,)) + raise InvalidGitRepository( + 'Cannot identify HEAD for git repository at %s' % (path,)) with open(head_path, 'r') as fp: - head = six.text_type(fp.read()).strip() + head = text_type(fp.read()).strip() if head.startswith('ref: '): revision_file = os.path.join( @@ -38,12 +38,14 @@ def fetch_git_sha(path, head=None): if not os.path.exists(revision_file): if not os.path.exists(os.path.join(path, '.git')): - raise InvalidGitRepository('%s does not seem to be the root of a git repository' % (path,)) - raise InvalidGitRepository('Unable to find ref to head "%s" in repository' % (head,)) + raise InvalidGitRepository( + '%s does not seem to be the root of a git repository' % (path,)) + raise InvalidGitRepository( + 'Unable to find ref to head "%s" in repository' % (head,)) fh = open(revision_file, 'r') try: - return six.text_type(fh.read()).strip() + return text_type(fh.read()).strip() finally: fh.close() @@ -53,6 +55,7 @@ def fetch_package_version(dist_name): >>> fetch_package_version('sentry') """ if pkg_resources is None: - raise NotImplementedError('pkg_resources is not available on this Python install') + raise NotImplementedError('pkg_resources is not available ' + 'on this Python install') dist = pkg_resources.get_distribution(dist_name) return dist.version diff --git a/setup.py b/setup.py index 2c692c53..9c254bf4 100755 --- a/setup.py +++ b/setup.py @@ -53,6 +53,7 @@ if sys.version_info[0] == 3: install_requires.remove('contextlib2') tests_require = [ + 'six', 'bottle', 'celery>=2.5', 'Django>=1.4', diff --git a/tests/base/tests.py b/tests/base/tests.py index 3cf290b3..685e045d 100644 --- a/tests/base/tests.py +++ b/tests/base/tests.py @@ -5,13 +5,13 @@ import inspect import mock import raven import time +import six from raven.base import Client, ClientState from raven.exceptions import RateLimited from raven.transport import AsyncTransport from raven.transport.http import HTTPTransport from raven.utils.stacks import iter_stack_frames -from raven.utils import six from raven.utils.testutils import TestCase diff --git a/tests/contrib/django/tests.py b/tests/contrib/django/tests.py index de4b8669..8d96ec10 100644 --- a/tests/contrib/django/tests.py +++ b/tests/contrib/django/tests.py @@ -9,8 +9,10 @@ import logging import mock import pytest import re +import six import sys # NOQA from exam import fixture +from six import StringIO from django.conf import settings from django.contrib.auth.models import User @@ -33,8 +35,6 @@ from raven.contrib.django.templatetags.raven import sentry_public_dsn from raven.contrib.django.views import is_valid_origin from raven.transport import HTTPTransport from raven.utils.serializer import transform -from raven.utils import six -from raven.utils.six import StringIO from django.test.client import Client as TestClient, ClientHandler as TestClientHandler from .models import TestModel diff --git a/tests/contrib/tornado/tests.py b/tests/contrib/tornado/tests.py index a2bd1b71..d50253b1 100644 --- a/tests/contrib/tornado/tests.py +++ b/tests/contrib/tornado/tests.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import six from mock import patch from tornado import web, gen, testing from tornado.concurrent import Future from tornado.httpclient import HTTPError from raven.contrib.tornado import SentryMixin, AsyncSentryClient -from raven.utils import six class AnErrorProneHandler(SentryMixin, web.RequestHandler): diff --git a/tests/handlers/logbook/tests.py b/tests/handlers/logbook/tests.py index aad74f56..c3810176 100644 --- a/tests/handlers/logbook/tests.py +++ b/tests/handlers/logbook/tests.py @@ -1,9 +1,9 @@ from __future__ import with_statement from __future__ import unicode_literals +import six import logbook from raven.utils.testutils import TestCase -from raven.utils import six from raven.base import Client from raven.handlers.logbook import SentryHandler diff --git a/tests/handlers/logging/tests.py b/tests/handlers/logging/tests.py index 239224e3..76b24e2f 100644 --- a/tests/handlers/logging/tests.py +++ b/tests/handlers/logging/tests.py @@ -3,10 +3,10 @@ from __future__ import unicode_literals import logging import sys import mock +import six from raven.base import Client from raven.handlers.logging import SentryHandler -from raven.utils import six from raven.utils.stacks import iter_stack_frames from raven.utils.testutils import TestCase diff --git a/tests/utils/encoding/tests.py b/tests/utils/encoding/tests.py index 1cbf9912..2b063a76 100644 --- a/tests/utils/encoding/tests.py +++ b/tests/utils/encoding/tests.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- import pytest import uuid +import six -from raven.utils import six, json +from raven.utils import json from raven.utils.testutils import TestCase from raven.utils.serializer import transform diff --git a/tests/utils/stacks/tests.py b/tests/utils/stacks/tests.py index 8ae22c47..4d1bc364 100644 --- a/tests/utils/stacks/tests.py +++ b/tests/utils/stacks/tests.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import six + from mock import Mock from raven.utils.testutils import TestCase -from raven.utils import six from raven.utils.stacks import get_culprit, get_stack_info, get_lines_from_file diff --git a/tests/utils/test_imports.py b/tests/utils/test_imports.py index e131abc6..12d9dc9e 100644 --- a/tests/utils/test_imports.py +++ b/tests/utils/test_imports.py @@ -1,8 +1,9 @@ from __future__ import absolute_import +import six + import raven -from raven.utils import six from raven.utils.imports import import_string diff --git a/tests/versioning/tests.py b/tests/versioning/tests.py index a39173c4..b3b49cb3 100644 --- a/tests/versioning/tests.py +++ b/tests/versioning/tests.py @@ -3,11 +3,11 @@ from __future__ import absolute_import import os.path import pytest import subprocess +import six from django.conf import settings from raven.versioning import fetch_git_sha, fetch_package_version -from raven.utils import six def has_git_requirements():