From c8cb83d4f98f8b5735c016f3c191605835ba2555 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Sun, 9 Jun 2024 20:36:11 -0400 Subject: [PATCH 1/2] Python: update deps and switch to ruff. --- python/requirements-dev.txt | 57 ++++++-------------------- python/requirements.in/development.txt | 7 +--- python/scripts/format.sh | 5 +-- python/scripts/lint.sh | 5 +-- 4 files changed, 18 insertions(+), 56 deletions(-) diff --git a/python/requirements-dev.txt b/python/requirements-dev.txt index 59147f3af..60a1a463b 100644 --- a/python/requirements-dev.txt +++ b/python/requirements-dev.txt @@ -1,6 +1,6 @@ # -# This file is autogenerated by pip-compile -# To update, run: +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: # # pip-compile --output-file=requirements-dev.txt requirements.in/development.txt # @@ -11,13 +11,9 @@ attrs==21.4.0 # openapi-python-client # pytest autoflake==1.4 - # via - # -r requirements.in/development.txt - # openapi-python-client + # via openapi-python-client black==23.3.0 - # via - # -r requirements.in/development.txt - # openapi-python-client + # via openapi-python-client build==0.10.0 # via pip-tools certifi==2023.07.22 @@ -29,15 +25,6 @@ click==8.0.1 # black # pip-tools # typer -flake8-polyfill==1.0.2 - # via pep8-naming -flake8-print==4.0.0 - # via -r requirements.in/development.txt -flake8==3.9.2 - # via - # -r requirements.in/development.txt - # flake8-polyfill - # flake8-print h11==0.12.0 # via httpcore httpcore==0.15.0 @@ -53,23 +40,19 @@ idna==3.3 iniconfig==1.1.1 # via pytest isort==5.8.0 - # via - # -r requirements.in/development.txt - # openapi-python-client + # via openapi-python-client jinja2==3.1.3 # via # -r requirements.in/development.txt # openapi-python-client markupsafe==2.1.0 # via jinja2 -mccabe==0.6.1 - # via flake8 +mypy==1.4.0 + # via -r requirements.in/development.txt mypy-extensions==1.0.0 # via # black # mypy -mypy==1.4.0 - # via -r requirements.in/development.txt openapi-python-client==0.14.1 # via -r requirements.in/development.txt packaging==23.1 @@ -79,8 +62,6 @@ packaging==23.1 # pytest pathspec==0.11.1 # via black -pep8-naming==0.11.1 - # via -r requirements.in/development.txt pip-tools==6.13.0 # via -r requirements.in/development.txt platformdirs==3.5.1 @@ -89,32 +70,26 @@ pluggy==0.13.1 # via pytest py==1.10.0 # via pytest -pycodestyle==2.7.0 - # via - # flake8 - # flake8-print -pydantic==1.10.0 +pydantic==1.10.13 # via openapi-python-client pyflakes==2.3.1 - # via - # autoflake - # flake8 + # via autoflake pyproject-hooks==1.0.0 # via build pytest==6.2.4 # via -r requirements.in/development.txt python-dateutil==2.8.2 # via openapi-python-client -pyyaml==6.0 +pyyaml==6.0.1 # via openapi-python-client rfc3986[idna2008]==1.5.0 # via httpx +ruff==0.4.8 + # via -r requirements.in/development.txt shellingham==1.4.0 # via openapi-python-client six==1.16.0 - # via - # flake8-print - # python-dateutil + # via python-dateutil sniffio==1.2.0 # via # anyio @@ -122,12 +97,6 @@ sniffio==1.2.0 # httpx toml==0.10.2 # via pytest -tomli==2.0.1 - # via - # black - # build - # mypy - # pyproject-hooks typer==0.7.0 # via openapi-python-client typing-extensions==4.6.3 diff --git a/python/requirements.in/development.txt b/python/requirements.in/development.txt index fc586b39d..7b885d039 100644 --- a/python/requirements.in/development.txt +++ b/python/requirements.in/development.txt @@ -1,9 +1,4 @@ -autoflake -black -isort -flake8 -flake8-print -pep8-naming +ruff mypy>=1.4.0 pip-tools>=6.13.0 pytest diff --git a/python/scripts/format.sh b/python/scripts/format.sh index 39ab708df..2abbf078f 100755 --- a/python/scripts/format.sh +++ b/python/scripts/format.sh @@ -1,6 +1,5 @@ #!/bin/sh -e set -x -autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place svix --exclude=__init__.py -isort svix -black svix +ruff check --fix svix +ruff format svix diff --git a/python/scripts/lint.sh b/python/scripts/lint.sh index 5fff9884e..dd3b4dbfa 100755 --- a/python/scripts/lint.sh +++ b/python/scripts/lint.sh @@ -3,6 +3,5 @@ set -ex mypy svix -isort --check-only svix -black svix --check -flake8 svix +ruff check svix +ruff format --check svix From b150951dc06f2517af7b972c697b6e0fba866a8f Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Sun, 9 Jun 2024 20:38:10 -0400 Subject: [PATCH 2/2] Run ruff format and fix. --- python/example.py | 18 +- python/setup.py | 8 +- python/svix/api.py | 481 ++++++++++++++++++++++++++-------- python/svix/webhooks.py | 4 +- python/tests/test_webhooks.py | 60 +++-- 5 files changed, 425 insertions(+), 146 deletions(-) diff --git a/python/example.py b/python/example.py index c448cadfb..e4acb787b 100644 --- a/python/example.py +++ b/python/example.py @@ -1,17 +1,10 @@ -import time import whsaas.openapi_client from pprint import pprint from whsaas.openapi_client.api import application_api -from whsaas.openapi_client.model.application_in import ApplicationIn -from whsaas.openapi_client.model.application_out import ApplicationOut -from whsaas.openapi_client.model.http_validation_error import HTTPValidationError -from whsaas.openapi_client.model.http_error_out import HttpErrorOut -from whsaas.openapi_client.model.list_response_application_out import ListResponseApplicationOut + # Defining the host is optional and defaults to http://localhost # See configuration.py for a list of all supported configuration parameters. -configuration = whsaas.openapi_client.Configuration( - host = "http://localhost:8040" -) +configuration = whsaas.openapi_client.Configuration(host="http://localhost:8040") # The client must configure the authentication and authorization parameters # in accordance with the API server security policy. @@ -19,7 +12,7 @@ # satisfies your auth use case. # Configure API key authorization: APIKeyHeader -configuration.api_key['APIKeyHeader'] = 'qqqqqqqq' +configuration.api_key["APIKeyHeader"] = "qqqqqqqq" # Uncomment below to setup prefix (e.g. Bearer) for API key, if needed # configuration.api_key_prefix['APIKeyHeader'] = 'Bearer' @@ -35,4 +28,7 @@ api_response = api_instance.list_applications_api_v1_app_get() pprint(api_response) except whsaas.openapi_client.ApiException as e: - print("Exception when calling ApplicationApi->create_application_api_v1_app_post: %s\n" % e) + print( + "Exception when calling ApplicationApi->create_application_api_v1_app_post: %s\n" + % e + ) diff --git a/python/setup.py b/python/setup.py index a6ad98cf4..5fca410ed 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,10 +1,10 @@ """ - Svix +Svix - The Svix server API documentation # noqa: E501 +The Svix server API documentation # noqa: E501 - The version of the OpenAPI document: 0.8.1 - Generated by: https://openapi-generator.tech +The version of the OpenAPI document: 0.8.1 +Generated by: https://openapi-generator.tech """ import os diff --git a/python/svix/api.py b/python/svix/api.py index cb690a5ae..cca45c8fd 100644 --- a/python/svix/api.py +++ b/python/svix/api.py @@ -4,7 +4,9 @@ from deprecated import deprecated -from svix.internal.openapi_client.models.aggregate_event_types_out import AggregateEventTypesOut +from svix.internal.openapi_client.models.aggregate_event_types_out import ( + AggregateEventTypesOut, +) from svix.internal.openapi_client.models.app_usage_stats_in import AppUsageStatsIn from svix.internal.openapi_client.models.app_usage_stats_out import AppUsageStatsOut @@ -21,7 +23,10 @@ v1_authentication_dashboard_access, v1_authentication_logout, ) -from .internal.openapi_client.api.background_tasks import get_background_task, list_background_tasks +from .internal.openapi_client.api.background_tasks import ( + get_background_task, + list_background_tasks, +) from .internal.openapi_client.api.endpoint import ( v1_endpoint_create, v1_endpoint_delete, @@ -91,20 +96,34 @@ from .internal.openapi_client.models.dashboard_access_out import DashboardAccessOut from .internal.openapi_client.models.endpoint_headers_in import EndpointHeadersIn from .internal.openapi_client.models.endpoint_headers_out import EndpointHeadersOut -from .internal.openapi_client.models.endpoint_headers_patch_in import EndpointHeadersPatchIn +from .internal.openapi_client.models.endpoint_headers_patch_in import ( + EndpointHeadersPatchIn, +) from .internal.openapi_client.models.endpoint_in import EndpointIn -from .internal.openapi_client.models.endpoint_message_out_payload import EndpointMessageOutPayload +from .internal.openapi_client.models.endpoint_message_out_payload import ( + EndpointMessageOutPayload, +) from .internal.openapi_client.models.endpoint_out import EndpointOut from .internal.openapi_client.models.endpoint_patch import EndpointPatch from .internal.openapi_client.models.endpoint_secret_out import EndpointSecretOut -from .internal.openapi_client.models.endpoint_secret_rotate_in import EndpointSecretRotateIn +from .internal.openapi_client.models.endpoint_secret_rotate_in import ( + EndpointSecretRotateIn, +) from .internal.openapi_client.models.endpoint_stats import EndpointStats -from .internal.openapi_client.models.endpoint_transformation_in import EndpointTransformationIn -from .internal.openapi_client.models.endpoint_transformation_out import EndpointTransformationOut +from .internal.openapi_client.models.endpoint_transformation_in import ( + EndpointTransformationIn, +) +from .internal.openapi_client.models.endpoint_transformation_out import ( + EndpointTransformationOut, +) from .internal.openapi_client.models.endpoint_update import EndpointUpdate from .internal.openapi_client.models.event_example_in import EventExampleIn -from .internal.openapi_client.models.event_type_import_open_api_in import EventTypeImportOpenApiIn -from .internal.openapi_client.models.event_type_import_open_api_out import EventTypeImportOpenApiOut +from .internal.openapi_client.models.event_type_import_open_api_in import ( + EventTypeImportOpenApiIn, +) +from .internal.openapi_client.models.event_type_import_open_api_out import ( + EventTypeImportOpenApiOut, +) from .internal.openapi_client.models.event_type_in import EventTypeIn from .internal.openapi_client.models.event_type_out import EventTypeOut from .internal.openapi_client.models.event_type_patch import EventTypePatch @@ -113,18 +132,36 @@ from .internal.openapi_client.models.integration_key_out import IntegrationKeyOut from .internal.openapi_client.models.integration_out import IntegrationOut from .internal.openapi_client.models.integration_update import IntegrationUpdate -from .internal.openapi_client.models.list_response_application_out import ListResponseApplicationOut -from .internal.openapi_client.models.list_response_background_task_out import ListResponseBackgroundTaskOut -from .internal.openapi_client.models.list_response_endpoint_message_out import ListResponseEndpointMessageOut -from .internal.openapi_client.models.list_response_endpoint_out import ListResponseEndpointOut -from .internal.openapi_client.models.list_response_event_type_out import ListResponseEventTypeOut -from .internal.openapi_client.models.list_response_integration_out import ListResponseIntegrationOut +from .internal.openapi_client.models.list_response_application_out import ( + ListResponseApplicationOut, +) +from .internal.openapi_client.models.list_response_background_task_out import ( + ListResponseBackgroundTaskOut, +) +from .internal.openapi_client.models.list_response_endpoint_message_out import ( + ListResponseEndpointMessageOut, +) +from .internal.openapi_client.models.list_response_endpoint_out import ( + ListResponseEndpointOut, +) +from .internal.openapi_client.models.list_response_event_type_out import ( + ListResponseEventTypeOut, +) +from .internal.openapi_client.models.list_response_integration_out import ( + ListResponseIntegrationOut, +) from .internal.openapi_client.models.list_response_message_attempt_endpoint_out import ( ListResponseMessageAttemptEndpointOut, ) -from .internal.openapi_client.models.list_response_message_attempt_out import ListResponseMessageAttemptOut -from .internal.openapi_client.models.list_response_message_endpoint_out import ListResponseMessageEndpointOut -from .internal.openapi_client.models.list_response_message_out import ListResponseMessageOut +from .internal.openapi_client.models.list_response_message_attempt_out import ( + ListResponseMessageAttemptOut, +) +from .internal.openapi_client.models.list_response_message_endpoint_out import ( + ListResponseMessageEndpointOut, +) +from .internal.openapi_client.models.list_response_message_out import ( + ListResponseMessageOut, +) from .internal.openapi_client.models.message_attempt_out import MessageAttemptOut from .internal.openapi_client.models.message_in import MessageIn from .internal.openapi_client.models.message_in_payload import MessageInPayload @@ -242,101 +279,163 @@ def __init__(self, client: AuthenticatedClient) -> None: class AuthenticationAsync(ApiBase): async def app_portal_access( - self, app_id: str, app_portal_access_in: AppPortalAccessIn, options: PostOptions = PostOptions() + self, + app_id: str, + app_portal_access_in: AppPortalAccessIn, + options: PostOptions = PostOptions(), ) -> AppPortalAccessOut: return await v1_authentication_app_portal_access.request_asyncio( - client=self._client, app_id=app_id, json_body=app_portal_access_in, **options.to_dict() + client=self._client, + app_id=app_id, + json_body=app_portal_access_in, + **options.to_dict(), ) - async def dashboard_access(self, app_id: str, options: PostOptions = PostOptions()) -> DashboardAccessOut: + async def dashboard_access( + self, app_id: str, options: PostOptions = PostOptions() + ) -> DashboardAccessOut: return await v1_authentication_dashboard_access.request_asyncio( client=self._client, app_id=app_id, **options.to_dict() ) async def logout(self, options: PostOptions = PostOptions()) -> None: - return await v1_authentication_logout.request_asyncio(client=self._client, **options.to_dict()) + return await v1_authentication_logout.request_asyncio( + client=self._client, **options.to_dict() + ) class Authentication(ApiBase): def app_portal_access( - self, app_id: str, app_portal_access_in: AppPortalAccessIn, options: PostOptions = PostOptions() + self, + app_id: str, + app_portal_access_in: AppPortalAccessIn, + options: PostOptions = PostOptions(), ) -> AppPortalAccessOut: return v1_authentication_app_portal_access.request_sync( - client=self._client, app_id=app_id, json_body=app_portal_access_in, **options.to_dict() + client=self._client, + app_id=app_id, + json_body=app_portal_access_in, + **options.to_dict(), ) - def dashboard_access(self, app_id: str, options: PostOptions = PostOptions()) -> DashboardAccessOut: - return v1_authentication_dashboard_access.request_sync(client=self._client, app_id=app_id, **options.to_dict()) + def dashboard_access( + self, app_id: str, options: PostOptions = PostOptions() + ) -> DashboardAccessOut: + return v1_authentication_dashboard_access.request_sync( + client=self._client, app_id=app_id, **options.to_dict() + ) def logout(self, options: PostOptions = PostOptions()) -> None: - return v1_authentication_logout.request_sync(client=self._client, **options.to_dict()) + return v1_authentication_logout.request_sync( + client=self._client, **options.to_dict() + ) class ApplicationAsync(ApiBase): - async def list(self, options: ApplicationListOptions = ApplicationListOptions()) -> ListResponseApplicationOut: - return await v1_application_list.request_asyncio(client=self._client, **options.to_dict()) + async def list( + self, options: ApplicationListOptions = ApplicationListOptions() + ) -> ListResponseApplicationOut: + return await v1_application_list.request_asyncio( + client=self._client, **options.to_dict() + ) - async def create(self, application_in: ApplicationIn, options: PostOptions = PostOptions()) -> ApplicationOut: + async def create( + self, application_in: ApplicationIn, options: PostOptions = PostOptions() + ) -> ApplicationOut: return await v1_application_create.request_asyncio( client=self._client, json_body=application_in, **options.to_dict() ) async def get(self, app_id: str) -> ApplicationOut: - return await v1_application_get.request_asyncio(client=self._client, app_id=app_id) + return await v1_application_get.request_asyncio( + client=self._client, app_id=app_id + ) async def get_or_create( self, application_in: ApplicationIn, options: PostOptions = PostOptions() ) -> ApplicationOut: return await v1_application_create.request_asyncio( - client=self._client, json_body=application_in, get_if_exists=True, **options.to_dict() + client=self._client, + json_body=application_in, + get_if_exists=True, + **options.to_dict(), ) - async def update(self, app_id: str, application_in: ApplicationIn) -> ApplicationOut: - return await v1_application_update.request_asyncio(client=self._client, app_id=app_id, json_body=application_in) + async def update( + self, app_id: str, application_in: ApplicationIn + ) -> ApplicationOut: + return await v1_application_update.request_asyncio( + client=self._client, app_id=app_id, json_body=application_in + ) - async def patch(self, app_id: str, application_patch: ApplicationPatch) -> ApplicationOut: + async def patch( + self, app_id: str, application_patch: ApplicationPatch + ) -> ApplicationOut: return await v1_application_patch.request_asyncio( client=self._client, app_id=app_id, json_body=application_patch ) async def delete(self, app_id: str) -> None: - return await v1_application_delete.request_asyncio(client=self._client, app_id=app_id) + return await v1_application_delete.request_asyncio( + client=self._client, app_id=app_id + ) class Application(ApiBase): - def list(self, options: ApplicationListOptions = ApplicationListOptions()) -> ListResponseApplicationOut: - return v1_application_list.request_sync(client=self._client, **options.to_dict()) + def list( + self, options: ApplicationListOptions = ApplicationListOptions() + ) -> ListResponseApplicationOut: + return v1_application_list.request_sync( + client=self._client, **options.to_dict() + ) - def create(self, application_in: ApplicationIn, options: PostOptions = PostOptions()) -> ApplicationOut: - return v1_application_create.request_sync(client=self._client, json_body=application_in, **options.to_dict()) + def create( + self, application_in: ApplicationIn, options: PostOptions = PostOptions() + ) -> ApplicationOut: + return v1_application_create.request_sync( + client=self._client, json_body=application_in, **options.to_dict() + ) def get(self, app_id: str) -> ApplicationOut: return v1_application_get.request_sync(client=self._client, app_id=app_id) - def get_or_create(self, application_in: ApplicationIn, options: PostOptions = PostOptions()) -> ApplicationOut: + def get_or_create( + self, application_in: ApplicationIn, options: PostOptions = PostOptions() + ) -> ApplicationOut: return v1_application_create.request_sync( - client=self._client, json_body=application_in, get_if_exists=True, **options.to_dict() + client=self._client, + json_body=application_in, + get_if_exists=True, + **options.to_dict(), ) def update(self, app_id: str, application_in: ApplicationIn) -> ApplicationOut: - return v1_application_update.request_sync(client=self._client, app_id=app_id, json_body=application_in) + return v1_application_update.request_sync( + client=self._client, app_id=app_id, json_body=application_in + ) def patch(self, app_id: str, application_patch: ApplicationPatch) -> ApplicationOut: - return v1_application_patch.request_sync(client=self._client, app_id=app_id, json_body=application_patch) + return v1_application_patch.request_sync( + client=self._client, app_id=app_id, json_body=application_patch + ) def delete(self, app_id: str) -> None: return v1_application_delete.request_sync(client=self._client, app_id=app_id) class EndpointAsync(ApiBase): - async def list(self, app_id: str, options: EndpointListOptions = EndpointListOptions()) -> ListResponseEndpointOut: + async def list( + self, app_id: str, options: EndpointListOptions = EndpointListOptions() + ) -> ListResponseEndpointOut: return await v1_endpoint_list.request_asyncio( client=self._client, app_id=app_id, **options.to_dict(), ) - async def create(self, app_id: str, endpoint_in: EndpointIn, options: PostOptions = PostOptions()) -> EndpointOut: + async def create( + self, app_id: str, endpoint_in: EndpointIn, options: PostOptions = PostOptions() + ) -> EndpointOut: return await v1_endpoint_create.request_asyncio( client=self._client, app_id=app_id, @@ -345,9 +444,13 @@ async def create(self, app_id: str, endpoint_in: EndpointIn, options: PostOption ) async def get(self, app_id: str, endpoint_id: str) -> EndpointOut: - return await v1_endpoint_get.request_asyncio(client=self._client, app_id=app_id, endpoint_id=endpoint_id) + return await v1_endpoint_get.request_asyncio( + client=self._client, app_id=app_id, endpoint_id=endpoint_id + ) - async def update(self, app_id: str, endpoint_id: str, endpoint_update: EndpointUpdate) -> EndpointOut: + async def update( + self, app_id: str, endpoint_id: str, endpoint_update: EndpointUpdate + ) -> EndpointOut: return await v1_endpoint_update.request_asyncio( client=self._client, app_id=app_id, @@ -355,7 +458,9 @@ async def update(self, app_id: str, endpoint_id: str, endpoint_update: EndpointU json_body=endpoint_update, ) - async def patch(self, app_id: str, endpoint_id: str, endpoint_patch: EndpointPatch) -> EndpointOut: + async def patch( + self, app_id: str, endpoint_id: str, endpoint_patch: EndpointPatch + ) -> EndpointOut: return await v1_endpoint_patch.request_asyncio( client=self._client, app_id=app_id, @@ -393,7 +498,11 @@ async def rotate_secret( ) async def recover( - self, app_id: str, endpoint_id: str, recover_in: RecoverIn, options: PostOptions = PostOptions() + self, + app_id: str, + endpoint_id: str, + recover_in: RecoverIn, + options: PostOptions = PostOptions(), ) -> RecoverOut: return await v1_endpoint_recover.request_asyncio( client=self._client, @@ -410,7 +519,9 @@ async def get_headers(self, app_id: str, endpoint_id: str) -> EndpointHeadersOut endpoint_id=endpoint_id, ) - async def update_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersIn) -> None: + async def update_headers( + self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersIn + ) -> None: return await v1_endpoint_update_headers.request_asyncio( client=self._client, app_id=app_id, @@ -418,7 +529,9 @@ async def update_headers(self, app_id: str, endpoint_id: str, endpoint_headers_i json_body=endpoint_headers_in, ) - async def patch_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersPatchIn) -> None: + async def patch_headers( + self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersPatchIn + ) -> None: return await v1_endpoint_patch_headers.request_asyncio( client=self._client, app_id=app_id, @@ -427,19 +540,32 @@ async def patch_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in ) async def replay_missing( - self, app_id: str, endpoint_id: str, replay_in: ReplayIn, options: PostOptions = PostOptions() + self, + app_id: str, + endpoint_id: str, + replay_in: ReplayIn, + options: PostOptions = PostOptions(), ) -> ReplayOut: return await v1_endpoint_replay.request_asyncio( - client=self._client, app_id=app_id, endpoint_id=endpoint_id, json_body=replay_in, **options.to_dict() + client=self._client, + app_id=app_id, + endpoint_id=endpoint_id, + json_body=replay_in, + **options.to_dict(), ) - async def transformations_get(self, app_id: str, endpoint_id: str) -> EndpointTransformationOut: + async def transformations_get( + self, app_id: str, endpoint_id: str + ) -> EndpointTransformationOut: return await v1_endpoint_transformation_get.request_asyncio( client=self._client, app_id=app_id, endpoint_id=endpoint_id ) async def transformation_partial_update( - self, app_id: str, endpoint_id: str, endpoint_transformation_in: EndpointTransformationIn + self, + app_id: str, + endpoint_id: str, + endpoint_transformation_in: EndpointTransformationIn, ) -> None: await v1_endpoint_transformation_partial_update.request_asyncio( client=self._client, @@ -449,7 +575,11 @@ async def transformation_partial_update( ) async def send_example( - self, app_id: str, endpoint_id: str, event_example_in: EventExampleIn, options: PostOptions = PostOptions() + self, + app_id: str, + endpoint_id: str, + event_example_in: EventExampleIn, + options: PostOptions = PostOptions(), ) -> MessageOut: return await v1_endpoint_send_example.request_asyncio( client=self._client, @@ -461,14 +591,18 @@ async def send_example( class Endpoint(ApiBase): - def list(self, app_id: str, options: EndpointListOptions = EndpointListOptions()) -> ListResponseEndpointOut: + def list( + self, app_id: str, options: EndpointListOptions = EndpointListOptions() + ) -> ListResponseEndpointOut: return v1_endpoint_list.request_sync( client=self._client, app_id=app_id, **options.to_dict(), ) - def create(self, app_id: str, endpoint_in: EndpointIn, options: PostOptions = PostOptions()) -> EndpointOut: + def create( + self, app_id: str, endpoint_in: EndpointIn, options: PostOptions = PostOptions() + ) -> EndpointOut: return v1_endpoint_create.request_sync( client=self._client, app_id=app_id, @@ -477,9 +611,13 @@ def create(self, app_id: str, endpoint_in: EndpointIn, options: PostOptions = Po ) def get(self, app_id: str, endpoint_id: str) -> EndpointOut: - return v1_endpoint_get.request_sync(client=self._client, app_id=app_id, endpoint_id=endpoint_id) + return v1_endpoint_get.request_sync( + client=self._client, app_id=app_id, endpoint_id=endpoint_id + ) - def update(self, app_id: str, endpoint_id: str, endpoint_update: EndpointUpdate) -> EndpointOut: + def update( + self, app_id: str, endpoint_id: str, endpoint_update: EndpointUpdate + ) -> EndpointOut: return v1_endpoint_update.request_sync( client=self._client, app_id=app_id, @@ -487,7 +625,9 @@ def update(self, app_id: str, endpoint_id: str, endpoint_update: EndpointUpdate) json_body=endpoint_update, ) - def patch(self, app_id: str, endpoint_id: str, endpoint_patch: EndpointPatch) -> EndpointOut: + def patch( + self, app_id: str, endpoint_id: str, endpoint_patch: EndpointPatch + ) -> EndpointOut: return v1_endpoint_patch.request_sync( client=self._client, app_id=app_id, @@ -525,7 +665,11 @@ def rotate_secret( ) def recover( - self, app_id: str, endpoint_id: str, recover_in: RecoverIn, options: PostOptions = PostOptions() + self, + app_id: str, + endpoint_id: str, + recover_in: RecoverIn, + options: PostOptions = PostOptions(), ) -> RecoverOut: return v1_endpoint_recover.request_sync( client=self._client, @@ -542,7 +686,9 @@ def get_headers(self, app_id: str, endpoint_id: str) -> EndpointHeadersOut: endpoint_id=endpoint_id, ) - def update_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersIn) -> None: + def update_headers( + self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersIn + ) -> None: return v1_endpoint_update_headers.request_sync( client=self._client, app_id=app_id, @@ -550,7 +696,9 @@ def update_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in: End json_body=endpoint_headers_in, ) - def patch_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersPatchIn) -> None: + def patch_headers( + self, app_id: str, endpoint_id: str, endpoint_headers_in: EndpointHeadersPatchIn + ) -> None: return v1_endpoint_patch_headers.request_sync( client=self._client, app_id=app_id, @@ -559,7 +707,10 @@ def patch_headers(self, app_id: str, endpoint_id: str, endpoint_headers_in: Endp ) def get_stats( - self, app_id: str, endpoint_id: str, options: EndpointStatsOptions = EndpointStatsOptions() + self, + app_id: str, + endpoint_id: str, + options: EndpointStatsOptions = EndpointStatsOptions(), ) -> EndpointStats: return v1_endpoint_get_stats.request_sync( client=self._client, @@ -570,17 +721,32 @@ def get_stats( ) def replay_missing( - self, app_id: str, endpoint_id: str, replay_in: ReplayIn, options: PostOptions = PostOptions() + self, + app_id: str, + endpoint_id: str, + replay_in: ReplayIn, + options: PostOptions = PostOptions(), ) -> ReplayOut: return v1_endpoint_replay.request_sync( - client=self._client, app_id=app_id, endpoint_id=endpoint_id, json_body=replay_in, **options.to_dict() + client=self._client, + app_id=app_id, + endpoint_id=endpoint_id, + json_body=replay_in, + **options.to_dict(), ) - def transformations_get(self, app_id: str, endpoint_id: str) -> EndpointTransformationOut: - return v1_endpoint_transformation_get.request_sync(client=self._client, app_id=app_id, endpoint_id=endpoint_id) + def transformations_get( + self, app_id: str, endpoint_id: str + ) -> EndpointTransformationOut: + return v1_endpoint_transformation_get.request_sync( + client=self._client, app_id=app_id, endpoint_id=endpoint_id + ) def transformation_partial_update( - self, app_id: str, endpoint_id: str, endpoint_transformation_in: EndpointTransformationIn + self, + app_id: str, + endpoint_id: str, + endpoint_transformation_in: EndpointTransformationIn, ) -> None: v1_endpoint_transformation_partial_update.request_sync( client=self._client, @@ -590,7 +756,11 @@ def transformation_partial_update( ) def send_example( - self, app_id: str, endpoint_id: str, event_example_in: EventExampleIn, options: PostOptions = PostOptions() + self, + app_id: str, + endpoint_id: str, + event_example_in: EventExampleIn, + options: PostOptions = PostOptions(), ) -> MessageOut: return v1_endpoint_send_example.request_sync( client=self._client, @@ -602,13 +772,17 @@ def send_example( class EventTypeAsync(ApiBase): - async def list(self, options: EventTypeListOptions = EventTypeListOptions()) -> ListResponseEventTypeOut: + async def list( + self, options: EventTypeListOptions = EventTypeListOptions() + ) -> ListResponseEventTypeOut: return await v1_event_type_list.request_asyncio( client=self._client, **options.to_dict(), ) - async def create(self, event_type_in: EventTypeIn, options: PostOptions = PostOptions()) -> EventTypeOut: + async def create( + self, event_type_in: EventTypeIn, options: PostOptions = PostOptions() + ) -> EventTypeOut: return await v1_event_type_create.request_asyncio( client=self._client, json_body=event_type_in, @@ -621,14 +795,18 @@ async def get(self, event_type_name: str) -> EventTypeOut: event_type_name=event_type_name, ) - async def update(self, event_type_name: str, event_type_update: EventTypeUpdate) -> EventTypeOut: + async def update( + self, event_type_name: str, event_type_update: EventTypeUpdate + ) -> EventTypeOut: return await v1_event_type_update.request_asyncio( client=self._client, event_type_name=event_type_name, json_body=event_type_update, ) - async def patch(self, event_type_name: str, event_type_patch: EventTypePatch) -> EventTypeOut: + async def patch( + self, event_type_name: str, event_type_patch: EventTypePatch + ) -> EventTypeOut: return await v1_event_type_patch.request_asyncio( client=self._client, event_type_name=event_type_name, @@ -642,7 +820,9 @@ async def delete(self, event_type_name: str) -> None: ) async def import_openapi( - self, event_type_import_openapi_in: EventTypeImportOpenApiIn, options: PostOptions = PostOptions() + self, + event_type_import_openapi_in: EventTypeImportOpenApiIn, + options: PostOptions = PostOptions(), ) -> EventTypeImportOpenApiOut: return await v1_event_type_import_openapi.request_asyncio( client=self._client, @@ -652,13 +832,17 @@ async def import_openapi( class EventType(ApiBase): - def list(self, options: EventTypeListOptions = EventTypeListOptions()) -> ListResponseEventTypeOut: + def list( + self, options: EventTypeListOptions = EventTypeListOptions() + ) -> ListResponseEventTypeOut: return v1_event_type_list.request_sync( client=self._client, **options.to_dict(), ) - def create(self, event_type_in: EventTypeIn, options: PostOptions = PostOptions()) -> EventTypeOut: + def create( + self, event_type_in: EventTypeIn, options: PostOptions = PostOptions() + ) -> EventTypeOut: return v1_event_type_create.request_sync( client=self._client, json_body=event_type_in, @@ -671,14 +855,18 @@ def get(self, event_type_name: str) -> EventTypeOut: event_type_name=event_type_name, ) - def update(self, event_type_name: str, event_type_update: EventTypeUpdate) -> EventTypeOut: + def update( + self, event_type_name: str, event_type_update: EventTypeUpdate + ) -> EventTypeOut: return v1_event_type_update.request_sync( client=self._client, event_type_name=event_type_name, json_body=event_type_update, ) - def patch(self, event_type_name: str, event_type_patch: EventTypePatch) -> EventTypeOut: + def patch( + self, event_type_name: str, event_type_patch: EventTypePatch + ) -> EventTypeOut: return v1_event_type_patch.request_sync( client=self._client, event_type_name=event_type_name, @@ -692,7 +880,9 @@ def delete(self, event_type_name: str) -> None: ) def import_openapi( - self, event_type_import_openapi_in: EventTypeImportOpenApiIn, options: PostOptions = PostOptions() + self, + event_type_import_openapi_in: EventTypeImportOpenApiIn, + options: PostOptions = PostOptions(), ) -> EventTypeImportOpenApiOut: return v1_event_type_import_openapi.request_sync( client=self._client, @@ -728,7 +918,9 @@ async def get(self, app_id: str, integ_id: str) -> IntegrationOut: integ_id=integ_id, ) - async def update(self, app_id: str, integ_id: str, integ_update: IntegrationUpdate) -> IntegrationOut: + async def update( + self, app_id: str, integ_id: str, integ_update: IntegrationUpdate + ) -> IntegrationOut: return await v1_integration_update.request_asyncio( client=self._client, app_id=app_id, @@ -750,7 +942,9 @@ async def get_key(self, app_id: str, integ_id: str) -> IntegrationKeyOut: integ_id=integ_id, ) - async def rotate_key(self, app_id: str, integ_id: str, options: PostOptions = PostOptions()) -> IntegrationKeyOut: + async def rotate_key( + self, app_id: str, integ_id: str, options: PostOptions = PostOptions() + ) -> IntegrationKeyOut: return await v1_integration_rotate_key.request_asyncio( client=self._client, app_id=app_id, @@ -769,7 +963,9 @@ def list( **options.to_dict(), ) - def create(self, app_id: str, integ_in: IntegrationIn, options: PostOptions = PostOptions()) -> IntegrationOut: + def create( + self, app_id: str, integ_in: IntegrationIn, options: PostOptions = PostOptions() + ) -> IntegrationOut: return v1_integration_create.request_sync( client=self._client, app_id=app_id, @@ -784,7 +980,9 @@ def get(self, app_id: str, integ_id: str) -> IntegrationOut: integ_id=integ_id, ) - def update(self, app_id: str, integ_id: str, integ_update: IntegrationUpdate) -> IntegrationOut: + def update( + self, app_id: str, integ_id: str, integ_update: IntegrationUpdate + ) -> IntegrationOut: return v1_integration_update.request_sync( client=self._client, app_id=app_id, @@ -806,7 +1004,9 @@ def get_key(self, app_id: str, integ_id: str) -> IntegrationKeyOut: integ_id=integ_id, ) - def rotate_key(self, app_id: str, integ_id: str, options: PostOptions = PostOptions()) -> IntegrationKeyOut: + def rotate_key( + self, app_id: str, integ_id: str, options: PostOptions = PostOptions() + ) -> IntegrationKeyOut: return v1_integration_rotate_key.request_sync( client=self._client, app_id=app_id, @@ -816,14 +1016,18 @@ def rotate_key(self, app_id: str, integ_id: str, options: PostOptions = PostOpti class MessageAsync(ApiBase): - async def list(self, app_id: str, options: MessageListOptions = MessageListOptions()) -> ListResponseMessageOut: + async def list( + self, app_id: str, options: MessageListOptions = MessageListOptions() + ) -> ListResponseMessageOut: return await v1_message_list.request_asyncio( client=self._client, app_id=app_id, **options.to_dict(), ) - async def create(self, app_id: str, message_in: MessageIn, options: PostOptions = PostOptions()) -> MessageOut: + async def create( + self, app_id: str, message_in: MessageIn, options: PostOptions = PostOptions() + ) -> MessageOut: ret = await v1_message_create.request_asyncio( client=self._client, app_id=app_id, @@ -850,14 +1054,18 @@ async def expunge_content(self, app_id: str, msg_id: str) -> None: class Message(ApiBase): - def list(self, app_id: str, options: MessageListOptions = MessageListOptions()) -> ListResponseMessageOut: + def list( + self, app_id: str, options: MessageListOptions = MessageListOptions() + ) -> ListResponseMessageOut: return v1_message_list.request_sync( client=self._client, app_id=app_id, **options.to_dict(), ) - def create(self, app_id: str, message_in: MessageIn, options: PostOptions = PostOptions()) -> MessageOut: + def create( + self, app_id: str, message_in: MessageIn, options: PostOptions = PostOptions() + ) -> MessageOut: ret = v1_message_create.request_sync( client=self._client, app_id=app_id, @@ -885,17 +1093,26 @@ def expunge_content(self, app_id: str, msg_id: str) -> None: class MessageAttemptAsync(ApiBase): async def list_by_msg( - self, app_id: str, msg_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + msg_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageAttemptOut: return await v1_message_attempt_list_by_msg.request_asyncio( client=self._client, app_id=app_id, msg_id=msg_id, **options.to_dict() ) async def list_by_endpoint( - self, app_id: str, endpoint_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + endpoint_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageAttemptOut: return await v1_message_attempt_list_by_endpoint.request_asyncio( - client=self._client, app_id=app_id, endpoint_id=endpoint_id, **options.to_dict() + client=self._client, + app_id=app_id, + endpoint_id=endpoint_id, + **options.to_dict(), ) async def get(self, app_id: str, msg_id: str, attempt_id: str) -> MessageAttemptOut: @@ -906,7 +1123,13 @@ async def get(self, app_id: str, msg_id: str, attempt_id: str) -> MessageAttempt attempt_id=attempt_id, ) - async def resend(self, app_id: str, msg_id: str, endpoint_id: str, options: PostOptions = PostOptions()) -> None: + async def resend( + self, + app_id: str, + msg_id: str, + endpoint_id: str, + options: PostOptions = PostOptions(), + ) -> None: return await v1_message_attempt_resend.request_asyncio( client=self._client, app_id=app_id, @@ -916,7 +1139,10 @@ async def resend(self, app_id: str, msg_id: str, endpoint_id: str, options: Post ) async def list_attempted_messages( - self, app_id: str, endpoint_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + endpoint_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseEndpointMessageOut: return await v1_message_attempt_list_attempted_messages.request_asyncio( client=self._client, @@ -926,7 +1152,10 @@ async def list_attempted_messages( ) async def list_attempted_destinations( - self, app_id: str, msg_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + msg_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageEndpointOut: return await v1_message_attempt_list_attempted_destinations.request_asyncio( client=self._client, @@ -967,22 +1196,34 @@ async def expunge_content( class MessageAttempt(ApiBase): @deprecated(reason="use list_by_msg or list_by_endpoint instead") def list( - self, app_id: str, msg_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + msg_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageAttemptOut: return self.list_by_msg(app_id=app_id, msg_id=msg_id, options=options) def list_by_msg( - self, app_id: str, msg_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + msg_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageAttemptOut: return v1_message_attempt_list_by_msg.request_sync( client=self._client, app_id=app_id, msg_id=msg_id, **options.to_dict() ) def list_by_endpoint( - self, app_id: str, endpoint_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + endpoint_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageAttemptOut: return v1_message_attempt_list_by_endpoint.request_sync( - client=self._client, app_id=app_id, endpoint_id=endpoint_id, **options.to_dict() + client=self._client, + app_id=app_id, + endpoint_id=endpoint_id, + **options.to_dict(), ) def get(self, app_id: str, msg_id: str, attempt_id: str) -> MessageAttemptOut: @@ -993,7 +1234,13 @@ def get(self, app_id: str, msg_id: str, attempt_id: str) -> MessageAttemptOut: attempt_id=attempt_id, ) - def resend(self, app_id: str, msg_id: str, endpoint_id: str, options: PostOptions = PostOptions()) -> None: + def resend( + self, + app_id: str, + msg_id: str, + endpoint_id: str, + options: PostOptions = PostOptions(), + ) -> None: return v1_message_attempt_resend.request_sync( client=self._client, app_id=app_id, @@ -1003,7 +1250,10 @@ def resend(self, app_id: str, msg_id: str, endpoint_id: str, options: PostOption ) def list_attempted_messages( - self, app_id: str, endpoint_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + endpoint_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseEndpointMessageOut: return v1_message_attempt_list_attempted_messages.request_sync( client=self._client, @@ -1013,7 +1263,10 @@ def list_attempted_messages( ) def list_attempted_destinations( - self, app_id: str, msg_id: str, options: MessageAttemptListOptions = MessageAttemptListOptions() + self, + app_id: str, + msg_id: str, + options: MessageAttemptListOptions = MessageAttemptListOptions(), ) -> ListResponseMessageEndpointOut: return v1_message_attempt_list_attempted_destinations.request_sync( client=self._client, @@ -1055,15 +1308,23 @@ class BackgroundTaskAsync(ApiBase): async def list( self, options: BackgroundTaskListOptions = BackgroundTaskListOptions() ) -> ListResponseBackgroundTaskOut: - return await list_background_tasks.request_asyncio(client=self._client, **options.to_dict()) + return await list_background_tasks.request_asyncio( + client=self._client, **options.to_dict() + ) async def get(self, task_id: str) -> BackgroundTaskOut: - return await get_background_task.request_asyncio(client=self._client, task_id=task_id) + return await get_background_task.request_asyncio( + client=self._client, task_id=task_id + ) class BackgroundTask(ApiBase): - def list(self, options: BackgroundTaskListOptions = BackgroundTaskListOptions()) -> ListResponseBackgroundTaskOut: - return list_background_tasks.request_sync(client=self._client, **options.to_dict()) + def list( + self, options: BackgroundTaskListOptions = BackgroundTaskListOptions() + ) -> ListResponseBackgroundTaskOut: + return list_background_tasks.request_sync( + client=self._client, **options.to_dict() + ) def get(self, task_id: str) -> BackgroundTaskOut: return get_background_task.request_sync(client=self._client, task_id=task_id) @@ -1080,7 +1341,9 @@ async def aggregate_app_stats( ) async def aggregate_event_types(self, task_id: str) -> AggregateEventTypesOut: - return await v1_statistics_aggregate_event_types.request_asyncio(client=self._client) + return await v1_statistics_aggregate_event_types.request_asyncio( + client=self._client + ) class Statistics(ApiBase): diff --git a/python/svix/webhooks.py b/python/svix/webhooks.py index 410f6cba0..62feb3597 100644 --- a/python/svix/webhooks.py +++ b/python/svix/webhooks.py @@ -46,7 +46,9 @@ def verify(self, data: t.Union[bytes, str], headers: t.Dict[str, str]) -> t.Any: timestamp = self.__verify_timestamp(msg_timestamp) - expected_sig = base64.b64decode(self.sign(msg_id=msg_id, timestamp=timestamp, data=data).split(",")[1]) + expected_sig = base64.b64decode( + self.sign(msg_id=msg_id, timestamp=timestamp, data=data).split(",")[1] + ) passed_sigs = msg_signature.split(" ") for versioned_sig in passed_sigs: (version, signature) = versioned_sig.split(",") diff --git a/python/tests/test_webhooks.py b/python/tests/test_webhooks.py index 8322c612d..450068fbd 100644 --- a/python/tests/test_webhooks.py +++ b/python/tests/test_webhooks.py @@ -1,4 +1,3 @@ -from time import timezone import pytest import base64 import typing as t @@ -7,9 +6,9 @@ from svix.webhooks import hmac_data, Webhook, WebhookVerificationError -defaultMsgID = 'msg_p5jXN8AQM9LWM0D4loKWxJek' +defaultMsgID = "msg_p5jXN8AQM9LWM0D4loKWxJek" defaultPayload = '{"test": 2432232314}' -defaultSecret = 'MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw' +defaultSecret = "MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" tolerance = timedelta(minutes=5) @@ -22,11 +21,13 @@ class PayloadForTesting: signature: str header: t.Dict[str, str] - def __init__(self, timestamp: datetime=datetime.now(tz=timezone.utc)): + def __init__(self, timestamp: datetime = datetime.now(tz=timezone.utc)): ts = str(floor(timestamp.timestamp())) to_sign = f"{defaultMsgID}.{ts}.{defaultPayload}".encode() - signature = base64.b64encode(hmac_data(base64.b64decode(defaultSecret), to_sign)).decode('utf-8') - + signature = base64.b64encode( + hmac_data(base64.b64decode(defaultSecret), to_sign) + ).decode("utf-8") + self.id = defaultMsgID self.timestamp = ts self.payload = defaultPayload @@ -38,96 +39,111 @@ def __init__(self, timestamp: datetime=datetime.now(tz=timezone.utc)): "svix-timestamp": self.timestamp, } + def test_missing_id_raises_error(): testPayload = PayloadForTesting() - del testPayload.header['svix-id'] - + del testPayload.header["svix-id"] + wh = Webhook(testPayload.secret) with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_timestamp_raises_error(): testPayload = PayloadForTesting() - del testPayload.header['svix-timestamp'] + del testPayload.header["svix-timestamp"] wh = Webhook(testPayload.secret) with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_invalid_timestamp_raises_error(): testPayload = PayloadForTesting() - testPayload.header['svix-timestamp'] = 'hello' + testPayload.header["svix-timestamp"] = "hello" wh = Webhook(testPayload.secret) with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_missing_signature_raises_error(): testPayload = PayloadForTesting() - del testPayload.header['svix-signature'] + del testPayload.header["svix-signature"] wh = Webhook(testPayload.secret) with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_invalid_signature_raises_error(): testPayload = PayloadForTesting() - testPayload.header['svix-signature'] = 'v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OA=' + testPayload.header["svix-signature"] = ( + "v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OA=" + ) wh = Webhook(testPayload.secret) with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_valid_signature_is_valid_and_returns_json(): testPayload = PayloadForTesting() wh = Webhook(testPayload.secret) json = wh.verify(testPayload.payload, testPayload.header) - assert json['test'] == 2432232314 + assert json["test"] == 2432232314 + def test_valid_unbranded_signature_is_valid_and_returns_json(): testPayload = PayloadForTesting() unbrandedHeaders = { "webhook-id": testPayload.header.get("svix-id"), "webhook-signature": testPayload.header.get("svix-signature"), - "webhook-timestamp": testPayload.header.get("svix-timestamp") + "webhook-timestamp": testPayload.header.get("svix-timestamp"), } testPayload.header = unbrandedHeaders wh = Webhook(testPayload.secret) json = wh.verify(testPayload.payload, testPayload.header) - assert json['test'] == 2432232314 + assert json["test"] == 2432232314 def test_old_timestamp_fails(): - testPayload = PayloadForTesting(datetime.now(tz=timezone.utc) - tolerance - timedelta(seconds=1)) - + testPayload = PayloadForTesting( + datetime.now(tz=timezone.utc) - tolerance - timedelta(seconds=1) + ) + wh = Webhook(testPayload.secret) with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_new_timestamp_fails(): - testPayload = PayloadForTesting(datetime.now(tz=timezone.utc) + tolerance + timedelta(seconds=1)) + testPayload = PayloadForTesting( + datetime.now(tz=timezone.utc) + tolerance + timedelta(seconds=1) + ) + + wh = Webhook(testPayload.secret) - wh = Webhook(testPayload.secret) - with pytest.raises(WebhookVerificationError): wh.verify(testPayload.payload, testPayload.header) + def test_multi_sig_payload_is_valid(): testPayload = PayloadForTesting() sigs = [ "v1,Ceo5qEr07ixe2NLpvHk3FH9bwy/WavXrAFQ/9tdO6mc=", "v2,Ceo5qEr07ixe2NLpvHk3FH9bwy/WavXrAFQ/9tdO6mc=", - testPayload.header["svix-signature"], # valid signature + testPayload.header["svix-signature"], # valid signature "v1,Ceo5qEr07ixe2NLpvHk3FH9bwy/WavXrAFQ/9tdO6mc=", ] testPayload.header["svix-signature"] = " ".join(sigs) @@ -137,6 +153,7 @@ def test_multi_sig_payload_is_valid(): json = wh.verify(testPayload.payload, testPayload.header) assert json["test"] == 2432232314 + def test_signature_verification_with_and_without_prefix(): testPayload = PayloadForTesting() @@ -149,6 +166,7 @@ def test_signature_verification_with_and_without_prefix(): json = wh.verify(testPayload.payload, testPayload.header) assert json["test"] == 2432232314 + def test_sign_function(): key = "whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw" msg_id = "msg_p5jXN8AQM9LWM0D4loKWxJek"