diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index c11b912..4292e5a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -81,6 +81,6 @@ jobs: - name: Install test dependencies run: poetry install --no-interaction --no-root --only test - name: Install app dependencies - run: poetry run pip install ${{ matrix.deps }} ./dist/starlette_apitally-*.whl + run: poetry run pip install ${{ matrix.deps }} ./dist/apitally-*.whl - name: Run tests run: poetry run make test diff --git a/Makefile b/Makefile index 55c3267..f1deef5 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ .PHONY: format check test test-coverage format: - ruff check starlette_apitally tests --fix --select I - black starlette_apitally tests + ruff check apitally tests --fix --select I + black apitally tests check: - ruff check starlette_apitally tests - mypy --install-types --non-interactive starlette_apitally tests - black --check --diff starlette_apitally tests + ruff check apitally tests + mypy --install-types --non-interactive apitally tests + black --check --diff apitally tests poetry check test: diff --git a/README.md b/README.md index a4d8acd..ec81771 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,22 @@ -# Starlette Apitally +# Apitally client for Python -[![Tests](https://github.com/apitally/starlette-apitally/actions/workflows/tests.yaml/badge.svg?event=push)](https://github.com/apitally/starlette-apitally/actions) -[![Codecov](https://codecov.io/gh/apitally/starlette-apitally/branch/main/graph/badge.svg?token=UNLYBY4Y3V)](https://codecov.io/gh/apitally/starlette-apitally) -[![PyPI](https://img.shields.io/pypi/v/starlette-apitally?logo=pypi&logoColor=white&color=%23006dad)](https://pypi.org/project/starlette-apitally/) +[![Tests](https://github.com/apitally/apitally-python/actions/workflows/tests.yaml/badge.svg?event=push)](https://github.com/apitally/apitally-python/actions) +[![Codecov](https://codecov.io/gh/apitally/apitally-python/branch/main/graph/badge.svg?token=UNLYBY4Y3V)](https://codecov.io/gh/apitally/apitally-python) +[![PyPI](https://img.shields.io/pypi/v/apitally?logo=pypi&logoColor=white&color=%23006dad)](https://pypi.org/project/apitally/) -Apitally integration for Starlette / FastAPI. - -The integration is implemented as a middleware which sends metrics about requests and responses to [Apitally](https://apitally.io) every 10 seconds. This is done asynchronously and does not impact the performance of your application. +Apitally client library for Python. ## Installation ```bash -pip install starlette-apitally +pip install apitally ``` ## Usage with FastAPI ```python from fastapi import FastAPI -from starlette_apitally import ApitallyMiddleware +from apitally.fastapi import ApitallyMiddleware app = FastAPI() app.add_middleware(ApitallyMiddleware, client_id="") @@ -28,7 +26,7 @@ app.add_middleware(ApitallyMiddleware, client_id="") ```python from starlette.applications import Starlette -from starlette_apitally import ApitallyMiddleware +from apitally.starlette import ApitallyMiddleware app = Starlette() app.add_middleware(ApitallyMiddleware, client_id="") diff --git a/starlette_apitally/__init__.py b/apitally/__init__.py similarity index 100% rename from starlette_apitally/__init__.py rename to apitally/__init__.py diff --git a/starlette_apitally/client.py b/apitally/client.py similarity index 97% rename from starlette_apitally/client.py rename to apitally/client.py index 0acc6a0..0c51014 100644 --- a/starlette_apitally/client.py +++ b/apitally/client.py @@ -10,8 +10,8 @@ import backoff import httpx -from starlette_apitally.keys import KeyRegistry -from starlette_apitally.requests import RequestLogger +from apitally.keys import KeyRegistry +from apitally.requests import RequestLogger logger = logging.getLogger(__name__) diff --git a/starlette_apitally/fastapi.py b/apitally/fastapi.py similarity index 93% rename from starlette_apitally/fastapi.py rename to apitally/fastapi.py index 0038203..a7e296f 100644 --- a/starlette_apitally/fastapi.py +++ b/apitally/fastapi.py @@ -8,9 +8,9 @@ from fastapi.security.utils import get_authorization_scheme_param from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN -from starlette_apitally.client import ApitallyClient -from starlette_apitally.keys import KeyInfo -from starlette_apitally.starlette import ApitallyMiddleware +from apitally.client import ApitallyClient +from apitally.keys import KeyInfo +from apitally.starlette import ApitallyMiddleware __all__ = ["ApitallyMiddleware", "KeyInfo", "api_key_auth"] diff --git a/starlette_apitally/keys.py b/apitally/keys.py similarity index 100% rename from starlette_apitally/keys.py rename to apitally/keys.py diff --git a/starlette_apitally/requests.py b/apitally/requests.py similarity index 100% rename from starlette_apitally/requests.py rename to apitally/requests.py diff --git a/starlette_apitally/starlette.py b/apitally/starlette.py similarity index 96% rename from starlette_apitally/starlette.py rename to apitally/starlette.py index 34f18e8..971644d 100644 --- a/starlette_apitally/starlette.py +++ b/apitally/starlette.py @@ -23,9 +23,9 @@ from starlette.testclient import TestClient from starlette.types import ASGIApp -import starlette_apitally -from starlette_apitally.client import ApitallyClient -from starlette_apitally.keys import KeyInfo +import apitally +from apitally.client import ApitallyClient +from apitally.keys import KeyInfo if TYPE_CHECKING: @@ -142,7 +142,7 @@ def _get_app_info(app: ASGIApp, app_version: Optional[str], openapi_url: Optiona elif endpoints := _get_endpoint_info(app): app_info["paths"] = [{"path": endpoint.path, "method": endpoint.http_method} for endpoint in endpoints] app_info["versions"] = _get_versions(app_version) - app_info["client"] = "starlette-apitally" + app_info["client"] = "apitally-python" return app_info @@ -175,7 +175,7 @@ def _get_routes(app: ASGIApp) -> List[BaseRoute]: def _get_versions(app_version: Optional[str]) -> Dict[str, str]: versions = { "python": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", - "starlette-apitally": starlette_apitally.__version__, + "apitally": apitally.__version__, "starlette": starlette.__version__, } try: diff --git a/pyproject.toml b/pyproject.toml index 7e61992..e9d35ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,12 +3,12 @@ requires = ["poetry-core", "poetry-dynamic-versioning"] build-backend = "poetry_dynamic_versioning.backend" [tool.poetry] -name = "starlette-apitally" +name = "apitally" version = "0.0.0" -description = "Apitally integration for Starlette" +description = "Apitally client library for Python" authors = ["Simon Gurcke "] license = "MIT License" -repository = "https://github.com/apitally/starlette-apitally" +repository = "https://github.com/apitally/apitally-python" readme = "README.md" [tool.poetry.dependencies] @@ -58,7 +58,7 @@ asyncio_mode = "auto" testpaths = ["tests"] [tool.coverage.run] -source = ["starlette_apitally"] +source = ["apitally"] [tool.coverage.report] exclude_lines = ["pragma: no cover", "if TYPE_CHECKING"] diff --git a/tests/test_client.py b/tests/test_client.py index d96d4e0..717a9b6 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: - from starlette_apitally.client import ApitallyClient + from apitally.client import ApitallyClient CLIENT_ID = "76b5cb91-a0a4-4ea0-a894-57d2b9fcb2c9" @@ -19,10 +19,10 @@ @pytest.fixture() async def client(mocker: MockerFixture) -> AsyncIterator[ApitallyClient]: - from starlette_apitally.client import ApitallyClient + from apitally.client import ApitallyClient - mocker.patch("starlette_apitally.client.ApitallyClient.start_sync_loop") - mocker.patch("starlette_apitally.client.ApitallyClient._run_sync_loop") + mocker.patch("apitally.client.ApitallyClient.start_sync_loop") + mocker.patch("apitally.client.ApitallyClient._run_sync_loop") client = ApitallyClient(client_id=CLIENT_ID, env=ENV, enable_keys=True) client.request_logger.log_request( @@ -41,7 +41,7 @@ async def client(mocker: MockerFixture) -> AsyncIterator[ApitallyClient]: async def test_send_requests_data(client: ApitallyClient, httpx_mock: HTTPXMock): - from starlette_apitally.client import HUB_BASE_URL, HUB_VERSION + from apitally.client import HUB_BASE_URL, HUB_VERSION httpx_mock.add_response() async with client.get_http_client() as http_client: @@ -55,7 +55,7 @@ async def test_send_requests_data(client: ApitallyClient, httpx_mock: HTTPXMock) async def test_send_app_info(client: ApitallyClient, httpx_mock: HTTPXMock): - from starlette_apitally.client import HUB_BASE_URL, HUB_VERSION + from apitally.client import HUB_BASE_URL, HUB_VERSION httpx_mock.add_response() app_info = {"paths": [], "client_version": "1.0.0", "starlette_version": "0.28.0", "python_version": "3.11.4"} @@ -70,7 +70,7 @@ async def test_send_app_info(client: ApitallyClient, httpx_mock: HTTPXMock): async def test_get_keys(client: ApitallyClient, httpx_mock: HTTPXMock): - from starlette_apitally.client import HUB_BASE_URL, HUB_VERSION + from apitally.client import HUB_BASE_URL, HUB_VERSION httpx_mock.add_response(json={"salt": "x", "keys": {"x": {"key_id": 1, "expires_in_seconds": None}}}) await client.get_keys() diff --git a/tests/test_fastapi.py b/tests/test_fastapi.py index 23a76a3..b6e8bbc 100644 --- a/tests/test_fastapi.py +++ b/tests/test_fastapi.py @@ -13,14 +13,14 @@ if TYPE_CHECKING: from fastapi import FastAPI -from starlette_apitally.keys import KeyInfo # import here to avoid pydantic error +from apitally.keys import KeyInfo # import here to avoid pydantic error @pytest.fixture() def app_with_auth() -> FastAPI: from fastapi import Depends, FastAPI, Security - from starlette_apitally.fastapi import api_key_auth + from apitally.fastapi import api_key_auth app = FastAPI() @@ -42,7 +42,7 @@ def baz(): def test_api_key_auth(app_with_auth: FastAPI, mocker: MockerFixture): from starlette.testclient import TestClient - from starlette_apitally.keys import KeyInfo, KeyRegistry + from apitally.keys import KeyInfo, KeyRegistry client = TestClient(app_with_auth) key_registry = KeyRegistry() @@ -55,7 +55,7 @@ def test_api_key_auth(app_with_auth: FastAPI, mocker: MockerFixture): ) } headers = {"Authorization": "ApiKey 7ll40FB.DuHxzQQuGQU4xgvYvTpmnii7K365j9VI"} - mock = mocker.patch("starlette_apitally.fastapi.ApitallyClient.get_instance") + mock = mocker.patch("apitally.fastapi.ApitallyClient.get_instance") mock.return_value.key_registry = key_registry # Unauthenticated diff --git a/tests/test_keys.py b/tests/test_keys.py index 3e8b7b5..0f1f45b 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -2,7 +2,7 @@ def test_keys(): - from starlette_apitally.keys import KeyRegistry + from apitally.keys import KeyRegistry keys = KeyRegistry() diff --git a/tests/test_requests.py b/tests/test_requests.py index 94f5d4b..e02b247 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -6,12 +6,12 @@ if TYPE_CHECKING: - from starlette_apitally.requests import RequestLogger + from apitally.requests import RequestLogger @pytest.fixture() def requests() -> RequestLogger: - from starlette_apitally.requests import RequestLogger + from apitally.requests import RequestLogger requests = RequestLogger() requests.log_request( diff --git a/tests/test_starlette.py b/tests/test_starlette.py index 59bb865..2b35858 100644 --- a/tests/test_starlette.py +++ b/tests/test_starlette.py @@ -37,8 +37,8 @@ def event_loop() -> Iterator[AbstractEventLoop]: params=["starlette", "fastapi"] if find_spec("fastapi") is not None else ["starlette"], ) async def app(request: FixtureRequest, module_mocker: MockerFixture) -> Starlette: - module_mocker.patch("starlette_apitally.client.ApitallyClient.start_sync_loop") - module_mocker.patch("starlette_apitally.client.ApitallyClient.send_app_info") + module_mocker.patch("apitally.client.ApitallyClient.start_sync_loop") + module_mocker.patch("apitally.client.ApitallyClient.send_app_info") if request.param == "starlette": return get_starlette_app() elif request.param == "fastapi": @@ -55,7 +55,7 @@ def app_with_auth() -> Starlette: from starlette.responses import JSONResponse, PlainTextResponse from starlette.routing import Route - from starlette_apitally.starlette import ApitallyKeysBackend + from apitally.starlette import ApitallyKeysBackend @requires(["authenticated", "foo"]) def foo(request: Request): @@ -93,7 +93,7 @@ def get_starlette_app() -> Starlette: from starlette.responses import PlainTextResponse from starlette.routing import Route - from starlette_apitally.starlette import ApitallyMiddleware + from apitally.starlette import ApitallyMiddleware background_task_mock = MagicMock() @@ -124,7 +124,7 @@ def baz(request: Request): def get_fastapi_app() -> Starlette: from fastapi import FastAPI - from starlette_apitally.fastapi import ApitallyMiddleware + from apitally.fastapi import ApitallyMiddleware background_task_mock = MagicMock() @@ -154,8 +154,8 @@ def baz(): def test_middleware_param_validation(app: Starlette): - from starlette_apitally.client import ApitallyClient - from starlette_apitally.starlette import ApitallyMiddleware + from apitally.client import ApitallyClient + from apitally.starlette import ApitallyMiddleware ApitallyClient._instance = None @@ -172,7 +172,7 @@ def test_middleware_param_validation(app: Starlette): def test_middleware_requests_ok(app: Starlette, mocker: MockerFixture): from starlette.testclient import TestClient - mock = mocker.patch("starlette_apitally.requests.RequestLogger.log_request") + mock = mocker.patch("apitally.requests.RequestLogger.log_request") client = TestClient(app) background_task_mock: MagicMock = app.state.background_task_mock # type: ignore[attr-defined] @@ -203,8 +203,8 @@ def test_middleware_requests_ok(app: Starlette, mocker: MockerFixture): def test_middleware_requests_error(app: Starlette, mocker: MockerFixture): from starlette.testclient import TestClient - mocker.patch("starlette_apitally.client.ApitallyClient.send_app_info") - mock = mocker.patch("starlette_apitally.requests.RequestLogger.log_request") + mocker.patch("apitally.client.ApitallyClient.send_app_info") + mock = mocker.patch("apitally.requests.RequestLogger.log_request") client = TestClient(app, raise_server_exceptions=False) response = client.post("/baz/") @@ -220,8 +220,8 @@ def test_middleware_requests_error(app: Starlette, mocker: MockerFixture): def test_middleware_requests_unhandled(app: Starlette, mocker: MockerFixture): from starlette.testclient import TestClient - mocker.patch("starlette_apitally.client.ApitallyClient.send_app_info") - mock = mocker.patch("starlette_apitally.requests.RequestLogger.log_request") + mocker.patch("apitally.client.ApitallyClient.send_app_info") + mock = mocker.patch("apitally.requests.RequestLogger.log_request") client = TestClient(app) response = client.post("/xxx/") @@ -232,7 +232,7 @@ def test_middleware_requests_unhandled(app: Starlette, mocker: MockerFixture): def test_keys_auth_backend(app_with_auth: Starlette, mocker: MockerFixture): from starlette.testclient import TestClient - from starlette_apitally.keys import KeyInfo, KeyRegistry + from apitally.keys import KeyInfo, KeyRegistry client = TestClient(app_with_auth) key_registry = KeyRegistry() @@ -245,7 +245,7 @@ def test_keys_auth_backend(app_with_auth: Starlette, mocker: MockerFixture): ) } headers = {"Authorization": "ApiKey 7ll40FB.DuHxzQQuGQU4xgvYvTpmnii7K365j9VI"} - mock = mocker.patch("starlette_apitally.starlette.ApitallyClient.get_instance") + mock = mocker.patch("apitally.starlette.ApitallyClient.get_instance") mock.return_value.key_registry = key_registry # Unauthenticated @@ -277,9 +277,9 @@ def test_keys_auth_backend(app_with_auth: Starlette, mocker: MockerFixture): def test_get_app_info(app: Starlette, mocker: MockerFixture): - from starlette_apitally.starlette import _get_app_info + from apitally.starlette import _get_app_info - mocker.patch("starlette_apitally.starlette.ApitallyClient") + mocker.patch("apitally.starlette.ApitallyClient") if app.middleware_stack is None: app.middleware_stack = app.build_middleware_stack()