Skip to content

Commit

Permalink
Merge pull request #455 from rollbar/updated/frameworks-and-tests
Browse files Browse the repository at this point in the history
Updated supported and tested frameworks and modernized tests and packaging.
  • Loading branch information
danielmorell authored Sep 13, 2024
2 parents 8493ac0 + c7130d5 commit 4956f85
Show file tree
Hide file tree
Showing 15 changed files with 181 additions and 126 deletions.
87 changes: 59 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,76 @@ jobs:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9, '3.10', 3.11]
framework:
- NONE
- FLASK_VERSION=1.1.4
- FLASK_VERSION=2.2.3
- DJANGO_VERSION=1.11.29
- DJANGO_VERSION=2.2.28
- DJANGO_VERSION=3.2.18
- DJANGO_VERSION=4.0.10
- DJANGO_VERSION=4.1.7
- FLASK_VERSION=2.3.3
- FLASK_VERSION=3.0.3
- DJANGO_VERSION=3.2.25
- DJANGO_VERSION=4.2.15
- DJANGO_VERSION=5.0.8
- TWISTED_VERSION=20.3.0
- TWISTED_VERSION=21.7.0
- TWISTED_VERSION=22.10.0
- PYRAMID_VERSION=1.10.8
- STARLETTE_VERSION=0.12.13 httpx==0.18.1 python-multipart==0.0.5
- STARLETTE_VERSION=0.14.2 httpx==0.18.1 python-multipart==0.0.5
- FASTAPI_VERSION=0.40.0 httpx==0.18.1 python-multipart==0.0.5
- FASTAPI_VERSION=0.50.0 httpx==0.18.1 python-multipart==0.0.5
- FASTAPI_VERSION=0.63.0 httpx==0.18.1 python-multipart==0.0.5
- PYRAMID_VERSION=2.0.2
- STARLETTE_VERSION=0.30.0 httpx==0.24.1 python-multipart==0.0.9
- STARLETTE_VERSION=0.38.2 httpx==0.27.0 python-multipart==0.0.9
- FASTAPI_VERSION=0.101.1 httpx==0.24.1 python-multipart==0.0.9
- FASTAPI_VERSION=0.112.1 httpx==0.27.0 python-multipart==0.0.9
exclude:
# Test frameworks on the python versions they support, according to pypi registry
# Flask
- framework: FLASK_VERSION=2.2.3
- framework: FLASK_VERSION=2.3.3
python-version: 3.6
- framework: FLASK_VERSION=2.3.3
python-version: 3.7
- framework: FLASK_VERSION=3.0.3
python-version: 3.6
- framework: FLASK_VERSION=3.0.3
python-version: 3.7

# Django
- framework: DJANGO_VERSION=1.11.29
python-version: 3.8
- framework: DJANGO_VERSION=1.11.29
python-version: 3.9
- framework: DJANGO_VERSION=1.11.29
python-version: '3.10'
- framework: DJANGO_VERSION=1.11.29
- framework: DJANGO_VERSION=3.2.25
python-version: 3.11
- framework: DJANGO_VERSION=4.0.10
- framework: DJANGO_VERSION=4.2.15
python-version: 3.6
- framework: DJANGO_VERSION=4.0.10
- framework: DJANGO_VERSION=4.2.15
python-version: 3.7
- framework: DJANGO_VERSION=4.1.7
python-version: 3.5
- framework: DJANGO_VERSION=4.1.7
- framework: DJANGO_VERSION=5.0.8
python-version: 3.6
- framework: DJANGO_VERSION=4.1.7
- framework: DJANGO_VERSION=5.0.8
python-version: 3.7
- framework: DJANGO_VERSION=5.0.8
python-version: 3.8
- framework: DJANGO_VERSION=5.0.8
python-version: 3.9

# Twisted
- framework: TWISTED_VERSION=20.3.0
python-version: 3.11
- framework: TWISTED_VERSION=22.10.0
python-version: 3.6

# Starlette
- framework: STARLETTE_VERSION=0.30.0 httpx==0.24.1 python-multipart==0.0.9
python-version: 3.6
- framework: STARLETTE_VERSION=0.30.0 httpx==0.24.1 python-multipart==0.0.9
python-version: 3.7
- framework: STARLETTE_VERSION=0.38.2 httpx==0.27.0 python-multipart==0.0.9
python-version: 3.6
- framework: STARLETTE_VERSION=0.38.2 httpx==0.27.0 python-multipart==0.0.9
python-version: 3.7

# FastAPI
- framework: FASTAPI_VERSION=0.101.1 httpx==0.24.1 python-multipart==0.0.9
python-version: 3.6
- framework: FASTAPI_VERSION=0.101.1 httpx==0.24.1 python-multipart==0.0.9
python-version: 3.7
- framework: FASTAPI_VERSION=0.112.1 httpx==0.27.0 python-multipart==0.0.9
python-version: 3.6
- framework: FASTAPI_VERSION=0.112.1 httpx==0.27.0 python-multipart==0.0.9
python-version: 3.7

steps:
- uses: actions/checkout@v2
with:
Expand All @@ -75,14 +97,15 @@ jobs:
- 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 "typing-extensions<4.2" requests==2.27.0 blinker==1.5 immutables==0.19
run: pip install "typing-extensions<4.2" requests==2.27.0 blinker==1.5 immutables==0.19 webob blinker httpx aiocontextvars

- 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
if: ${{ matrix.framework != 'NONE' }}
run: echo ${{ matrix.framework }} >> $GITHUB_ENV

- name: Install Flask
Expand All @@ -109,5 +132,13 @@ jobs:
if: ${{ contains(matrix.framework, 'FASTAPI_VERSION') }}
run: pip install fastapi==$FASTAPI_VERSION

- name: Run tests
run: python setup.py test
- name: Install Tox
run: pip install tox

- name: Run tests (skip on Python 3.6)
if: ${{ !contains(matrix.python-version, '3.6') }}
run: tox

- name: Run tests (Python 3.6)
if: ${{ contains(matrix.python-version, '3.6') }}
run: python -m unittest rollbar.test.discover
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Pipfile
Pipfile.lock
.pytest_cache/
.python-version
.tox/
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Python notifier for reporting exceptions, errors, and log messages to [Rollbar](
- **Advanced search:** Filter items by many different properties. <a href="https://docs.rollbar.com/docs/search-items">Learn more about search</a>.
- **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. <a href="https://docs.rollbar.com/docs/notifications">Learn more about Rollbar notifications</a>.

## Versions Supported
## Python Versions Supported

| PyRollbar Version | Python Version Compatibility | Support Level |
|-------------------|-----------------------------------------------|---------------------|
Expand All @@ -33,6 +33,26 @@ Python notifier for reporting exceptions, errors, and log messages to [Rollbar](

**Security Fixes Only** - We will only provide critical security fixes for the library.

## Frameworks Supported

Generally, PyRollbar can be used with any Python framework. However, we have official support for the following frameworks:

| Framework | Support Duration | Tested Versions |
|-----------|----------------------------|-----------------|
| Celery | Release +1 year | None |
| Django | Release or LTS end +1 year | 3.2, 4.2, 5.0 |
| FastAPI | Release +1 year | 0.101, 0.112 |
| Flask | Release +1 year | 1.1, 2.3, 3.0 |
| Pyramid | Release +1 year | 1.10, 2.0 |

Official support means that we ship and maintain integrations for these frameworks. It also means that we test against these frameworks as part of our CI pipeline.

Generally, we will support the last year of releases for a framework. If a framework has a defined support period (including LTS releases), we will support the release for the duration of that period plus one year.

### Community Supported

There are also a number of community-supported integrations available. For more information, see the [Python SDK docs](https://docs.rollbar.com/docs/python-community-supported-sdks).

## Setup Instructions

1. [Sign up for a Rollbar account](https://rollbar.com/signup)
Expand Down
54 changes: 54 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[project]
name = "rollbar"
dynamic = ["version"]
description = "Easy and powerful exception tracking with Rollbar. Send messages and exceptions with arbitrary context, get back aggregates, and debug production issues quickly."
readme = "README.md"
license = {file = "LICENSE"}
maintainers = [{name = "Rollbar, Inc.", email = "support@rollbar.com"}]
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"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",
"Environment :: Web Environment",
"Framework :: AsyncIO",
"Framework :: Bottle",
"Framework :: Django",
"Framework :: Flask",
"Framework :: Pylons",
"Framework :: Pyramid",
"Framework :: Twisted",
"Intended Audience :: Developers",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development",
"Topic :: Software Development :: Bug Tracking",
"Topic :: Software Development :: Testing",
"Topic :: Software Development :: Quality Assurance",
"Topic :: System :: Logging",
"Topic :: System :: Monitoring",
]
requires-python = ">=3.6"
dependencies = [
"requests>=0.12.1",
]

[project.urls]
Homepage = "https://rollbar.com/"
Documentation = "https://docs.rollbar.com/docs/python"
Changes = "https://github.com/rollbar/pyrollbar/blob/master/CHANGELOG.md"
Source = "https://github.com/rollbar/pyrollbar/"

[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[tool.setuptools.dynamic]
version = {attr = "rollbar.__version__"}
6 changes: 5 additions & 1 deletion rollbar/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1372,7 +1372,7 @@ def _build_starlette_request_data(request):
'params': dict(request.path_params),
}

if hasattr(request, '_form'):
if hasattr(request, '_form') and request._form is not None:
request_data['POST'] = {
k: v.filename if isinstance(v, UploadFile) else v
for k, v in request._form.items()
Expand Down Expand Up @@ -1772,4 +1772,8 @@ def _wsgi_extract_user_ip(environ):


def _starlette_extract_user_ip(request):
if not hasattr(request, 'client'):
return _extract_user_ip_from_headers(request)
if not hasattr(request.client, 'host'):
return _extract_user_ip_from_headers(request)
return request.client.host or _extract_user_ip_from_headers(request)
2 changes: 2 additions & 0 deletions rollbar/lib/transforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def transform(obj, transforms, key=None, batch_transforms=False):
transforms = [BatchedTransform(transforms)]

for transform in transforms:
if not isinstance(transform, Transform):
continue
obj = _transform(obj, transform, key=key)

return obj
Expand Down
5 changes: 3 additions & 2 deletions rollbar/test/fastapi_tests/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def test_should_add_framework_version_to_payload(self, mock_send_payload, *mocks

app = FastAPI()
app.add_middleware(LoggerMiddleware)
app.build_middleware_stack()

rollbar.report_exc_info()

Expand Down Expand Up @@ -70,10 +71,10 @@ def test_should_store_current_request(self, store_current_request):
'client': ['testclient', 50000],
'headers': [
(b'host', b'testserver'),
(b'user-agent', b'testclient'),
(b'accept-encoding', b'gzip, deflate'),
(b'accept', b'*/*'),
(b'accept-encoding', b'gzip, deflate'),
(b'connection', b'keep-alive'),
(b'user-agent', b'testclient'),
],
'http_version': '1.1',
'method': 'GET',
Expand Down
8 changes: 5 additions & 3 deletions rollbar/test/fastapi_tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import rollbar
from rollbar.lib._async import AsyncMock
from rollbar.test import BaseTest
from rollbar.test.utils import get_public_attrs

ALLOWED_PYTHON_VERSION = sys.version_info >= (3, 6)

Expand Down Expand Up @@ -152,6 +153,7 @@ def test_should_add_framework_version_to_payload(self, mock_send_payload, *mocks

app = FastAPI()
app.add_middleware(ReporterMiddleware)
app.build_middleware_stack()

rollbar.report_exc_info()

Expand Down Expand Up @@ -272,10 +274,10 @@ def test_should_store_current_request(self, store_current_request):
'client': ['testclient', 50000],
'headers': [
(b'host', b'testserver'),
(b'user-agent', b'testclient'),
(b'accept-encoding', b'gzip, deflate'),
(b'accept', b'*/*'),
(b'accept-encoding', b'gzip, deflate'),
(b'connection', b'keep-alive'),
(b'user-agent', b'testclient'),
],
'http_version': '1.1',
'method': 'GET',
Expand Down Expand Up @@ -324,7 +326,7 @@ def test_should_return_current_request(self):
async def read_root(original_request: Request):
request = get_current_request()

self.assertEqual(request, original_request)
self.assertEqual(get_public_attrs(request), get_public_attrs(original_request))

client = TestClient(app)
client.get('/')
Expand Down
5 changes: 3 additions & 2 deletions rollbar/test/starlette_tests/test_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def test_should_add_framework_version_to_payload(self, mock_send_payload, *mocks

app = Starlette()
app.add_middleware(LoggerMiddleware)
app.build_middleware_stack()

rollbar.report_exc_info()

Expand Down Expand Up @@ -67,10 +68,10 @@ def test_should_store_current_request(self, store_current_request):
'client': ['testclient', 50000],
'headers': [
(b'host', b'testserver'),
(b'user-agent', b'testclient'),
(b'accept-encoding', b'gzip, deflate'),
(b'accept', b'*/*'),
(b'accept-encoding', b'gzip, deflate'),
(b'connection', b'keep-alive'),
(b'user-agent', b'testclient'),
],
'http_version': '1.1',
'method': 'GET',
Expand Down
8 changes: 5 additions & 3 deletions rollbar/test/starlette_tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import rollbar
from rollbar.lib._async import AsyncMock
from rollbar.test import BaseTest
from rollbar.test.utils import get_public_attrs

ALLOWED_PYTHON_VERSION = sys.version_info >= (3, 6)

Expand Down Expand Up @@ -138,6 +139,7 @@ def test_should_add_framework_version_to_payload(self, mock_send_payload, *mocks

app = Starlette()
app.add_middleware(ReporterMiddleware)
app.build_middleware_stack()

rollbar.report_exc_info()

Expand Down Expand Up @@ -243,10 +245,10 @@ def test_should_store_current_request(self, store_current_request):
'client': ['testclient', 50000],
'headers': [
(b'host', b'testserver'),
(b'user-agent', b'testclient'),
(b'accept-encoding', b'gzip, deflate'),
(b'accept', b'*/*'),
(b'accept-encoding', b'gzip, deflate'),
(b'connection', b'keep-alive'),
(b'user-agent', b'testclient'),
],
'http_version': '1.1',
'method': 'GET',
Expand Down Expand Up @@ -290,7 +292,7 @@ def test_should_return_current_request(self):
async def root(original_request):
request = get_current_request()

self.assertEqual(request, original_request)
self.assertEqual(get_public_attrs(request), get_public_attrs(original_request))

return PlainTextResponse('OK')

Expand Down
Loading

0 comments on commit 4956f85

Please sign in to comment.