diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5b046c4d..59a77d18 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,9 +12,8 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
- python-version: [3.5, 3.6, 3.7, 3.8, 3.9, '3.10', 3.11]
+ python-version: [3.6, 3.7, 3.8, 3.9, '3.10', 3.11]
framework:
- - FLASK_VERSION=0.12.5 Werkzeug\>=0.7,\<1.0
- FLASK_VERSION=1.1.4
- FLASK_VERSION=2.2.3
- DJANGO_VERSION=1.11.29
@@ -34,8 +33,6 @@ jobs:
exclude:
# Test frameworks on the python versions they support, according to pypi registry
# Flask
- - framework: FLASK_VERSION=2.2.3
- python-version: 3.5
- framework: FLASK_VERSION=2.2.3
python-version: 3.6
@@ -48,10 +45,6 @@ jobs:
python-version: '3.10'
- framework: DJANGO_VERSION=1.11.29
python-version: 3.11
- - framework: DJANGO_VERSION=3.2.18
- python-version: 3.5
- - framework: DJANGO_VERSION=4.0.10
- python-version: 3.5
- framework: DJANGO_VERSION=4.0.10
python-version: 3.6
- framework: DJANGO_VERSION=4.0.10
@@ -66,28 +59,9 @@ jobs:
# Twisted
- framework: TWISTED_VERSION=20.3.0
python-version: 3.11
- - framework: TWISTED_VERSION=21.7.0
- python-version: 3.5
- - framework: TWISTED_VERSION=22.10.0
- python-version: 3.5
- framework: TWISTED_VERSION=22.10.0
python-version: 3.6
-
- # Starlette
- - framework: STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5
- python-version: 3.5
- - framework: STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5
- python-version: 3.5
-
- # Fastapi
- - framework: FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5
- python-version: 3.5
- - framework: FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5
- python-version: 3.5
- - framework: FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5
- python-version: 3.5
-
steps:
- uses: actions/checkout@v2
with:
@@ -98,15 +72,15 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- - name: Install Python 3.5 dependencies
- if: ${{ contains(matrix.python-version, '3.5') }}
- # typing-extensions dropped support for Python 3.5 in version 4
- run: pip install six==1.16.0 "typing-extensions<4" requests==2.24.0 blinker==1.5 WebOb==1.8.7
-
- name: Install Python 3.6 dependencies
if: ${{ contains(matrix.python-version, '3.6') }}
# typing-extensions dropped support for Python 3.6 in version 4.2
- run: pip install six==1.16.0 "typing-extensions<4.2" requests==2.27.0 blinker==1.5
+ run: pip install "typing-extensions<4.2" requests==2.27.0 blinker==1.5 immutables==0.19
+
+ - name: Install Python 3.7 dependencies
+ if: ${{ contains(matrix.python-version, '3.7') }}
+ # immutables dropped support for Python<3.8 in version 0.20
+ run: pip install immutables==0.19
- name: Set the framework
run: echo ${{ matrix.framework }} >> $GITHUB_ENV
diff --git a/README.md b/README.md
index 4b833026..9757f315 100644
--- a/README.md
+++ b/README.md
@@ -20,17 +20,29 @@ Python notifier for reporting exceptions, errors, and log messages to [Rollbar](
- **Advanced search:** Filter items by many different properties. Learn more about search.
- **Customizable notifications:** Rollbar supports several messaging and incident management tools where your team can get notified about errors and important events by real-time alerts. Learn more about Rollbar notifications.
+## Versions Supported
-# Setup Instructions
+| PyRollbar Version | Python Version Compatibility | Support Level |
+|-------------------|-----------------------------------------------|---------------------|
+| 0.17.0 | 3.6, 3.7. 3.8, 3.9, 3.10, 3.11 | Full |
+| 0.16.3 | 2.7, 3.4, 3.5, 3.6, 3.7. 3.8, 3.9, 3.10, 3.11 | Security Fixes Only |
+
+#### Support Level Definitions
+
+**Full** - We will support new features of the library and test against all supported versions.
+
+**Security Fixes Only** - We will only provide critical security fixes for the library.
+
+## Setup Instructions
1. [Sign up for a Rollbar account](https://rollbar.com/signup)
2. Follow the [Quick Start](https://docs.rollbar.com/docs/python#section-quick-start) instructions in our [Python SDK docs](https://docs.rollbar.com/docs/python) to install pyrollbar and configure it for your platform.
-# Usage and Reference
+## Usage and Reference
For complete usage instructions and configuration reference, see our [Python SDK docs](https://docs.rollbar.com/docs/python).
-# Release History & Changelog
+## Release History & Changelog
See our [Releases](https://github.com/rollbar/pyrollbar/releases) page for a list of all releases, including changes.
diff --git a/rollbar/__init__.py b/rollbar/__init__.py
index 5cf1c967..4c150e37 100644
--- a/rollbar/__init__.py
+++ b/rollbar/__init__.py
@@ -16,23 +16,18 @@
import uuid
import wsgiref.util
import warnings
+import queue
+from urllib.parse import parse_qs, urljoin
import requests
-import six
-from rollbar.lib import events, filters, dict_merge, parse_qs, text, transport, urljoin, iteritems, defaultJSONEncode
+from rollbar.lib import events, filters, dict_merge, transport, defaultJSONEncode
-__version__ = '0.16.4beta2'
+__version__ = '1.0.0b0'
__log_name__ = 'rollbar'
log = logging.getLogger(__log_name__)
-try:
- # 2.x
- import Queue as queue
-except ImportError:
- # 3.x
- import queue
# import request objects from various frameworks, if available
try:
@@ -86,7 +81,7 @@
try:
from google.appengine.api.urlfetch import fetch as AppEngineFetch
-except ImportError:
+except (ImportError, KeyError):
AppEngineFetch = None
try:
@@ -691,7 +686,7 @@ def prev_page(self):
def _resolve_exception_class(idx, filter):
cls, level = filter
- if isinstance(cls, six.string_types):
+ if isinstance(cls, str):
# Lazily resolve class name
parts = cls.split('.')
module = '.'.join(parts[:-1])
@@ -830,7 +825,7 @@ def _trace_data(cls, exc, trace):
'frames': frames,
'exception': {
'class': getattr(cls, '__name__', cls.__class__.__name__),
- 'message': text(exc),
+ 'message': str(exc),
}
}
@@ -907,7 +902,7 @@ def _build_base_data(request, level='error'):
'level': level,
'language': 'python %s' % '.'.join(str(x) for x in sys.version_info[:3]),
'notifier': SETTINGS['notifier'],
- 'uuid': text(uuid.uuid4()),
+ 'uuid': str(uuid.uuid4()),
}
if SETTINGS.get('code_version'):
@@ -962,9 +957,9 @@ def hasuser(request): return True
else:
retval = {}
if getattr(user, 'id', None):
- retval['id'] = text(user.id)
+ retval['id'] = str(user.id)
elif getattr(user, 'user_id', None):
- retval['id'] = text(user.user_id)
+ retval['id'] = str(user.user_id)
# id is required, so only include username/email if we have an id
if retval.get('id'):
@@ -981,7 +976,7 @@ def hasuser(request): return True
user_id = user_id_prop() if callable(user_id_prop) else user_id_prop
if not user_id:
return None
- return {'id': text(user_id)}
+ return {'id': str(user_id)}
def _get_func_from_frame(frame):
@@ -996,16 +991,6 @@ def _get_func_from_frame(frame):
return func
-def _flatten_nested_lists(l):
- ret = []
- for x in l:
- if isinstance(x, list):
- ret.extend(_flatten_nested_lists(x))
- else:
- ret.append(x)
- return ret
-
-
def _add_locals_data(trace_data, exc_info):
if not SETTINGS['locals']['enabled']:
return
@@ -1040,15 +1025,7 @@ def _add_locals_data(trace_data, exc_info):
# Optionally fill in locals for this frame
if arginfo.locals and _check_add_locals(cur_frame, frame_num, num_frames):
# Get all of the named args
- #
- # args can be a nested list of args in the case where there
- # are anonymous tuple args provided.
- # e.g. in Python 2 you can:
- # def func((x, (a, b), z)):
- # return x + a + b + z
- #
- # func((1, (1, 2), 3))
- argspec = _flatten_nested_lists(arginfo.args)
+ argspec = arginfo.args
if arginfo.varargs is not None:
varargspec = arginfo.varargs
@@ -1078,7 +1055,7 @@ def _add_locals_data(trace_data, exc_info):
cur_frame['keywordspec'] = keywordspec
if _locals:
try:
- cur_frame['locals'] = dict((k, _serialize_frame_data(v)) for k, v in iteritems(_locals))
+ cur_frame['locals'] = {k: _serialize_frame_data(v) for k, v in _locals.items()}
except Exception:
log.exception('Error while serializing frame data.')
@@ -1366,7 +1343,7 @@ def _build_wsgi_request_data(request):
if 'QUERY_STRING' in request:
request_data['GET'] = parse_qs(request['QUERY_STRING'], keep_blank_values=True)
# Collapse single item arrays
- request_data['GET'] = dict((k, v[0] if len(v) == 1 else v) for k, v in request_data['GET'].items())
+ request_data['GET'] = {k: (v[0] if len(v) == 1 else v) for k, v in request_data['GET'].items()}
request_data['headers'] = _extract_wsgi_headers(request.items())
@@ -1495,7 +1472,7 @@ def _build_payload(data):
Returns the full payload as a string.
"""
- for k, v in iteritems(data):
+ for k, v in data.items():
data[k] = _transform(v, key=(k,))
payload = {
diff --git a/rollbar/contrib/django/middleware.py b/rollbar/contrib/django/middleware.py
index f68e5d8d..f5f98e5c 100644
--- a/rollbar/contrib/django/middleware.py
+++ b/rollbar/contrib/django/middleware.py
@@ -86,7 +86,6 @@ def get_payload_data(self, request, exc):
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
from django.http import Http404
-from six import reraise
try:
from django.urls import resolve
@@ -311,7 +310,9 @@ def process_response(self, request, response):
try:
if hasattr(request, '_rollbar_notifier_original_http404_exc_info'):
exc_type, exc_value, exc_traceback = request._rollbar_notifier_original_http404_exc_info
- reraise(exc_type, exc_value, exc_traceback)
+ if exc_value is None:
+ exc_value = Http404()
+ raise exc_value.with_traceback(exc_traceback)
else:
raise Http404()
except Exception as exc:
diff --git a/rollbar/contrib/pyramid/__init__.py b/rollbar/contrib/pyramid/__init__.py
index f02c7a79..e133e15b 100644
--- a/rollbar/contrib/pyramid/__init__.py
+++ b/rollbar/contrib/pyramid/__init__.py
@@ -138,7 +138,7 @@ def hook(request, data):
environment = kw.pop('environment', 'production')
if kw.get('scrub_fields'):
- kw['scrub_fields'] = set([str.strip(x) for x in kw.get('scrub_fields').split('\n') if x])
+ kw['scrub_fields'] = {str.strip(x) for x in kw.get('scrub_fields').split('\n') if x}
if kw.get('exception_level_filters'):
r = DottedNameResolver()
diff --git a/rollbar/lib/__init__.py b/rollbar/lib/__init__.py
index 78a32d87..8eb7be69 100644
--- a/rollbar/lib/__init__.py
+++ b/rollbar/lib/__init__.py
@@ -1,98 +1,33 @@
import base64
import collections
import copy
-import os
-import sys
from array import array
-import json
-try:
- # Python 3
- from collections.abc import Mapping
-except ImportError:
- # Python 2.7
- from collections import Mapping
-
-import six
-from six.moves import urllib
+from collections.abc import Mapping
-iteritems = six.iteritems
-reprlib = six.moves.reprlib
-
-binary_type = six.binary_type
-integer_types = six.integer_types
-number_types = integer_types + (float, )
-string_types = six.string_types
+binary_type = bytes
+integer_types = int
+number_types = (float, int)
+string_types = str
sequence_types = (Mapping, list, tuple, set, frozenset, array, collections.deque)
-urlparse = urllib.parse.urlparse
-urlsplit = urllib.parse.urlsplit
-urlunparse = urllib.parse.urlunparse
-urlunsplit = urllib.parse.urlunsplit
-parse_qs = urllib.parse.parse_qs
-urlencode = urllib.parse.urlencode
-urljoin = urllib.parse.urljoin
-quote = urllib.parse.quote
-
-
-_version = sys.version_info
-
-
-def python_major_version():
- return _version[0]
-
-
-if python_major_version() < 3:
- def text(val):
- if isinstance(val, (str, unicode)):
- return val
-
- conversion_options = [unicode, lambda x: unicode(x, encoding='utf8')]
- for option in conversion_options:
- try:
- return option(val)
- except UnicodeDecodeError:
- pass
- return repr(val)
-
- _map = map
-
- def map(*args):
- return _map(*args)
-
- def force_lower(val):
+def force_lower(val):
+ try:
+ return val.lower()
+ except:
return str(val).lower()
-else:
- def text(val):
- return str(val)
-
- _map = map
-
- def map(*args):
- return list(_map(*args))
-
- def force_lower(val):
- try:
- return val.lower()
- except:
- return str(val).lower()
-
-
-def do_for_python_version(two_fn, three_fn, *args, **kw):
- if python_major_version() < 3:
- return two_fn(*args, **kw)
- return three_fn(*args, **kw)
-
def prefix_match(key, prefixes):
if not key:
return False
for prefix in prefixes:
- common_prefix = os.path.commonprefix((prefix, key))
- if common_prefix == prefix:
+ if len(prefix) > len(key):
+ continue
+
+ if prefix == key[:len(prefix)]:
return True
return False
@@ -110,23 +45,22 @@ def key_in(key, keys):
def key_match(key1, key2):
- key1_len = len(key1)
- key2_len = len(key2)
- if key1_len != key2_len:
+ if len(key1) != len(key2):
return False
- z_key = zip(key1, key2)
- num_matches = 0
- for p1, p2 in z_key:
- if '*' in (p1, p2) or p1 == p2:
- num_matches += 1
+ for p1, p2 in zip(key1, key2):
+ if '*' == p1 or '*' == p2:
+ continue
+ if p1 == p2:
+ continue
+ return False
- return num_matches == key1_len
+ return True
def reverse_list_of_lists(l, apply_each_fn=None):
apply_each_fn = apply_each_fn or (lambda x: x)
- return map(lambda x: list(reversed(map(apply_each_fn, x))), l or [])
+ return [reversed([apply_each_fn(x) for x in inner]) for inner in l or []]
def build_key_matcher(prefixes_or_suffixes, type='prefix', case_sensitive=False):
@@ -183,9 +117,9 @@ def dict_merge(a, b, silence_errors=False):
else:
try:
result[k] = copy.deepcopy(v)
- except:
+ except Exception as e:
if not silence_errors:
- raise six.reraise(*sys.exc_info())
+ raise e
result[k] = '' % (v,)
@@ -193,7 +127,7 @@ def dict_merge(a, b, silence_errors=False):
def circular_reference_label(data, ref_key=None):
- ref = '.'.join(map(text, ref_key))
+ ref = '.'.join([str(x) for x in ref_key])
return '' % (type(data).__name__, ref)
diff --git a/rollbar/lib/_async.py b/rollbar/lib/_async.py
index b41dc2f7..1b025258 100644
--- a/rollbar/lib/_async.py
+++ b/rollbar/lib/_async.py
@@ -4,6 +4,7 @@
import logging
import sys
from unittest import mock
+from urllib.parse import urljoin
try:
import httpx
@@ -12,7 +13,7 @@
import rollbar
from rollbar import DEFAULT_TIMEOUT
-from rollbar.lib import transport, urljoin
+from rollbar.lib import transport
log = logging.getLogger(__name__)
diff --git a/rollbar/lib/transform.py b/rollbar/lib/transform.py
index fa08e5cd..2ba7a030 100644
--- a/rollbar/lib/transform.py
+++ b/rollbar/lib/transform.py
@@ -23,10 +23,7 @@ def transform_dict(self, o, key=None):
def transform_number(self, o, key=None):
return self.default(o, key=key)
- def transform_py2_str(self, o, key=None):
- return self.default(o, key=key)
-
- def transform_py3_bytes(self, o, key=None):
+ def transform_bytes(self, o, key=None):
return self.default(o, key=key)
def transform_unicode(self, o, key=None):
diff --git a/rollbar/lib/transforms/__init__.py b/rollbar/lib/transforms/__init__.py
index 2869f2d4..3f1b8802 100644
--- a/rollbar/lib/transforms/__init__.py
+++ b/rollbar/lib/transforms/__init__.py
@@ -1,18 +1,10 @@
-try:
- # Python 3
- from collections.abc import Iterable
-except ImportError:
- # Python 2.7
- from collections import Iterable
+from collections.abc import Iterable
from rollbar.lib import (
- python_major_version,
binary_type,
string_types,
- integer_types,
number_types,
traverse,
- type_info,
)
# NOTE: Don't remove this import, it would cause a breaking change to the library's API.
# The `Transform` class was moved out of this file to prevent a cyclical dependency issue.
@@ -56,21 +48,11 @@ def do_transform(type_name, val, key=None, **kw):
return val
- if python_major_version() < 3:
-
- def string_handler(s, key=None):
- if isinstance(s, str):
- return do_transform("py2_str", s, key=key)
- elif isinstance(s, unicode):
- return do_transform("unicode", s, key=key)
-
- else:
-
- def string_handler(s, key=None):
- if isinstance(s, bytes):
- return do_transform("py3_bytes", s, key=key)
- elif isinstance(s, str):
- return do_transform("unicode", s, key=key)
+ def string_handler(s, key=None):
+ if isinstance(s, bytes):
+ return do_transform("bytes", s, key=key)
+ elif isinstance(s, str):
+ return do_transform("unicode", s, key=key)
def default_handler(o, key=None):
if isinstance(o, bool):
diff --git a/rollbar/lib/transforms/batched.py b/rollbar/lib/transforms/batched.py
index 5ba9eadd..b0d5d04d 100644
--- a/rollbar/lib/transforms/batched.py
+++ b/rollbar/lib/transforms/batched.py
@@ -1,6 +1,5 @@
from rollbar.lib.transform import Transform
from rollbar.lib import (
- python_major_version,
number_types,
type_info,
)
@@ -13,21 +12,11 @@ def do_transform(transform, type_name, val, key=None, **kw):
return val
-if python_major_version() < 3:
-
- def string_handler(transform, s, key=None):
- if isinstance(s, str):
- return do_transform(transform, "py2_str", s, key=key)
- elif isinstance(s, unicode):
- return do_transform(transform, "unicode", s, key=key)
-
-else:
-
- def string_handler(transform, s, key=None):
- if isinstance(s, bytes):
- return do_transform(transform, "py3_bytes", s, key=key)
- elif isinstance(s, str):
- return do_transform(transform, "unicode", s, key=key)
+def string_handler(transform, s, key=None):
+ if isinstance(s, bytes):
+ return do_transform(transform, "bytes", s, key=key)
+ elif isinstance(s, str):
+ return do_transform(transform, "unicode", s, key=key)
def default_handler(transform, o, key=None):
diff --git a/rollbar/lib/transforms/scrub.py b/rollbar/lib/transforms/scrub.py
index 96158d85..ff0af810 100644
--- a/rollbar/lib/transforms/scrub.py
+++ b/rollbar/lib/transforms/scrub.py
@@ -1,17 +1,21 @@
import random
-from rollbar.lib import build_key_matcher, text
+from rollbar.lib import build_key_matcher
from rollbar.lib.transform import Transform
class ScrubTransform(Transform):
+ suffix_matcher = None
def __init__(self, suffixes=None, redact_char='*', randomize_len=True):
super(ScrubTransform, self).__init__()
- self.suffix_matcher = build_key_matcher(suffixes, type='suffix')
+ if suffixes is not None and len(suffixes) > 0:
+ self.suffix_matcher = build_key_matcher(suffixes, type='suffix')
self.redact_char = redact_char
self.randomize_len = randomize_len
def in_scrub_fields(self, key):
+ if self.suffix_matcher is None:
+ return False
return self.suffix_matcher(key)
def redact(self, val):
@@ -21,7 +25,7 @@ def redact(self, val):
try:
_len = len(val)
except:
- _len = len(text(val))
+ _len = len(str(val))
return self.redact_char * _len
diff --git a/rollbar/lib/transforms/scruburl.py b/rollbar/lib/transforms/scruburl.py
index 7b570462..0ab922cc 100644
--- a/rollbar/lib/transforms/scruburl.py
+++ b/rollbar/lib/transforms/scruburl.py
@@ -1,6 +1,7 @@
import re
+from urllib.parse import urlsplit, urlencode, urlunsplit, parse_qs
-from rollbar.lib import iteritems, map, urlsplit, urlencode, urlunsplit, parse_qs, string_types, binary_type
+from rollbar.lib import string_types, binary_type
from rollbar.lib.transforms.scrub import ScrubTransform
@@ -21,7 +22,7 @@ def __init__(self,
randomize_len=randomize_len)
self.scrub_username = scrub_username
self.scrub_password = scrub_password
- self.params_to_scrub = set(map(lambda x: x.lower(), params_to_scrub))
+ self.params_to_scrub = {x.lower() for x in params_to_scrub or []}
def in_scrub_fields(self, key):
# Returning True here because we want to scrub URLs out of
@@ -51,9 +52,9 @@ def redact(self, url_string):
if not netloc:
return url_string
- for qs_param, vals in iteritems(qs_params):
+ for qs_param, vals in qs_params.items():
if qs_param.lower() in self.params_to_scrub:
- vals2 = map(_redact, vals)
+ vals2 = [_redact(x) for x in vals]
qs_params[qs_param] = vals2
scrubbed_qs = urlencode(qs_params, doseq=True)
diff --git a/rollbar/lib/transforms/serializable.py b/rollbar/lib/transforms/serializable.py
index 756b9a58..49f95d29 100644
--- a/rollbar/lib/transforms/serializable.py
+++ b/rollbar/lib/transforms/serializable.py
@@ -4,7 +4,6 @@
from rollbar.lib import (
circular_reference_label, float_infinity_label, float_nan_label,
undecodable_object_label, unencodable_object_label)
-from rollbar.lib import iteritems, python_major_version, text
from rollbar.lib.transform import Transform
@@ -25,7 +24,7 @@ def transform_namedtuple(self, o, key=None):
for field in tuple_dict:
new_vals.append(transformed_dict[field])
- return '<%s>' % text(o._make(new_vals))
+ return '<%s>' % str(o._make(new_vals))
def transform_number(self, o, key=None):
if math.isnan(o):
@@ -35,15 +34,7 @@ def transform_number(self, o, key=None):
else:
return o
- def transform_py2_str(self, o, key=None):
- try:
- o.decode('utf8')
- except UnicodeDecodeError:
- return undecodable_object_label(o)
- else:
- return o
-
- def transform_py3_bytes(self, o, key=None):
+ def transform_bytes(self, o, key=None):
try:
o.decode('utf8')
except UnicodeDecodeError:
@@ -61,20 +52,14 @@ def transform_unicode(self, o, key=None):
def transform_dict(self, o, key=None):
ret = {}
- for k, v in iteritems(o):
+ for k, v in o.items():
if isinstance(k, string_types) or isinstance(k, binary_type):
- if python_major_version() < 3:
- if isinstance(k, unicode):
- new_k = self.transform_unicode(k)
- else:
- new_k = self.transform_py2_str(k)
+ if isinstance(k, bytes):
+ new_k = self.transform_bytes(k)
else:
- if isinstance(k, bytes):
- new_k = self.transform_py3_bytes(k)
- else:
- new_k = self.transform_unicode(k)
+ new_k = self.transform_unicode(k)
else:
- new_k = text(k)
+ new_k = str(k)
ret[new_k] = v
diff --git a/rollbar/lib/transforms/shortener.py b/rollbar/lib/transforms/shortener.py
index 44508e0b..f0392912 100644
--- a/rollbar/lib/transforms/shortener.py
+++ b/rollbar/lib/transforms/shortener.py
@@ -1,17 +1,13 @@
from array import array
import collections
import itertools
+import reprlib
-try:
- # Python 3
- from collections.abc import Mapping
-except ImportError:
- # Python 2.7
- from collections import Mapping
+from collections.abc import Mapping
from rollbar.lib import (
- integer_types, iteritems, key_in, number_types, reprlib, sequence_types,
- string_types, text)
+ integer_types, key_in, number_types, sequence_types,
+ string_types)
from rollbar.lib.transform import Transform
@@ -36,11 +32,11 @@ def __init__(self, safe_repr=True, keys=None, **sizes):
self.keys = keys
self._repr = reprlib.Repr()
- for name, size in iteritems(sizes):
+ for name, size in sizes.items():
setattr(self._repr, name, size)
def _get_max_size(self, obj):
- for name, _type in iteritems(_type_name_mapping):
+ for name, _type in _type_name_mapping.items():
# Special case for dicts since we are using collections.abc.Mapping
# to provide better type checking for dict-like objects
if name == 'mapping':
@@ -66,7 +62,7 @@ def _shorten_mapping(self, obj, max_keys):
return {k: obj[k] for k in itertools.islice(obj.keys(), max_keys)}
def _shorten_basic(self, obj, max_len):
- val = text(obj)
+ val = str(obj)
if len(val) <= max_len:
return obj
@@ -77,7 +73,7 @@ def _shorten_other(self, obj):
return None
if self.safe_repr:
- obj = text(obj)
+ obj = str(obj)
return self._repr.repr(obj)
diff --git a/rollbar/lib/traverse.py b/rollbar/lib/traverse.py
index f732771f..6a613dad 100644
--- a/rollbar/lib/traverse.py
+++ b/rollbar/lib/traverse.py
@@ -1,7 +1,7 @@
import logging
-from rollbar.lib import binary_type, iteritems, string_types, circular_reference_label
+from rollbar.lib import binary_type, string_types, circular_reference_label
# NOTE: Don't remove this line of code as it would cause a breaking change
# to the library's API. The items imported here were originally in this file
@@ -118,29 +118,27 @@ def traverse(
return namedtuple_handler(
obj._make(
traverse(v, key=key + (k,), **kw)
- for k, v in iteritems(obj._asdict())
+ for k, v in obj._asdict().items()
),
key=key,
)
elif obj_type is LIST:
return list_handler(
- list(
- traverse(elem, key=key + (i,), **kw) for i, elem in enumerate(obj)
- ),
+ [traverse(elem, key=key + (i,), **kw) for i, elem in enumerate(obj)],
key=key,
)
elif obj_type is SET:
return set_handler(
- set(traverse(elem, key=key + (i,), **kw) for i, elem in enumerate(obj)),
+ {traverse(elem, key=key + (i,), **kw) for i, elem in enumerate(obj)},
key=key,
)
elif obj_type is MAPPING:
return mapping_handler(
- dict((k, traverse(v, key=key + (k,), **kw)) for k, v in iteritems(obj)),
+ {k: traverse(v, key=key + (k,), **kw) for k, v in obj.items()},
key=key,
)
elif obj_type is DEFAULT:
- for handler_type, handler in iteritems(custom_handlers):
+ for handler_type, handler in custom_handlers.items():
if isinstance(obj, handler_type):
return handler(obj, key=key)
except:
diff --git a/rollbar/lib/type_info.py b/rollbar/lib/type_info.py
index a15b44bf..7cf0af54 100644
--- a/rollbar/lib/type_info.py
+++ b/rollbar/lib/type_info.py
@@ -1,16 +1,7 @@
from rollbar.lib import binary_type, string_types
-try:
- # Python 3
- from collections.abc import Mapping
- from collections.abc import Sequence
- from collections.abc import Set
-except ImportError:
- # Python 2.7
- from collections import Mapping
- from collections import Sequence
- from collections import Set
+from collections.abc import Mapping, Sequence, Set
CIRCULAR = -1
diff --git a/rollbar/test/__init__.py b/rollbar/test/__init__.py
index 9a6903ad..5f52f1bf 100644
--- a/rollbar/test/__init__.py
+++ b/rollbar/test/__init__.py
@@ -1,5 +1,4 @@
import unittest
-import sys
SNOWMAN = b'\xe2\x98\x83'
@@ -10,24 +9,7 @@ class BaseTest(unittest.TestCase):
pass
-class SkipAsyncTestLoader(unittest.TestLoader):
- """
- Python 2 does not have the async keyword, so when tests are run under python 2.7 the loader
- will fail with a syntaxerror. This loader class does the following:
- - try to load as normal
- - if loading fails because of a syntax error in python < 3.4, skip the file.
- """
- def _get_module_from_name(self, name):
- try:
- return super(SkipAsyncTestLoader, self)._get_module_from_name(name)
- except SyntaxError as e:
- if sys.version_info < (3, 5):
- return None
- else:
- raise
-
-
def discover():
- loader = SkipAsyncTestLoader()
+ loader = unittest.TestLoader()
suite = loader.discover(__name__)
return suite
diff --git a/rollbar/test/asgi_tests/test_middleware.py b/rollbar/test/asgi_tests/test_middleware.py
index 28ac42a0..d949d596 100644
--- a/rollbar/test/asgi_tests/test_middleware.py
+++ b/rollbar/test/asgi_tests/test_middleware.py
@@ -2,10 +2,7 @@
import importlib
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
import unittest
diff --git a/rollbar/test/async_tests/test_async.py b/rollbar/test/async_tests/test_async.py
index 9779f587..6843c8ec 100644
--- a/rollbar/test/async_tests/test_async.py
+++ b/rollbar/test/async_tests/test_async.py
@@ -1,10 +1,7 @@
import copy
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
import unittest
diff --git a/rollbar/test/fastapi_tests/test_logger.py b/rollbar/test/fastapi_tests/test_logger.py
index 4ef2cdb0..49a4a8a6 100644
--- a/rollbar/test/fastapi_tests/test_logger.py
+++ b/rollbar/test/fastapi_tests/test_logger.py
@@ -1,10 +1,7 @@
import importlib
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
try:
import fastapi
diff --git a/rollbar/test/fastapi_tests/test_middleware.py b/rollbar/test/fastapi_tests/test_middleware.py
index 6cecf48b..c49336e4 100644
--- a/rollbar/test/fastapi_tests/test_middleware.py
+++ b/rollbar/test/fastapi_tests/test_middleware.py
@@ -2,10 +2,7 @@
import importlib
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
try:
import fastapi
diff --git a/rollbar/test/fastapi_tests/test_routing.py b/rollbar/test/fastapi_tests/test_routing.py
index bd7f6e71..c26ca159 100644
--- a/rollbar/test/fastapi_tests/test_routing.py
+++ b/rollbar/test/fastapi_tests/test_routing.py
@@ -3,10 +3,7 @@
import json
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
try:
import fastapi
diff --git a/rollbar/test/flask_tests/test_flask.py b/rollbar/test/flask_tests/test_flask.py
index f8b020e3..b97227bb 100644
--- a/rollbar/test/flask_tests/test_flask.py
+++ b/rollbar/test/flask_tests/test_flask.py
@@ -6,10 +6,7 @@
import sys
import os
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
import rollbar
diff --git a/rollbar/test/starlette_tests/test_logger.py b/rollbar/test/starlette_tests/test_logger.py
index 6c7b61d7..3ed51e68 100644
--- a/rollbar/test/starlette_tests/test_logger.py
+++ b/rollbar/test/starlette_tests/test_logger.py
@@ -1,10 +1,7 @@
import importlib
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
try:
import starlette
diff --git a/rollbar/test/starlette_tests/test_middleware.py b/rollbar/test/starlette_tests/test_middleware.py
index fcc26136..7c9f6554 100644
--- a/rollbar/test/starlette_tests/test_middleware.py
+++ b/rollbar/test/starlette_tests/test_middleware.py
@@ -2,10 +2,7 @@
import importlib
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
try:
import starlette
diff --git a/rollbar/test/test_lib.py b/rollbar/test/test_lib.py
index 1facb933..7d792638 100644
--- a/rollbar/test/test_lib.py
+++ b/rollbar/test/test_lib.py
@@ -1,8 +1,7 @@
-from rollbar.lib import dict_merge
+from rollbar.lib import dict_merge, prefix_match
from rollbar.test import BaseTest
-import six
class RollbarLibTest(BaseTest):
def test_dict_merge_not_dict(self):
@@ -12,6 +11,14 @@ def test_dict_merge_not_dict(self):
self.assertEqual(99, result)
+ def test_prefix_match(self):
+ key = ['password', 'argspec', '0']
+ self.assertTrue(prefix_match(key, [['password']]))
+
+ def test_prefix_match(self):
+ key = ['environ', 'argspec', '0']
+ self.assertFalse(prefix_match(key, [['password']]))
+
def test_dict_merge_dicts_independent(self):
a = {'a': {'b': 42}}
b = {'x': {'y': 99}}
@@ -58,4 +65,4 @@ def test_dict_merge_dicts_select_poll(self):
self.assertIn('b', result['a'])
self.assertEqual(42, result['a']['b'])
self.assertIn('y', result['a'])
- six.assertRegex(self, result['a']['y'], r'Uncopyable obj')
+ self.assertRegex(result['a']['y'], r'Uncopyable obj')
diff --git a/rollbar/test/test_loghandler.py b/rollbar/test/test_loghandler.py
index 5c3cf1c2..c4c80d32 100644
--- a/rollbar/test/test_loghandler.py
+++ b/rollbar/test/test_loghandler.py
@@ -6,10 +6,7 @@
import logging
import sys
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
import rollbar
from rollbar.logger import RollbarHandler
@@ -81,25 +78,23 @@ def test_request_is_get_from_log_record_if_present(self):
logger.warning("Warning message", extra={"request": request})
self.assertEqual(report_message_mock.call_args[1]["request"], request)
- # Python 2.6 doesnt support extra param in logger.exception.
- if not sys.version_info[:2] == (2, 6):
- # if you call logger.exception outside of an exception
- # handler, it shouldn't try to report exc_info, since it
- # won't have any
- with mock.patch("rollbar.report_exc_info") as report_exc_info:
- with mock.patch("rollbar.report_message") as report_message_mock:
+ # if you call logger.exception outside of an exception
+ # handler, it shouldn't try to report exc_info, since it
+ # won't have any
+ with mock.patch("rollbar.report_exc_info") as report_exc_info:
+ with mock.patch("rollbar.report_message") as report_message_mock:
+ logger.exception("Exception message", extra={"request": request})
+ report_exc_info.assert_not_called()
+ self.assertEqual(report_message_mock.call_args[1]["request"], request)
+
+ with mock.patch("rollbar.report_exc_info") as report_exc_info:
+ with mock.patch("rollbar.report_message") as report_message_mock:
+ try:
+ raise Exception()
+ except:
logger.exception("Exception message", extra={"request": request})
- report_exc_info.assert_not_called()
- self.assertEqual(report_message_mock.call_args[1]["request"], request)
-
- with mock.patch("rollbar.report_exc_info") as report_exc_info:
- with mock.patch("rollbar.report_message") as report_message_mock:
- try:
- raise Exception()
- except:
- logger.exception("Exception message", extra={"request": request})
- self.assertEqual(report_exc_info.call_args[1]["request"], request)
- report_message_mock.assert_not_called()
+ self.assertEqual(report_exc_info.call_args[1]["request"], request)
+ report_message_mock.assert_not_called()
@mock.patch('rollbar.send_payload')
def test_nested_exception_trace_chain(self, send_payload):
diff --git a/rollbar/test/test_pyramid.py b/rollbar/test/test_pyramid.py
index 4f643bbd..63c4a3ca 100644
--- a/rollbar/test/test_pyramid.py
+++ b/rollbar/test/test_pyramid.py
@@ -1,7 +1,4 @@
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
from rollbar.test import BaseTest
diff --git a/rollbar/test/test_rollbar.py b/rollbar/test/test_rollbar.py
index 26d9ab6f..3107e9e4 100644
--- a/rollbar/test/test_rollbar.py
+++ b/rollbar/test/test_rollbar.py
@@ -11,16 +11,13 @@
from StringIO import StringIO
except ImportError:
from io import StringIO
-try:
- from unittest import mock
-except ImportError:
- import mock
+
+from unittest import mock
import unittest
-import six
import rollbar
-from rollbar.lib import python_major_version, string_types
+from rollbar.lib import string_types
from rollbar.test import BaseTest
@@ -464,18 +461,8 @@ def test_get_request_fastapi_middleware(self):
app = FastAPI()
app.add_middleware(ReporterMiddleware)
- # Inject annotations and decorate endpoint dynamically
- # to avoid SyntaxError for older Python
- #
- # This is the code we'd use if we had not loaded the test file on Python 2.
- #
- # @app.get('/{param}')
- # def root(param, fastapi_request: Request):
- # current_request = rollbar.get_request()
- #
- # self.assertEqual(current_request, fastapi_request)
-
- def root(param, fastapi_request):
+ @app.get('/{param}')
+ def root(param, fastapi_request: Request):
current_request = rollbar.get_request()
self.assertEqual(current_request, fastapi_request)
@@ -501,18 +488,8 @@ def test_get_request_fastapi_logger(self):
app = FastAPI()
app.add_middleware(ReporterMiddleware)
- # Inject annotations and decorate endpoint dynamically
- # to avoid SyntaxError for older Python
- #
- # This is the code we'd use if we had not loaded the test file on Python 2.
- #
- # @app.get('/{param}')
- # def root(fastapi_request: Request):
- # current_request = rollbar.get_request()
- #
- # self.assertEqual(current_request, fastapi_request)
-
- def root(param, fastapi_request):
+ @app.get('/{param}')
+ def root(fastapi_request: Request):
current_request = rollbar.get_request()
self.assertEqual(current_request, fastapi_request)
@@ -542,18 +519,8 @@ def test_get_request_fastapi_router(self):
app = FastAPI()
rollbar_add_to(app)
- # Inject annotations and decorate endpoint dynamically
- # to avoid SyntaxError for older Python
- #
- # This is the code we'd use if we had not loaded the test file on Python 2.
- #
- # @app.get('/{param}')
- # def root(fastapi_request: Request):
- # current_request = rollbar.get_request()
- #
- # self.assertEqual(current_request, fastapi_request)
-
- def root(param, fastapi_request):
+ @app.get('/{param}')
+ def root(fastapi_request: Request):
current_request = rollbar.get_request()
self.assertEqual(current_request, fastapi_request)
@@ -1190,7 +1157,7 @@ def test_args_lambda_with_star_args(self, send_payload):
varargs = payload['data']['body']['trace']['frames'][-1]['varargspec']
self.assertEqual(1, len(payload['data']['body']['trace']['frames'][-1]['locals'][varargs]))
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals'][varargs][0], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][varargs][0], r'\*+')
@mock.patch('rollbar.send_payload')
def test_args_lambda_with_star_args_and_args(self, send_payload):
@@ -1217,8 +1184,8 @@ def test_args_lambda_with_star_args_and_args(self, send_payload):
self.assertEqual('arg1-value', payload['data']['body']['trace']['frames'][-1]['locals']['arg1'])
self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['locals'][varargs]))
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals'][varargs][0], r'\*+')
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals'][varargs][1], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][varargs][0], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][varargs][1], r'\*+')
@mock.patch('rollbar.send_payload')
def test_args_lambda_with_kwargs(self, send_payload):
@@ -1383,8 +1350,8 @@ def _raise(password='sensitive', clear='text'):
self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['argspec']))
self.assertEqual('password', payload['data']['body']['trace']['frames'][-1]['argspec'][0])
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals']['password'], r'\*+')
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals']['headers']['Authorization'], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals']['password'], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals']['headers']['Authorization'], r'\*+')
self.assertEqual('clear', payload['data']['body']['trace']['frames'][-1]['argspec'][1])
self.assertEqual('text', payload['data']['body']['trace']['frames'][-1]['locals']['clear'])
@@ -1438,7 +1405,7 @@ def _raise(**kwargs):
self.assertEqual(2, len(payload['data']['body']['trace']['frames'][-1]['locals'][keywords]))
self.assertIn('password', payload['data']['body']['trace']['frames'][-1]['locals'][keywords])
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['password'], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['password'], r'\*+')
self.assertIn('clear', payload['data']['body']['trace']['frames'][-1]['locals'][keywords])
self.assertEqual('text', payload['data']['body']['trace']['frames'][-1]['locals'][keywords]['clear'])
@@ -1469,12 +1436,11 @@ def _raise():
payload = send_payload.call_args[0][0]
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals']['password'], r'\*+')
- six.assertRegex(self, payload['data']['body']['trace']['frames'][-1]['locals']['Password'], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals']['password'], r'\*+')
+ self.assertRegex(payload['data']['body']['trace']['frames'][-1]['locals']['Password'], r'\*+')
self.assertIn('_invalid', payload['data']['body']['trace']['frames'][-1]['locals'])
- binary_type_name = 'str' if python_major_version() < 3 else 'bytes'
- undecodable_message = '' % (binary_type_name, base64.b64encode(invalid).decode('ascii'))
+ undecodable_message = '' % ('bytes', base64.b64encode(invalid).decode('ascii'))
self.assertEqual(undecodable_message, payload['data']['body']['trace']['frames'][-1]['locals']['_invalid'])
@mock.patch('rollbar.send_payload')
@@ -1787,19 +1753,19 @@ def test_scrub_webob_request_data(self):
self.assertEqual('I am from NSA', unscrubbed['headers']['Authorization'])
scrubbed = rollbar._transform(unscrubbed)
- six.assertRegex(self, scrubbed['url'], r'http://example.com/the/path\?(q=hello&password=-+)|(password=-+&q=hello)')
+ self.assertRegex(scrubbed['url'], r'http://example.com/the/path\?(q=hello&password=-+)|(password=-+&q=hello)')
self.assertEqual(scrubbed['GET']['q'], 'hello')
- six.assertRegex(self, scrubbed['GET']['password'], r'\*+')
+ self.assertRegex(scrubbed['GET']['password'], r'\*+')
self.assertEqual(scrubbed['POST']['foo'], 'bar')
- six.assertRegex(self, scrubbed['POST']['confirm_password'], r'\*+')
- six.assertRegex(self, scrubbed['POST']['token'], r'\*+')
+ self.assertRegex(scrubbed['POST']['confirm_password'], r'\*+')
+ self.assertRegex(scrubbed['POST']['token'], r'\*+')
self.assertEqual('5.6.7.8', scrubbed['headers']['X-Real-Ip'])
- six.assertRegex(self, scrubbed['headers']['Cookies'], r'\*+')
- six.assertRegex(self, scrubbed['headers']['Authorization'], r'\*+')
+ self.assertRegex(scrubbed['headers']['Cookies'], r'\*+')
+ self.assertRegex(scrubbed['headers']['Authorization'], r'\*+')
def test_filter_ip_no_user_ip(self):
request_data = {'something': 'but no ip'}
diff --git a/rollbar/test/test_scrub_redact_transform.py b/rollbar/test/test_scrub_redact_transform.py
index 34e3356d..da6abe4b 100644
--- a/rollbar/test/test_scrub_redact_transform.py
+++ b/rollbar/test/test_scrub_redact_transform.py
@@ -1,11 +1,6 @@
-try:
- # Python 3
- from collections.abc import Mapping
-except ImportError:
- # Python 2.7
- from collections import Mapping
+from collections.abc import Mapping
-from rollbar.lib import text, transforms
+from rollbar.lib import transforms
from rollbar.lib.transforms.scrub_redact import ScrubRedactTransform, REDACT_REF
from rollbar.test import BaseTest
@@ -19,7 +14,7 @@ class NotRedactRef():
try:
SCRUBBED = '*' * len(REDACT_REF)
except:
- SCRUBBED = '*' * len(text(REDACT_REF))
+ SCRUBBED = '*' * len(str(REDACT_REF))
class ScrubRedactTransformTest(BaseTest):
diff --git a/rollbar/test/test_scrub_transform.py b/rollbar/test/test_scrub_transform.py
index 7cc50eb1..be74b61b 100644
--- a/rollbar/test/test_scrub_transform.py
+++ b/rollbar/test/test_scrub_transform.py
@@ -1,11 +1,6 @@
import copy
-try:
- # Python 3
- from collections.abc import Mapping
-except ImportError:
- # Python 2.7
- from collections import Mapping
+from collections.abc import Mapping
from rollbar.lib import transforms
from rollbar.lib.transforms.scrub import ScrubTransform
diff --git a/rollbar/test/test_scruburl_transform.py b/rollbar/test/test_scruburl_transform.py
index b0a63e08..03a0013c 100644
--- a/rollbar/test/test_scruburl_transform.py
+++ b/rollbar/test/test_scruburl_transform.py
@@ -1,15 +1,12 @@
-import copy
-import six
+from urllib.parse import urlparse, parse_qs
-from rollbar.lib import map, transforms, string_types, urlparse, parse_qs, python_major_version
+from rollbar.lib import transforms, string_types
from rollbar.lib.transforms.scruburl import ScrubUrlTransform, _starts_with_auth_re
-from rollbar.test import BaseTest, SNOWMAN, SNOWMAN_UNICODE
+from rollbar.test import BaseTest, SNOWMAN_UNICODE
-if python_major_version() >= 3:
- SNOWMAN = SNOWMAN_UNICODE
-SNOWMAN_LEN = len(SNOWMAN)
+SNOWMAN_LEN = len(SNOWMAN_UNICODE)
class ScrubUrlTransformTest(BaseTest):
@@ -43,17 +40,17 @@ def _compare_urls(self, url1, url2):
if _starts_with_auth_re.match(url2):
url2 = '//%s' % url2
- parsed_urls = map(urlparse, (url1, url2))
- qs_params = map(lambda x: parse_qs(x.query, keep_blank_values=True), parsed_urls)
- num_params = map(len, qs_params)
- param_names = map(lambda x: set(x.keys()), qs_params)
+ parsed_urls = [urlparse(url) for url in (url1, url2)]
+ qs_params = [parse_qs(x.query, keep_blank_values=True) for x in parsed_urls]
+ num_params = [len(x) for x in qs_params]
+ param_names = [set(x.keys()) for x in qs_params]
self.assertEqual(*num_params)
self.assertDictEqual(*qs_params)
self.assertSetEqual(*param_names)
for facet in ('scheme', 'netloc', 'path', 'params', 'username', 'password', 'hostname', 'port'):
- comp = map(lambda x: getattr(x, facet), parsed_urls)
+ comp = [getattr(x, facet) for x in parsed_urls]
self.assertEqual(*comp)
def test_no_scrub(self):
@@ -72,14 +69,14 @@ def test_scrub_simple_url_params(self):
self._assertScrubbed(['password'], obj, expected)
def test_scrub_utf8_url_params(self):
- obj = 'http://foo.com/asdf?password=%s' % SNOWMAN
- expected = obj.replace(SNOWMAN, '-' * SNOWMAN_LEN)
+ obj = 'http://foo.com/asdf?password=%s' % SNOWMAN_UNICODE
+ expected = obj.replace(SNOWMAN_UNICODE, '-' * SNOWMAN_LEN)
self._assertScrubbed(['password'], obj, expected)
def test_scrub_utf8_url_keys(self):
- obj = 'http://foo.com/asdf?%s=secret' % SNOWMAN
+ obj = 'http://foo.com/asdf?%s=secret' % SNOWMAN_UNICODE
expected = obj.replace('secret', '------')
- self._assertScrubbed([str(SNOWMAN)], obj, expected)
+ self._assertScrubbed([str(SNOWMAN_UNICODE)], obj, expected)
def test_scrub_multi_url_params(self):
obj = 'http://foo.com/asdf?password=secret&password=secret2&token=TOK&clear=text'
@@ -147,5 +144,5 @@ def test_scrub_dict_nested_key_match_with_circular_ref(self):
self.assertNotIn('secret', result['url'][0]['link'])
self.assertNotIn('secr3t', result['link'][0]['url'])
self.assertNotIn('secret', result['link'][0]['url'])
- six.assertNotRegex(self, result['url'][0]['link'], r'^-+$')
- six.assertNotRegex(self, result['link'][0]['url'], r'^-+$')
+ self.assertNotRegex(result['url'][0]['link'], r'^-+$')
+ self.assertNotRegex(result['link'][0]['url'], r'^-+$')
diff --git a/rollbar/test/test_serializable_transform.py b/rollbar/test/test_serializable_transform.py
index 3a3cab85..6978d7c0 100644
--- a/rollbar/test/test_serializable_transform.py
+++ b/rollbar/test/test_serializable_transform.py
@@ -4,24 +4,14 @@
import enum
import sys
-try:
- # Python 3
- from collections.abc import Mapping
-except ImportError:
- # Python 2.7
- from collections import Mapping
+from collections.abc import Mapping
-import six
-
-from rollbar.lib import transforms, python_major_version
+from rollbar.lib import transforms
from rollbar.lib.transforms.serializable import SerializableTransform
-from rollbar.test import BaseTest, SNOWMAN, SNOWMAN_UNICODE
-
-if python_major_version() >= 3:
- SNOWMAN = SNOWMAN_UNICODE
+from rollbar.test import BaseTest, SNOWMAN_UNICODE
-SNOWMAN_LEN = len(SNOWMAN)
+SNOWMAN_LEN = len(SNOWMAN_UNICODE)
# This base64 encoded string contains bytes that do not
@@ -29,8 +19,7 @@
invalid_b64 = b'CuX2JKuXuLVtJ6l1s7DeeQ=='
invalid = base64.b64decode(invalid_b64)
-binary_type_name = 'str' if python_major_version() < 3 else 'bytes'
-undecodable_repr = '' % (binary_type_name, invalid_b64.decode('ascii'))
+undecodable_repr = f''
class SerializableTransformTest(BaseTest):
@@ -171,10 +160,7 @@ def test_encode_namedtuple(self):
nt = MyType(field_1='this is field 1', field_2=invalid)
start = nt
- if python_major_version() < 3:
- expected = "" % undecodable_repr
- else:
- expected = "" % undecodable_repr
+ expected = "" % undecodable_repr
self._assertSerialized(start, expected)
@@ -243,10 +229,7 @@ def __repr__(self):
serializable = SerializableTransform(safelist_types=[CustomRepr])
result = transforms.transform(start, serializable)
- if python_major_version() < 3:
- self.assertEqual(result['custom'], b'hello')
- else:
- six.assertRegex(self, result['custom'], "")
+ self.assertRegex(result['custom'], "")
def test_encode_with_custom_repr_returns_object(self):
class CustomRepr(object):
@@ -257,16 +240,16 @@ def __repr__(self):
serializable = SerializableTransform(safelist_types=[CustomRepr])
result = transforms.transform(start, serializable)
- six.assertRegex(self, result['custom'], "")
+ self.assertRegex(result['custom'], "")
def test_encode_with_custom_repr_returns_unicode(self):
class CustomRepr(object):
def __repr__(self):
- return SNOWMAN
+ return SNOWMAN_UNICODE
start = {'hello': 'world', 'custom': CustomRepr()}
expected = copy.deepcopy(start)
- expected['custom'] = SNOWMAN
+ expected['custom'] = SNOWMAN_UNICODE
self._assertSerialized(start, expected, safelist=[CustomRepr])
def test_encode_with_bad_repr_doesnt_die(self):
@@ -277,7 +260,7 @@ def __repr__(self):
start = {'hello': 'world', 'custom': CustomRepr()}
serializable = SerializableTransform(safelist_types=[CustomRepr])
result = transforms.transform(start, serializable)
- six.assertRegex(self, result['custom'], "")
+ self.assertRegex(result['custom'], "")
def test_encode_with_bad_str_doesnt_die(self):
@@ -293,4 +276,4 @@ def __repr__(self):
start = {'hello': 'world', 'custom': CustomRepr()}
serializable = SerializableTransform(safelist_types=[CustomRepr])
result = transforms.transform(start, serializable)
- six.assertRegex(self, result['custom'], "")
+ self.assertRegex(result['custom'], "")
diff --git a/rollbar/test/test_shortener_transform.py b/rollbar/test/test_shortener_transform.py
index acb91a5b..55180c34 100644
--- a/rollbar/test/test_shortener_transform.py
+++ b/rollbar/test/test_shortener_transform.py
@@ -2,7 +2,6 @@
from array import array
from collections import deque
-import six
from rollbar import DEFAULT_LOCALS_SIZES
from rollbar.lib import transforms
from rollbar.lib.transforms.shortener import ShortenerTransform
@@ -71,9 +70,7 @@ def test_shorten_string(self):
self._assert_shortened('string', expected)
def test_shorten_long(self):
- expected = '179556827339164684...002504519623752387L'
- if six.PY3:
- expected = '179556827339164684...5002504519623752387'
+ expected = '179556827339164684...5002504519623752387'
self._assert_shortened('long', expected)
def test_shorten_mapping(self):
@@ -114,9 +111,7 @@ def test_shorten_deque(self):
self._assert_shortened('deque', expected)
def test_shorten_other(self):
- expected = '= "3.6"',
+ 'httpx',
'aiocontextvars; python_version == "3.6"'
]
@@ -46,17 +44,14 @@
url='http://github.com/rollbar/pyrollbar',
classifiers=[
"Programming Language :: Python",
- "Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.4",
- "Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3 :: Only",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Development Status :: 5 - Production/Stable",
@@ -78,16 +73,7 @@
"Topic :: System :: Monitoring",
],
install_requires=[
- # The currently used version of `setuptools` has a bug,
- # so the version requirements are not properly respected.
- #
- # In the current version, `requests>= 0.12.1`
- # always installs the latest version of the package.
- 'requests>=0.12.1; python_version == "2.7"',
- 'requests>=0.12.1; python_version >= "3.6"',
- 'requests>=0.12.1; python_version == "3.5"',
- 'requests>=0.12.1; python_version == "3.4"',
- 'six>=1.9.0'
+ 'requests>=0.12.1',
],
tests_require=tests_require,
)