Skip to content
This repository has been archived by the owner on Mar 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #261 from quantmind/master
Browse files Browse the repository at this point in the history
v 2.2.0
  • Loading branch information
lsbardel authored Feb 14, 2021
2 parents 4b811f5 + c9b9aa8 commit 47be34d
Show file tree
Hide file tree
Showing 17 changed files with 52 additions and 183 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
python-version: [3.7, 3.8, 3.9]

steps:
- uses: actions/checkout@v2
Expand All @@ -34,5 +34,5 @@ jobs:
- name: run tests
run: make test
- name: upload coverage
if: matrix.python-version == '3.8'
if: matrix.python-version == '3.9'
run: coveralls
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.QMBOT_GITHUB_TOKEN }}
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
python-version: [3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2020 Quantmind
Copyright (c) 2021 Quantmind

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Expand Down
6 changes: 1 addition & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Minimal makefile for Sphinx documentation
#
# Makefile for development & CI

.PHONY: help clean docs

Expand Down Expand Up @@ -64,9 +63,6 @@ test-version: ## validate version with pypi
@agilekit git validate


bundle3.6: ## build python 3.6 bundle
@python setup.py bdist_wheel --python-tag py36

bundle3.7: ## build python 3.7 bundle
@python setup.py bdist_wheel --python-tag py37

Expand Down
2 changes: 1 addition & 1 deletion dev/requirements-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ twine
agile-toolkit

# additional features
raven-aiohttp
sentry-sdk
python-dotenv
openapi-spec-validator
2 changes: 1 addition & 1 deletion openapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Minimal OpenAPI asynchronous server application"""

__version__ = "2.1.2"
__version__ = "2.2.0"
52 changes: 0 additions & 52 deletions openapi/_py36.py

This file was deleted.

2 changes: 1 addition & 1 deletion openapi/db/container.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import os
from contextlib import asynccontextmanager
from typing import Any, Optional

import asyncpg
Expand All @@ -8,7 +9,6 @@
from asyncpg.pool import Pool

from ..exc import ImproperlyConfigured
from ..utils import asynccontextmanager

DBPOOL_MIN_SIZE = int(os.environ.get("DBPOOL_MIN_SIZE") or "10")
DBPOOL_MAX_SIZE = int(os.environ.get("DBPOOL_MAX_SIZE") or "10")
Expand Down
13 changes: 13 additions & 0 deletions openapi/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,22 @@

from aiohttp import web

from .exc import ImproperlyConfigured

try:
from . import sentry
except ImportError: # pragma: no cover
sentry = None

ERROR_500 = os.environ.get("ERROR_500_MESSSAGE", "Internal Server Error")


def sentry_middleware(app, dsn, env="dev"):
if not sentry: # pragma: no cover
raise ImproperlyConfigured("Sentry middleware requires sentry-sdk")
sentry.setup(app, dsn, env)


def json_error(status_codes=None):
status_codes = set(status_codes or (404, 405, 500))
content_type = "application/json"
Expand Down
86 changes: 20 additions & 66 deletions openapi/sentry.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,20 @@
from aiohttp import web

from .exc import ImproperlyConfigured

try:
from raven import Client
from raven.conf.remote import RemoteConfig
from raven_aiohttp import AioHttpTransport
except ImportError: # pragma: no cover
AioHttpTransport = None


def middleware(app, dsn, env="dev"):
if not AioHttpTransport: # pragma: no cover
raise ImproperlyConfigured("Sentry middleware requires raven_aiohttp")
app["sentry"] = Sentry(dsn, env)
app.on_shutdown.append(close)

@web.middleware
async def middleware_handler(request, handler):
try:
return await handler(request)
except Exception:
content = await request.content.read()
data = {
"request": {
"url": str(request.url).split("?")[0],
"method": request.method.lower(),
"data": content,
"query_string": request.url.query_string,
"cookies": dict(request.cookies),
"headers": dict(request.headers),
},
"user": {"id": request.get("user_id")},
}
app["sentry"].captureException(data=data)
raise

return middleware_handler


async def close(app):
await app["sentry"].close()


class Sentry:
def __init__(self, dsn, env):
client = Client(
transport=AioHttpTransport, ignore_exceptions=[web.HTTPException]
)
client.remote = RemoteConfig(transport=AioHttpTransport)
client._transport_cache = {None: client.remote}
client.set_dsn(dsn, AioHttpTransport)
self.env = env
self.client = client

def captureException(self, data=None):
if data is None:
data = {}
data["environment"] = self.env
self.client.captureException(data=data)

async def close(self):
transport = self.client.remote.get_transport()
if transport:
await transport.close()
import logging

import sentry_sdk
from sentry_sdk.integrations.aiohttp import AioHttpIntegration
from sentry_sdk.integrations.logging import LoggingIntegration


def setup(app, dsn, env="dev", level=logging.ERROR, event_level=logging.ERROR):

sentry_sdk.init(
dsn=dsn,
environment=env,
integrations=[
LoggingIntegration(
level=level, # Capture level and above as breadcrumbs
event_level=event_level, # Send event_level and above as events
),
AioHttpIntegration(),
],
)
2 changes: 1 addition & 1 deletion openapi/testing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Testing utilities
"""
import asyncio
from contextlib import asynccontextmanager
from typing import Any

from aiohttp.client import ClientResponse
Expand All @@ -9,7 +10,6 @@

from .db.dbmodel import CrudDB
from .json import dumps, loads
from .utils import asynccontextmanager


async def json_body(response: ClientResponse, status: int = 200) -> Any:
Expand Down
22 changes: 2 additions & 20 deletions openapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,9 @@

from .exc import InvalidTypeException

if sys.version_info >= (3, 7):
from contextlib import asynccontextmanager # noqa

def get_origin(value: Any) -> Any:
return getattr(value, "__origin__", None)


else: # pragma: no cover
from ._py36 import asynccontextmanager # noqa

py36_origins = {List: list, Dict: dict}

def get_origin(value: Any) -> Any:
try:
if value in py36_origins:
origin = value
else:
origin = getattr(value, "__origin__", None)
except TypeError:
origin = getattr(value, "__origin__", None)
return py36_origins.get(origin, origin)
def get_origin(value: Any) -> Any:
return getattr(value, "__origin__", None)


if sys.version_info >= (3, 8):
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![PyPI version](https://badge.fury.io/py/aio-openapi.svg)](https://badge.fury.io/py/aio-openapi)
[![Python versions](https://img.shields.io/pypi/pyversions/aio-openapi.svg)](https://pypi.org/project/aio-openapi)
[![Build](https://github.com/quantmind/aio-openapi/workflows/build/badge.svg)](https://github.com/quantmind/aio-openapi/actions?query=workflow%3Abuild)
[![Coverage Status](https://coveralls.io/repos/github/quantmind/aio-openapi/badge.svg?branch=HEAD)](https://coveralls.io/github/quantmind/aio-openapi?branch=HEAD)
[![Coverage Status](https://coveralls.io/repos/github/quantmind/aio-openapi/badge.svg?branch=master)](https://coveralls.io/github/quantmind/aio-openapi?branch=master)
[![Documentation Status](https://readthedocs.org/projects/aio-openapi/badge/?version=latest)](https://aio-openapi.readthedocs.io/en/latest/?badge=latest)
[![Downloads](https://img.shields.io/pypi/dd/aio-openapi.svg)](https://pypi.org/project/aio-openapi/)

Expand Down
6 changes: 1 addition & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ def requirements(name):
install_requires = requirements("dev/requirements.txt")[0]
tests_require = requirements("dev/requirements-test.txt")[0]

if sys.version_info < (3, 7):
install_requires.append("dataclasses")


if sys.version_info < (3, 8):
install_requires.append("cached-property")
Expand All @@ -52,7 +49,7 @@ def requirements(name):
author_email="[email protected]",
maintainer_email="[email protected]",
url="https://github.com/quantmind/aio-openapi",
python_requires=">=3.6",
python_requires=">=3.7",
install_requires=install_requires,
tests_require=tests_require,
include_package_data=True,
Expand All @@ -64,7 +61,6 @@ def requirements(name):
"Programming Language :: JavaScript",
"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",
Expand Down
8 changes: 4 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import asyncio
import os
import shutil
from unittest import mock

import pytest
from aiohttp import test_utils
from aiohttp.web import Application
from asynctest import CoroutineMock
from sqlalchemy_utils import create_database, database_exists

from openapi.db.dbmodel import CrudDB
Expand All @@ -23,9 +23,9 @@ def clean_migrations():

@pytest.fixture(autouse=True)
def sentry_mock(mocker):
mock = CoroutineMock()
mocker.patch("raven_aiohttp.AioHttpTransport._do_send", mock)
return mock
mm = mock.MagicMock()
mocker.patch("sentry_sdk.init", mm)
return mm


@pytest.fixture(scope="session", autouse=True)
Expand Down
17 changes: 0 additions & 17 deletions tests/core/test_sentry.py

This file was deleted.

7 changes: 2 additions & 5 deletions tests/example/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

from aiohttp import web

from openapi import sentry
from openapi.db.commands import db as db_command
from openapi.middleware import json_error
from openapi.middleware import json_error, sentry_middleware
from openapi.rest import rest
from openapi.spec import Redoc

Expand Down Expand Up @@ -39,9 +38,7 @@ def create_app():
def setup_app(app: web.Application) -> None:
db.setup(app)
app.middlewares.append(json_error())
app.middlewares.append(
sentry.middleware(app, f"https://{uuid.uuid4().hex}@sentry.io/1234567", "test")
)
sentry_middleware(app, f"https://{uuid.uuid4().hex}@sentry.io/1234567", "test")
app.router.add_routes(base_routes)
app.router.add_routes(routes)
#
Expand Down

0 comments on commit 47be34d

Please sign in to comment.