From c38268a1846f8e7d54453a5c387ee6d67d02286b Mon Sep 17 00:00:00 2001 From: Guillaume Pujol Date: Wed, 29 Jan 2025 10:34:40 +0100 Subject: [PATCH] Initial commit --- .github/ISSUE_TEMPLATE.md | 2 +- .pre-commit-config.yaml | 8 +- AUTHORS.md | 9 - CONTRIBUTING.md | 14 +- HISTORY.md | 41 - README.md | 239 ++--- docs/api.md | 2 +- docs/installation.md | 12 +- docs/usage.md | 4 +- mkdocs.yml | 14 +- .../__init__.py | 26 +- .../api_client.py | 65 +- .../auth.py | 52 +- .../authorization_request.py | 13 +- .../backchannel_authentication.py | 2 +- .../client.py | 143 +-- .../client_authentication.py | 50 +- .../device_authorization.py | 6 +- .../discovery.py | 0 .../dpop.py | 26 +- .../exceptions.py | 14 +- .../flask/__init__.py | 0 .../flask/auth.py | 4 +- .../pooling.py | 14 +- .../py.typed | 0 .../tokens.py | 12 +- .../utils.py | 5 +- .../vendor_specific/__init__.py | 2 +- .../vendor_specific/auth0.py | 28 +- .../vendor_specific/ping.py | 8 +- poetry.lock | 962 +++++++++++++----- pyproject.toml | 23 +- tests/.coveragerc | 2 +- tests/conftest.py | 147 ++- tests/test_authorization_code.py | 40 +- tests/test_client_credentials.py | 26 +- tests/test_device_authorization.py | 30 +- tests/test_oidc.py | 8 +- tests/test_refresh_token.py | 22 +- tests/test_token_exchange.py | 16 +- tests/unit_tests/conftest.py | 16 +- tests/unit_tests/test_api_client.py | 223 ++-- tests/unit_tests/test_auth.py | 122 +-- .../unit_tests/test_authorization_request.py | 2 +- .../test_backchannel_authentication.py | 94 +- tests/unit_tests/test_client.py | 427 ++++---- .../unit_tests/test_client_authentication.py | 56 +- tests/unit_tests/test_device_authorization.py | 58 +- tests/unit_tests/test_discovery.py | 2 +- tests/unit_tests/test_dpop.py | 126 +-- tests/unit_tests/test_flask.py | 25 +- tests/unit_tests/test_oidc.py | 4 +- tests/unit_tests/test_pkce.py | 2 +- tests/unit_tests/test_tokens.py | 2 +- tests/unit_tests/test_utils.py | 4 +- .../unit_tests/vendor_specific/test_auth0.py | 4 +- tests/unit_tests/vendor_specific/test_ping.py | 2 +- tox.ini | 45 - 58 files changed, 1868 insertions(+), 1437 deletions(-) delete mode 100644 AUTHORS.md delete mode 100644 HISTORY.md rename {requests_oauth2client => niquests_oauth2client}/__init__.py (98%) rename {requests_oauth2client => niquests_oauth2client}/api_client.py (92%) rename {requests_oauth2client => niquests_oauth2client}/auth.py (88%) rename {requests_oauth2client => niquests_oauth2client}/authorization_request.py (98%) rename {requests_oauth2client => niquests_oauth2client}/backchannel_authentication.py (98%) rename {requests_oauth2client => niquests_oauth2client}/client.py (95%) rename {requests_oauth2client => niquests_oauth2client}/client_authentication.py (92%) rename {requests_oauth2client => niquests_oauth2client}/device_authorization.py (96%) rename {requests_oauth2client => niquests_oauth2client}/discovery.py (100%) rename {requests_oauth2client => niquests_oauth2client}/dpop.py (95%) rename {requests_oauth2client => niquests_oauth2client}/exceptions.py (95%) rename {requests_oauth2client => niquests_oauth2client}/flask/__init__.py (100%) rename {requests_oauth2client => niquests_oauth2client}/flask/auth.py (95%) rename {requests_oauth2client => niquests_oauth2client}/pooling.py (86%) rename {requests_oauth2client => niquests_oauth2client}/py.typed (100%) rename {requests_oauth2client => niquests_oauth2client}/tokens.py (98%) rename {requests_oauth2client => niquests_oauth2client}/utils.py (97%) rename {requests_oauth2client => niquests_oauth2client}/vendor_specific/__init__.py (78%) rename {requests_oauth2client => niquests_oauth2client}/vendor_specific/auth0.py (84%) rename {requests_oauth2client => niquests_oauth2client}/vendor_specific/ping.py (91%) delete mode 100644 tox.ini diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 4ce4f58..907e3ff 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,4 @@ -- `requests_oauth2client` version: +- `niquests_oauth2client` version: - Python version: - Operating System: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a948b71..70e9642 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] @@ -23,14 +23,14 @@ repos: args: - --in-place - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.6.8 + rev: v0.9.3 hooks: - id: ruff-format - id: ruff args: [ --fix ] - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.2 + rev: v1.14.1 hooks: - id: mypy args: @@ -43,7 +43,7 @@ repos: - pytest-mypy - pytest-freezer - jwskate>=0.11.1 - - types-requests + - niquests - requests_mock - flask - furl diff --git a/AUTHORS.md b/AUTHORS.md deleted file mode 100644 index bd0b99d..0000000 --- a/AUTHORS.md +++ /dev/null @@ -1,9 +0,0 @@ -# Credits - -## Development Lead - -- Guillaume Pujol - -## Contributors - -None yet. Why not be the first? diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 75c0227..d4de007 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ You can contribute in many ways: ### Report Bugs -Report bugs at https://github.com/guillp/requests_oauth2client/issues. +Report bugs at https://github.com/guillp/niquests_oauth2client/issues. If you are reporting a bug, please include: @@ -30,13 +30,13 @@ and "help wanted" is open to whoever wants to implement it. ### Write Documentation -`requests_oauth2client` could always use more documentation, whether as part of the -official requests_oauth2client docs, in docstrings, or even on the web in blog posts, +`niquests_oauth2client` could always use more documentation, whether as part of the +official niquests_oauth2client docs, in docstrings, or even on the web in blog posts, articles, and such. ### Submit Feedback -The best way to send feedback is to file an issue at https://github.com/guillp/requests_oauth2client/issues. +The best way to send feedback is to file an issue at https://github.com/guillp/niquests_oauth2client/issues. If you are proposing a feature: @@ -47,9 +47,9 @@ If you are proposing a feature: ## Get Started! -Ready to contribute? Here's how to set up `requests_oauth2client` for local development. +Ready to contribute? Here's how to set up `niquests_oauth2client` for local development. -1. Fork the `requests_oauth2client` repo on GitHub. +1. Fork the `niquests_oauth2client` repo on GitHub. 2. Clone your fork locally ``` @@ -97,7 +97,7 @@ Before you submit a pull request, check that it meets these guidelines: your new functionality into a function with a docstring, and add the feature to the list in README.md. 3. The pull request should work for Python 3.6, 3.7, 3.8, 3.9 and for PyPy. Check - https://github.com/guillp/requests_oauth2client/actions + https://github.com/guillp/niquests_oauth2client/actions and make sure that the tests pass for all supported Python versions. ## Tips diff --git a/HISTORY.md b/HISTORY.md deleted file mode 100644 index 6042ee4..0000000 --- a/HISTORY.md +++ /dev/null @@ -1,41 +0,0 @@ -# History - -## 1.2 - -- `OAuth2AuthorizationCodeAuth` now accepts an AuthorizationResponse -- `AuthorizationRequest` now handles `nonce` and `acr_values` -- `OAuth2Client` accepts `authorization_endpoint` and `redirect_uri` at init time, and has a `authorization_request()` method to generate AuthorizationRequests -- `BearerToken` has a `validate_id_token()` method to handle ID Token validation has specified in OIDC -- Added `PingClient` for PingFederate by PingID - -## 1.1 - -- ApiClient now has `allow_redirects=False` by default -- OAuth2Client now has `extra_metadata` -- bugfixes, optimizations, introduce methods for easier subclassing - -## 1.0.0 - -- First properly documented version. -- Migrated from pipenv to poetry -- Added pre-commit checks -- `requests` is now automatically imported with `from requests_oauth2client import *` -- ApiClient is now a wrapper around `requests.Session` instead of a subclass -- `ApiClient.__init__()` now accepts extra kwargs which will be used to configure the `Session`. -- Add `__getitem__` and `__getattr_` to ApiClient -- `AuthorizationRequest.validate_callback()` now returns an `AuthorizationResponse` which contains all returned - response attributes instead of just a code. To access the authorization code, get the `code` attribute from that response. -- `OAuth2Client.authorization_code()` now accepts an `AuthorizationResponse` as parameter, and will - use it to include all necessary parameters for the Authorization Code Grant. -- removed `OAuth2Client.authorization_code_pkce()` -- Renamed `ClientSecretJWT` and `PrivateKeyJWT` to `ClientSecretJwt` and `PrivateKeyJwt`, for consistency with `jwskate`. -- Methods from `requests_oauth2client.utils` are no longer exposed in top-level module. -- Renamed base class `ClientAuthenticationMethod` to `BaseClientAuthenticationMethod`. -- Introduced a default timeout in `ApiClient` -- Splitted `jwskate` into its own independant module -- Use `BinaPy` for binary data manipulation -- Add support for Pushed Authorization Requests - -## \<= 0.18 - -- Draft versions diff --git a/README.md b/README.md index 0b0dd81..64caa23 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ -`requests_oauth2client` is an OAuth 2.x client for Python, able to obtain, refresh and revoke tokens from any -OAuth2.x/OIDC compliant Authorization Server. It sits upon and extends the famous [requests] HTTP client module. +> This is a side project forked from my initial module [`requests_oauth2client`](https://github.com/guillp/requests_oauth2client), +> which was based on `requests`. As `requests` is more or less officially replaced by `niquests`, this new module ensures +> compatibility with `niquests`. I will maintain and update both as much as possible, since they are almost 100% the same +> code base. But, at some point, I hope to add async features in `niquests_oauth2client`. + +`niquests_oauth2client` is an OAuth 2.x client for Python, able to obtain, refresh and revoke tokens from any +OAuth2.x/OIDC compliant Authorization Server. It sits upon and extends the [niquests] HTTP client module. It can act as an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) / [2.1](https://datatracker.ietf.org/doc/draft-ietf-oauth-v2-1) client, to automatically get and renew Access Tokens, @@ -12,7 +17,7 @@ based on the [Device Authorization](https://www.rfc-editor.org/rfc/rfc8628.html), [Resource Owner Password](https://www.rfc-editor.org/rfc/rfc6749#section-4.3) or [CIBA](https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html) grants. -Additional grant types are easy to add if needed. +Additional grant types are easy to add if needed.[](https://) It also supports [OpenID Connect 1.0](https://openid.net/specs/openid-connect-core-1_0.html), [PKCE](https://www.rfc-editor.org/rfc/rfc7636.html), @@ -27,54 +32,54 @@ It also supports [OpenID Connect 1.0](https://openid.net/specs/openid-connect-co as well as using custom params to any endpoint, and other important features that are often overlooked or needlessly complex in other client libraries. -And it also includes a [wrapper][apiclient] around [requests.Session] that makes it super easy to use REST-style APIs, +And it also includes a [wrapper][apiclient] around [niquests.Session] that makes it super easy to use REST-style APIs, with or without OAuth 2.x. Please note that despite the name, this library has no relationship with Google [oauth2client](https://github.com/googleapis/oauth2client) library. [![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/) -[![PyPi version](https://img.shields.io/pypi/v/requests_oauth2client)](https://pypi.org/project/requests_oauth2client/) -[![Downloads](https://static.pepy.tech/badge/requests_oauth2client/month)](https://pepy.tech/project/requests_oauth2client) -[![Supported Versions](https://img.shields.io/pypi/pyversions/requests_oauth2client.svg)](https://pypi.org/project/requests_oauth2client) -[![PyPi license](https://badgen.net/pypi/license/requests_oauth2client/)](https://pypi.com/project/requests_oauth2client/) -[![PyPI status](https://img.shields.io/pypi/status/requests_oauth2client.svg)](https://pypi.python.org/pypi/requests_oauth2client/) -[![GitHub commits](https://badgen.net/github/commits/guillp/requests_oauth2client)](https://github.com/guillp/requests_oauth2client/commit/) -[![GitHub latest commit](https://badgen.net/github/last-commit/guillp/requests_oauth2client)](https://github.com/guillp/requests_oauth2client/commit/) +[![PyPi version](https://img.shields.io/pypi/v/niquests_oauth2client)](https://pypi.org/project/niquests_oauth2client/) +[![Downloads](https://static.pepy.tech/badge/niquests_oauth2client/month)](https://pepy.tech/project/niquests_oauth2client) +[![Supported Versions](https://img.shields.io/pypi/pyversions/niquests_oauth2client.svg)](https://pypi.org/project/niquests_oauth2client) +[![PyPi license](https://badgen.net/pypi/license/niquests_oauth2client/)](https://pypi.com/project/niquests_oauth2client/) +[![PyPI status](https://img.shields.io/pypi/status/niquests_oauth2client.svg)](https://pypi.python.org/pypi/niquests_oauth2client/) +[![GitHub commits](https://badgen.net/github/commits/guillp/niquests_oauth2client)](https://github.com/guillp/niquests_oauth2client/commit/) +[![GitHub latest commit](https://badgen.net/github/last-commit/guillp/niquests_oauth2client)](https://github.com/guillp/niquests_oauth2client/commit/) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) # Documentation -Full module documentation is available at https://guillp.github.io/requests_oauth2client/. +Full module documentation is available at https://guillp.github.io/niquests_oauth2client/. # Installation -`requests_oauth2client` is [available from PyPi](https://pypi.org/project/requests-oauth2client/), so installing it is +`niquests_oauth2client` is [available from PyPi](https://pypi.org/project/niquests-oauth2client/), so installing it is as easy as: ```shell -pip install requests_oauth2client +pip install niquests_oauth2client ``` # Usage -Everything from `requests_oauth2client` is available from the root module, so you can import it like this: +Everything from `niquests_oauth2client` is available from the root module, so you can import it like this: ```python -from requests_oauth2client import * +from niquests_oauth2client import * ``` Or you can import individual objects from this package as usual. Note that importing `*` automatically imports -`requests`, so no need to import it yourself. +`niquests`, so no need to import it yourself. ## Calling APIs with Access Tokens If you have already obtained an access token for the API you want to call, you can convert it to an instance of -[BearerToken]. Instances of this class work as a `requests` compatible auth handler. +[BearerToken]. Instances of this class work as a `niquests` compatible auth handler. ```python import requests -from requests_oauth2client import BearerToken +from niquests_oauth2client import BearerToken token = BearerToken("my_access_token") resp = requests.get("https://my.protected.api/endpoint", auth=token) @@ -97,7 +102,7 @@ and the credentials for your application, typically a `client_id` and a `client_ AS: ```python -from requests_oauth2client import OAuth2Client +from niquests_oauth2client import OAuth2Client oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -137,7 +142,7 @@ These methods directly return a [BearerToken] if the request is successful, or r You can create such a [BearerToken] yourself if needed: ```python -from requests_oauth2client import BearerToken +from niquests_oauth2client import BearerToken bearer_token = BearerToken(access_token="an_access_token", expires_in=60) print(bearer_token) @@ -155,28 +160,28 @@ print(bearer_token.expires_in) Note that the `expires_in` indicator here is not static. It keeps track of the token lifetime, in seconds, and is calculated as the time flies. The actual static expiration date is accessible with the `expires_at` property. You can check if a token is expired with -[bearer_token.is_expired()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.tokens.BearerToken.is_expired). +[bearer_token.is_expired()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.tokens.BearerToken.is_expired). You can use a [BearerToken] instance anywhere you can use an access_token as string. -### Using OAuth2Client as a requests Auth Handler +### Using OAuth2Client as a niquests Auth Handler Using [OAuth2Client] directly is useful for testing or debugging OAuth2.x flows, but it may not be suitable for actual applications where tokens must be obtained, used during their lifetime, then obtained again or refreshed once they are -expired. `requests_oauth2client` contains several [requests] compatible Auth Handlers (as subclasses of -[requests.auth.AuthBase](https://requests.readthedocs.io/en/latest/user/advanced/#custom-authentication)), that will +expired. `niquests_oauth2client` contains several [niquests] compatible Auth Handlers (as subclasses of +[niquests.auth.AuthBase](https://niquests.readthedocs.io/en/latest/user/authentication.html#new-forms-of-authentication)), that will take care of obtaining tokens when required, then will cache those tokens until they are expired, and will obtain new -ones (or refresh them, when possible), once the initial token is expired. Those are best used with a [requests.Session], +ones (or refresh them, when possible), once the initial token is expired. Those are best used with a [niquests.Session], or an [ApiClient], which is a wrapper around `Session` with a few enhancements as described below. ### Client Credentials grant To send a request using the Client Credentials grant, use the -[.client_credentials()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.client_credentials) +[.client_credentials()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.client_credentials) method, providing the necessary parameters as keyword arguments in the token request. ```python -from requests_oauth2client import OAuth2Client +from niquests_oauth2client import OAuth2Client oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -201,12 +206,12 @@ fulfill your request. #### As Auth Handler You can use the -[OAuth2ClientCredentialsAuth](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.auth.OAuth2ClientCredentialsAuth) +[OAuth2ClientCredentialsAuth](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.auth.OAuth2ClientCredentialsAuth) auth handler. It takes an `OAuth2Client` as parameter, and the additional kwargs to pass to the token endpoint: ```python import requests -from requests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth +from niquests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -231,7 +236,7 @@ resp = session.get("https://myapi.local/resource") Once again, extra parameters such as `scope`, `resource` or `audience` are allowed if required. When you send your first request, -[OAuth2ClientCredentialsAuth](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.auth.OAuth2ClientCredentialsAuth) +[OAuth2ClientCredentialsAuth](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.auth.OAuth2ClientCredentialsAuth) will automatically retrieve an access token from the AS using the Client Credentials grant, then will include it in the request. Next requests will use the same token, as long as it is valid. A new token will be automatically retrieved once the previous one is expired. @@ -241,7 +246,7 @@ obtained. This may help getting continuous access to the API when the client and Use the parameter `leeway` to `OAuth2ClientCredentialsAuth`: ```python -from requests_oauth2client import OAuth2ClientCredentialsAuth +from niquests_oauth2client import OAuth2ClientCredentialsAuth auth = OAuth2ClientCredentialsAuth( oauth2client, @@ -280,7 +285,7 @@ automatically. Then you can generate valid Authorization Requests by calling the the request specific parameters, such as `scope`, `state`, `nonce` as parameter: ```python -from requests_oauth2client import OAuth2Client +from niquests_oauth2client import OAuth2Client client = OAuth2Client( token_endpoint="https://url.to.the/token_endoint", @@ -343,7 +348,7 @@ Once you have obtained the AS response, containing an authorization code, your a Token(s). To exchange a code for Access and/or ID tokens, use the -[OAuth2Client.authorization_code()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.authorization_code) +[OAuth2Client.authorization_code()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.authorization_code) method. If you have obtained an AuthorizationResponse as described above, you can simply do: ```python @@ -366,12 +371,12 @@ token = oauth2client.authorization_code( #### As Auth Handler The -[OAuth2AuthorizationCodeAuth](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.auth.OAuth2AuthorizationCodeAuth) +[OAuth2AuthorizationCodeAuth](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.auth.OAuth2AuthorizationCodeAuth) handler takes an [OAuth2Client] and an authorization code as parameter, plus whatever additional keyword parameters are required by your Authorization Server: ```python -from requests_oauth2client import OAuth2Client, ApiClient, OAuth2AuthorizationCodeAuth +from niquests_oauth2client import OAuth2Client, ApiClient, OAuth2AuthorizationCodeAuth oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -391,13 +396,13 @@ api_client = ApiClient( resp = api_client.post(data={...}) ``` -[OAuth2AuthorizationCodeAuth](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.auth.OAuth2AuthorizationCodeAuth) +[OAuth2AuthorizationCodeAuth](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.auth.OAuth2AuthorizationCodeAuth) will take care of refreshing the token automatically once it is expired, using the refresh token, if available. ### Note on AuthorizationRequest Authorization Requests generated by `OAuth2Client.authorization_request()` are instance of the class -[`AuthorizationRequest`](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.authorization_request.AuthorizationRequest). +[`AuthorizationRequest`](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.authorization_request.AuthorizationRequest). You can also use that class directly to generate your requests, but in that case you need to supply your Authorization Endpoint URI, your `client_id`, `redirect_uri`, etc. You can access every parameter from an `AuthorizationRequest` instance, as well as the generated `code_verifier`, as attributes of this instance. Once an Authorization Request URL is @@ -405,7 +410,7 @@ generated, it your application responsibility to redirect or otherwise send the `webbrowser` module from Python standard library to do so. Here is an example for generating Authorization Requests: ```python -from requests_oauth2client import AuthorizationRequest +from niquests_oauth2client import AuthorizationRequest az_request = AuthorizationRequest( "https://url.to.the/authorization_endpoint", @@ -439,7 +444,7 @@ Helpers for the Device Authorization Grant are also included. To get device and (including Device Code, User Code, Verification URI, etc.), then pooling the Token Endpoint: ```python -from requests_oauth2client import ( +from niquests_oauth2client import ( OAuth2Client, DeviceAuthorizationPoolingJob, BearerToken, @@ -473,18 +478,18 @@ while resp is None: assert isinstance(resp, BearerToken) ``` -[DeviceAuthorizationPoolingJob](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.device_authorization.DeviceAuthorizationPoolingJob) +[DeviceAuthorizationPoolingJob](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.device_authorization.DeviceAuthorizationPoolingJob) will automatically obey the pooling period. Everytime you call `pool_job()`, it will wait the appropriate number of seconds as indicated by the AS, and will apply slow-down requests. #### As Auth Handler Use -[OAuth2DeviceCodeAuth](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.auth.OAuth2DeviceCodeAuth) +[OAuth2DeviceCodeAuth](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.auth.OAuth2DeviceCodeAuth) as auth handler to exchange a device code for an access token: ```python -from requests_oauth2client import ApiClient, OAuth2DeviceCodeAuth, OAuth2Client +from niquests_oauth2client import ApiClient, OAuth2DeviceCodeAuth, OAuth2Client client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -517,7 +522,7 @@ To initiate a BackChannel Authentication against the dedicated endpoint, read th Endpoint until the end-user successfully authenticates: ```python -from requests_oauth2client import ( +from niquests_oauth2client import ( OAuth2Client, BearerToken, BackChannelAuthenticationPoolingJob, @@ -555,11 +560,11 @@ Hints by the AS to slow down pooling will automatically be obeyed. ### Token Exchange To send a token exchange request, use the -[OAuth2Client.token_exchange()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.token_exchange) +[OAuth2Client.token_exchange()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.token_exchange) method: ```python -from requests_oauth2client import OAuth2Client, ClientSecretJwt +from niquests_oauth2client import OAuth2Client, ClientSecretJwt client = OAuth2Client( "https://url.to.the/token_endpoint", @@ -587,7 +592,7 @@ token = client.token_exchange( Or to make it even easier, types can be guessed based on the supplied subject or actor token: ```python -from requests_oauth2client import BearerToken, ClientSecretJwt, IdToken, OAuth2Client +from niquests_oauth2client import BearerToken, ClientSecretJwt, IdToken, OAuth2Client client = OAuth2Client( "https://url.to.the/token_endpoint", @@ -606,7 +611,7 @@ token = client.token_exchange( ## Supported Client Authentication Methods -`requests_oauth2client` supports several client authentication methods, as defined in multiple OAuth2.x standards. You +`niquests_oauth2client` supports several client authentication methods, as defined in multiple OAuth2.x standards. You select the appropriate method to use when initializing your [OAuth2Client], with the `auth` parameter. Once initialized, a client will automatically use the configured authentication method every time it sends a requested to an endpoint that requires client authentication. You don't have anything else to do afterwards. @@ -615,11 +620,11 @@ requires client authentication. You don't have anything else to do afterwards. With **client_secret_basic**, `client_id` and `client_secret` are included in clear-text in the `Authorization` header when sending requests to the Token Endpoint. To use it, just pass a -[`ClientSecretBasic(client_id, client_secret)`](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client_authentication.ClientSecretBasic) +[`ClientSecretBasic(client_id, client_secret)`](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client_authentication.ClientSecretBasic) as `auth` parameter: ```python -from requests_oauth2client import OAuth2Client, ClientSecretBasic +from niquests_oauth2client import OAuth2Client, ClientSecretBasic client = OAuth2Client( "https://url.to.the/token_endpoint", @@ -631,12 +636,12 @@ client = OAuth2Client( With **client_secret_post**, `client_id` and `client_secret` are included as part of the body form data. To use it, pass a -[`ClientSecretPost(client_id, client_secret)`](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client_authentication.ClientSecretPost) +[`ClientSecretPost(client_id, client_secret)`](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client_authentication.ClientSecretPost) as `auth` parameter. This is the default when you pass a tuple `(client_id, client_secret)` as `auth` when initializing an `OAuth2Client`: ```python -from requests_oauth2client import OAuth2Client, ClientSecretPost +from niquests_oauth2client import OAuth2Client, ClientSecretPost client = OAuth2Client( "https://url.to.the/token_endpoint", @@ -658,11 +663,11 @@ oauth2client = OAuth2Client( With **client_secret_jwt**, the client generates an ephemeral JWT assertion including information about itself (client_id), the AS (url of the endpoint), and an expiration date a few seconds in the future. To use it, pass a -[`ClientSecretJwt(client_id, client_secret)`](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client_authentication.ClientSecretJwt) +[`ClientSecretJwt(client_id, client_secret)`](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client_authentication.ClientSecretJwt) as `auth` parameter. Assertion generation is entirely automatic, you don't have anything to do: ```python -from requests_oauth2client import OAuth2Client, ClientSecretJwt +from niquests_oauth2client import OAuth2Client, ClientSecretJwt client = OAuth2Client( "https://url.to.the/token_endpoint", @@ -680,11 +685,11 @@ With **private_key_jwt**, client uses a JWT assertion that is just like the one signed with an _asymmetric_ key. To use it, you need a private signing key, in a `dict` that matches the JWK format, or as an instance of `jwskate.Jwk`. The matching public key must be registered for your client on AS side. Once you have that, using this auth method is simple with the -[`PrivateKeyJwt(client_id, private_jwk)`](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client_authentication.PrivateKeyJwt) +[`PrivateKeyJwt(client_id, private_jwk)`](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client_authentication.PrivateKeyJwt) auth handler: ```python -from requests_oauth2client import OAuth2Client, PrivateKeyJwt +from niquests_oauth2client import OAuth2Client, PrivateKeyJwt private_jwk = { "kid": "mykid", @@ -721,10 +726,10 @@ transmitting the Client Secret, which is a shared key that must be considered as The latest Client Authentication Method, **none**, is for Public Clients which do not authenticate to the Token Endpoint. Those clients only include their `client_id` in body form data, without any authentication credentials. Use -[`PublicApp(client_id)`](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client_authentication.PublicApp): +[`PublicApp(client_id)`](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client_authentication.PublicApp): ```python -from requests_oauth2client import OAuth2Client, PublicApp +from niquests_oauth2client import OAuth2Client, PublicApp client = OAuth2Client( "https://url.to.the/token_endpoint", auth=PublicApp("app_client_id") @@ -737,14 +742,14 @@ The [OAuth2Client] class provides methods for sending revocation requests to a R you need to provide the Revocation Endpoint URI when creating an instance of [OAuth2Client]. The available methods for revoking tokens are: -- [revoke_token()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.revoke_token): Revokes a token by providing the token value and an optional token_type_hint. -- [revoke_access_token()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.revoke_access_token): Revokes an access token by providing the token value. -- [revoke_refresh_token()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.revoke_refresh_token): Revokes a refresh token by providing the token value. +- [revoke_token()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.revoke_token): Revokes a token by providing the token value and an optional token_type_hint. +- [revoke_access_token()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.revoke_access_token): Revokes an access token by providing the token value. +- [revoke_refresh_token()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.revoke_refresh_token): Revokes a refresh token by providing the token value. Here is an example of how to use these methods: ```python -from requests_oauth2client import OAuth2Client, ClientSecretJwt +from niquests_oauth2client import OAuth2Client, ClientSecretJwt oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -765,11 +770,11 @@ return `False`. If the Authorization Server returns a standard error, an excepti The [OAuth2Client] class also supports sending requests to a Token Introspection Endpoint. To use this feature, you need to provide the Introspection Endpoint URI when creating an instance of [OAuth2Client]. -The [introspect_token()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.instrospect_token()) +The [introspect_token()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.instrospect_token()) method is then available for introspecting tokens: ```python -from requests_oauth2client import OAuth2Client, ClientSecretJwt +from niquests_oauth2client import OAuth2Client, ClientSecretJwt oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -786,11 +791,11 @@ The `introspect_token()` method returns the data returned by the introspection e The [OAuth2Client] class also supports sending requests to a UserInfo Endpoint. To use this feature, you need to provide the UserInfo Endpoint URI when creating an instance of [OAuth2Client] -The [userinfo()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.userinfo) +The [userinfo()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.userinfo) method is then available for retrieving user information: ```python -from requests_oauth2client import OAuth2Client, ClientSecretJwt +from niquests_oauth2client import OAuth2Client, ClientSecretJwt oauth2client = OAuth2Client( token_endpoint="https://url.to.the/token_endpoint", @@ -806,11 +811,11 @@ The `userinfo()` method returns the data returned by the userinfo endpoint, deco ## Initializing an `OAuth2Client` from a discovery document You can initialize an [OAuth2Client] with the endpoint URIs mentioned in a standardised discovery document using the -[OAuth2Client.from_discovery_endpoint()](https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client.from_discovery_document) +[OAuth2Client.from_discovery_endpoint()](https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client.from_discovery_document) class method: ```python -from requests_oauth2client import OAuth2Client, ClientSecretJwt +from niquests_oauth2client import OAuth2Client, ClientSecretJwt oauth2client = OAuth2Client.from_discovery_endpoint( "https://url.to.the.as/.well-known/openid-configuration", @@ -840,7 +845,7 @@ check will be made to ensure that the `issuer` from the retrieved metadata docum - or enable `DPoP` by default by passing `dpop_bound_access_tokens=True` when initializing your client. ```python -from requests_oauth2client import DPoPToken, OAuth2Client +from niquests_oauth2client import DPoPToken, OAuth2Client oauth2client = OAuth2Client.from_discovery_endpoint( issuer="https://as.local", @@ -862,21 +867,21 @@ assert isinstance(token, DPoPToken) ### About `DPoPToken` -`DPoPToken` is actually a `BearerToken` subclass. If you use it as a `requests` Auth Handler, it will take care of +`DPoPToken` is actually a `BearerToken` subclass. If you use it as a `niquests` Auth Handler, it will take care of adding a `DPoP` proof to the request headers, in addition to the access token. -Since it is a `BearerToken` subclass, it is fully compatible with the `requests` compatible auth handlers provided by -`requests_oauth2client`, such as `OAuth2ClientCredentialsAuth`, `OAuth2AccessTokenAuth`, etc. So you may use DPoP with +Since it is a `BearerToken` subclass, it is fully compatible with the `niquests` compatible auth handlers provided by +`niquests_oauth2client`, such as `OAuth2ClientCredentialsAuth`, `OAuth2AccessTokenAuth`, etc. So you may use DPoP with those auth handlers like this: ```python import requests -from requests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth, PrivateKeyJwt +from niquests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth, PrivateKeyJwt client = OAuth2Client.from_discovery_endpoint( issuer="https://my.issuer.local", auth=PrivateKeyJwt("client_id", "client_secret"), - dpop_bound_access_tokens=True, # enable DPoP by default + dpop_bound_access_tokens=True, # enable DPoP by default ) session = requests.Session() @@ -904,7 +909,7 @@ using `DPoPKey.generate()`, or by initializing an instance with a key that you p ```python from cryptography.hazmat.primitives.asymmetric import rsa import jwskate -from requests_oauth2client import DPoPKey, DPoPToken, OAuth2Client +from niquests_oauth2client import DPoPKey, DPoPToken, OAuth2Client oauth2client = OAuth2Client.from_discovery_endpoint( issuer="https://as.local", @@ -914,7 +919,8 @@ oauth2client = OAuth2Client.from_discovery_endpoint( dpop_key = DPoPKey.generate(alg="RS512") # generate a new DPoP key with an alg of your choice # or, for testing purposes only, your can load your own key -dpop_key = DPoPKey(private_key=jwskate.Jwk({"kty": "EC", "crv": "P-256", "alg": "ES256", "x": "...", "y": "...", "d": "..."})) +dpop_key = DPoPKey( + private_key=jwskate.Jwk({"kty": "EC", "crv": "P-256", "alg": "ES256", "x": "...", "y": "...", "d": "..."})) # or, any key material supported by `jwskate` is supported, so you can also use `cryptography` keys directly, # but you need to specify the signature `alg` since it is not part of the key itself dpop_key = DPoPKey(private_key=rsa.generate_private_key(public_exponent=65537, key_size=2048), alg="RS256") @@ -937,28 +943,29 @@ returned by the AS, and then generates proofs and includes those proofs into HTT You may use `DPoPKey.generate` as a helper method for that, or implement your own generator: - ```python import secrets -from requests_oauth2client import DPoPKey, DPoPToken, OAuth2Client +from niquests_oauth2client import DPoPKey, DPoPToken, OAuth2Client + class CustomDPoPToken(DPoPToken): """A custom DPoP token class that places the DPoP proof and token into a non-standard header.""" AUTHORIZATION_HEADER = "X-Custom-Auth" DPOP_HEADER = "X-DPoP" + oauth2client = OAuth2Client.from_discovery_endpoint( issuer="https://as.local", client_id="client_id", client_secret="client_secret", dpop_bound_access_tokens=True, # enable DPoP by default - dpop_alg="RS256", # choose the signing alg to use, and it will automatically determine the key type to generate. + dpop_alg="RS256", # choose the signing alg to use, and it will automatically determine the key type to generate. dpop_key_generator=lambda alg: DPoPKey.generate( alg=alg, # those other parameters are for feature testing the AS, or for workarounding AS bugs: - jwt_typ="jwt+custom", # you can customize the `typ` that is included in DPoP proof headers - jti_generator=lambda: secrets.token_urlsafe(24), # generate unique jti differently than the default UUIDs - iat_generator=lambda: 12532424, # override `iat` generation in DPoP proofs, here it will return a static value - dpop_token_class=CustomDPoPToken, # override the class that represents DPoP tokens + jwt_typ="jwt+custom", # you can customize the `typ` that is included in DPoP proof headers + jti_generator=lambda: secrets.token_urlsafe(24), # generate unique jti differently than the default UUIDs + iat_generator=lambda: 12532424, # override `iat` generation in DPoP proofs, here it will return a static value + dpop_token_class=CustomDPoPToken, # override the class that represents DPoP tokens ) ) ``` @@ -968,39 +975,39 @@ oauth2client = OAuth2Client.from_discovery_endpoint( Authorization Server provided `DPoP` nonces are automatically and transparently handled by `OAuth2Client`. Likewise, Resource Server provided `DPoP` nonces are supported when using the default `DPoPToken` class. -This includes all requests-compatible auth handlers provided by `requests_oauth2client`, like `OAuth2AccessTokenAuth`, +This includes all `niquests`-compatible auth handlers provided by `niquests_oauth2client`, like `OAuth2AccessTokenAuth`, `OAuth2ClientCredentialsAuth`, `OAuth2AuthorizationCodeAuth`, etc. As an example, see the sample below: ```python -from requests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth +from niquests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth -import requests +import niquests oauth2client = OAuth2Client.from_discovery_endpoint( issuer="https://as.local", client_id="client_id", client_secret="client_secret", ) -response = requests.get( +response = niquests.get( "https://my.api.local/endpoint", auth=OAuth2ClientCredentialsAuth(oauth2client, scope="my_scope", dpop=True), ) ``` Assuming that both the Authorization Server (at https://as.local) and the Resource Server (at https://my.api.local) -require the use of `DPoP` nonces, then at least 4 different requests are sent as a result of the `requests.get()` call +require the use of `DPoP` nonces, then at least 4 different requests are sent as a result of the `niquests.get()` call above: 1. The first request is to get a token from the Authorization Server, here using a *Client Credentials* grant and -including a DPoP proof. DPoP also works with all other grant types. That first requests does not include a nonce. -Since the AS requires a DPoP nonce, it replies to that request with an `error=use_dpop_nonce` flag and a generated DPoP -nonce. + including a DPoP proof. DPoP also works with all other grant types. That first requests does not include a nonce. + Since the AS requires a DPoP nonce, it replies to that request with an `error=use_dpop_nonce` flag and a generated DPoP + nonce. 2. Second request is automatically sent to the AS, this time with a DPoP proof that contains the nonce provided by the AS. -As a result, the AS returns a DPoP token. + As a result, the AS returns a DPoP token. 3. Third request is sent to the target API, with the DPoP token obtained at step 2, and a DPoP proof that does not yet -contain a `nonce`. + contain a `nonce`. The response from this call is a `401` with at least these 2 response headers: - a `WWW-Authenticate: DPoP error="use_dpop_nonce"` header, indicating that a DPoP `nonce` is requested, @@ -1008,13 +1015,13 @@ contain a `nonce`. 4. a request is sent again to the target API, this time with a DPoP proof that contains the RS provided `nonce` obtained at step 3. Target API then should accept that request, do its own business and return a `200` response. -If you send multiple requests to the same API, instead of using individual calls to `requests.get()`, `requests.post()` -etc., you should use a `requests.Session` or an `ApiClient`. It will make sure that the obtained access token and +If you send multiple requests to the same API, instead of using individual calls to `niquests.get()`, `niquests.post()` +etc., you should use a `niquests.Session` or an `ApiClient`. It will make sure that the obtained access token and DPoP nonce(s) are reused as long as they are valid, which avoid repeating calls 1 and 2 unnecessarily and consuming more tokens and nonces than necessary: ```python -from requests_oauth2client import ApiClient, OAuth2Client, OAuth2ClientCredentialsAuth +from niquests_oauth2client import ApiClient, OAuth2Client, OAuth2ClientCredentialsAuth oauth2client = OAuth2Client.from_discovery_endpoint( issuer="https://as.local", @@ -1023,10 +1030,12 @@ oauth2client = OAuth2Client.from_discovery_endpoint( ) api = ApiClient("https://my.api.local/", auth=OAuth2ClientCredentialsAuth(oauth2client, scope="my_scope", dpop=True)) -response1 = api.get("endpoint") # the first call will trigger requests 1. 2. 3. 4. like above -response2 = api.post("other_endpoint") # next calls will reuse the same token and DPoP nonces as long as they are valid. +response1 = api.get("endpoint") # the first call will trigger requests 1. 2. 3. 4. like above +response2 = api.post( + "other_endpoint") # next calls will reuse the same token and DPoP nonces as long as they are valid. # some time later -response3 = api.get("other_endpoint") # new tokens and DPoP nonces will automatically be obtained when the first ones are expired +response3 = api.get( + "other_endpoint") # new tokens and DPoP nonces will automatically be obtained when the first ones are expired ``` AS and RS provided nonces are memoized independently by the `DPoPToken` instance, so the amount of "extra" requests to @@ -1035,15 +1044,15 @@ obtain new DPoP nonces should be minimal. ## Specialized API Client Using APIs usually involves multiple endpoints under the same root url, with a common authentication method. To make it -easier, `requests_oauth2client` includes a [requests.Session] wrapper called [ApiClient], which takes the root API url +easier, `niquests_oauth2client` includes a [niquests.Session] wrapper called [ApiClient], which takes the root API url as parameter on initialization. You can then send requests to different endpoints by passing their relative path instead of the full url. [ApiClient] also accepts an `auth` parameter with an AuthHandler. You can pass any of the OAuth2 Auth -Handler from this module, or any [requests]-compatible -[Authentication Handler](https://requests.readthedocs.io/en/latest/user/advanced/#custom-authentication). Which makes it -very easy to call APIs that are protected with an OAuth2 Client Credentials Grant: +Handler from this module, or any `niquests`-compatible +[Authentication Handler](https://niquests.readthedocs.io/en/latest/user/authentication.html). Which makes it +straightforward to call APIs that are protected with an OAuth2 Client Credentials Grant: ```python -from requests_oauth2client import OAuth2Client, ApiClient, OAuth2ClientCredentialsAuth +from niquests_oauth2client import OAuth2Client, ApiClient, OAuth2ClientCredentialsAuth oauth2client = OAuth2Client( "https://url.to.the/token_endpoint", client_id="client_id", client_secret="client_secret" @@ -1085,7 +1094,7 @@ Both `__getattr__` and `__getitem__` return a new `ApiClient` initialised on the multiple sub-resources on the same API this way: ```python -from requests_oauth2client import ApiClient +from niquests_oauth2client import ApiClient api = ApiClient("https://myapi.local") users_api = api.users @@ -1099,7 +1108,7 @@ resources = resources_api.get() # GET https://myapi.local/resources passing `raise_for_status=False` when initializing your [ApiClient]: ```python -from requests_oauth2client import ApiClient +from niquests_oauth2client import ApiClient api = ApiClient( "http://httpstat.us", raise_for_status=False @@ -1116,12 +1125,12 @@ You may override this at request time: resp = api.get("500", raise_for_status=True) ``` -You can access the underlying `requests.Session` with the session attribute, and you can provide an already existing and +You can access the underlying `niquests.Session` with the session attribute, and you can provide an already existing and configured `Session` instance at init time: ```python import requests -from requests_oauth2client import ApiClient +from niquests_oauth2client import ApiClient session = requests.Session() session.proxies = {"https": "http://localhost:3128"} @@ -1131,7 +1140,7 @@ assert api.session == session ## Vendor-Specific clients -`requests_oauth2client` is flexible enough to handle most use cases, so you should be able to use any AS by any vendor +`niquests_oauth2client` is flexible enough to handle most use cases, so you should be able to use any AS by any vendor as long as it supports OAuth 2.0. You can however create a subclass of [OAuth2Client] or [ApiClient] to make it easier to use with specific Authorization @@ -1140,7 +1149,7 @@ Servers or APIs. [OAuth2Client] has several extensibility points in the form of etc. ```python -from requests_oauth2client.vendor_specific import Auth0 +from niquests_oauth2client.vendor_specific import Auth0 a0client = Auth0.client( "mytenant.eu", client_id="client_id", client_secret="client_secret" @@ -1156,8 +1165,8 @@ a0mgmt = Auth0.management_api_client( myusers = a0mgmt.get("users") ``` -[apiclient]: https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.api_client.ApiClient -[bearertoken]: https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.tokens.BearerToken -[oauth2client]: https://guillp.github.io/requests_oauth2client/api/#requests_oauth2client.client.OAuth2Client -[requests]: https://requests.readthedocs.io/en/latest/ -[requests.session]: https://requests.readthedocs.io/en/latest/api/#requests.Session +[apiclient]: https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.api_client.ApiClient +[bearertoken]: https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.tokens.BearerToken +[oauth2client]: https://guillp.github.io/niquests_oauth2client/api/#niquests_oauth2client.client.OAuth2Client +[niquests]: https://niquests.readthedocs.io/en/latest/ +[niquests.session]: https://niquests.readthedocs.io/en/latest/user/advanced.html#session-objects diff --git a/docs/api.md b/docs/api.md index 89cf2cc..ca90949 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1 +1 @@ -::: requests_oauth2client +::: niquests_oauth2client diff --git a/docs/installation.md b/docs/installation.md index 8a6919a..8ff874c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,33 +2,33 @@ ## Stable release -To install requests_oauth2client, run this command in your +To install niquests_oauth2client, run this command in your terminal: ```console -$ pip install requests_oauth2client +$ pip install niquests_oauth2client ``` -This is the preferred method to install requests_oauth2client, as it will always install the most recent stable release. +This is the preferred method to install niquests_oauth2client, as it will always install the most recent stable release. If you don't have [pip] installed, this [Python installation guide] can guide you through the process. ## From source -The source for requests_oauth2client can be downloaded from +The source for niquests_oauth2client can be downloaded from the [Github repo]. You can either clone the public repository: ```console -$ git clone git://github.com/guillp/requests_oauth2client +$ git clone git://github.com/guillp/niquests_oauth2client ``` Or download the [tarball]: ```console -$ curl -OJL https://github.com/guillp/requests_oauth2client/tarball/master +$ curl -OJL https://github.com/guillp/niquests_oauth2client/tarball/master ``` Once you have a copy of the source, you can install it with: diff --git a/docs/usage.md b/docs/usage.md index 23e0263..f202843 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,7 +1,7 @@ # Usage -To use requests_oauth2client in a project +To use niquests_oauth2client in a project ``` -from requests_oauth2client import * +from niquests_oauth2client import * ``` diff --git a/mkdocs.yml b/mkdocs.yml index 7b6f8f4..cd05f72 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,10 +1,10 @@ -site_name: requests_oauth2client +site_name: niquests_oauth2client # site_url: http://www.jieyu.ai -repo_url: https://github.com/guillp/requests_oauth2client -repo_name: requests_oauth2client +repo_url: https://github.com/guillp/niquests_oauth2client +repo_name: niquests_oauth2client strict: true watch: - - requests_oauth2client + - niquests_oauth2client - README.md nav: - Home: index.md @@ -71,12 +71,12 @@ plugins: show_root_heading: true show_submodules: true import: - - https://requests.readthedocs.io/en/master/objects.inv + #- https://niquests.readthedocs.io/en/master/objects.inv - https://guillp.github.io/jwskate/objects.inv extra: social: - icon: fontawesome/brands/github - link: https://github.com/guillp/requests_oauth2client + link: https://github.com/guillp/niquests_oauth2client name: Github - icon: material/email - link: "mailto:guill.p.linux@gmail.com" + link: "mailto:guillp.dev@pm.me" diff --git a/requests_oauth2client/__init__.py b/niquests_oauth2client/__init__.py similarity index 98% rename from requests_oauth2client/__init__.py rename to niquests_oauth2client/__init__.py index e78f28f..f7b07eb 100644 --- a/requests_oauth2client/__init__.py +++ b/niquests_oauth2client/__init__.py @@ -1,10 +1,10 @@ -"""Main module for `requests_oauth2client`. +"""Main module for `niquests_oauth2client`. You can import any class from any submodule directly from this main module. """ -import requests +import niquests from jwskate import EncryptionAlgs, KeyManagementAlgs, SignatureAlgs from .api_client import ApiClient, InvalidBoolFieldsParam, InvalidPathParam @@ -163,11 +163,11 @@ "BackChannelAuthenticationError", "BackChannelAuthenticationPoolingJob", "BackChannelAuthenticationResponse", + "BaseClientAssertionAuthenticationMethod", "BaseClientAuthenticationMethod", "BaseTokenEndpointPoolingJob", "BearerToken", "BearerTokenSerializer", - "BaseClientAssertionAuthenticationMethod", "ClientSecretBasic", "ClientSecretJwt", "ClientSecretPost", @@ -196,12 +196,12 @@ "InvalidClient", "InvalidClientAssertionSigningKeyOrAlg", "InvalidCodeVerifierParam", - "InvalidDeviceAuthorizationResponse", - "InvalidDiscoveryDocument", "InvalidDPoPAccessToken", "InvalidDPoPAlg", "InvalidDPoPKey", "InvalidDPoPProof", + "InvalidDeviceAuthorizationResponse", + "InvalidDiscoveryDocument", "InvalidEndpointUri", "InvalidGrant", "InvalidIdToken", @@ -221,18 +221,18 @@ "KeyManagementAlgs", "LoginRequired", "MismatchingIdTokenAcr", - "MissingAuthRequestId", - "MissingEndpointUri", + "MismatchingIdTokenAlg", "MismatchingIdTokenAudience", "MismatchingIdTokenAzp", - "MismatchingIdTokenAlg", "MismatchingIdTokenIssuer", "MismatchingIdTokenNonce", "MismatchingIssuer", "MismatchingState", "MissingAuthCode", - "MissingDeviceCode", + "MissingAuthRequestId", "MissingDPoPNonce", + "MissingDeviceCode", + "MissingEndpointUri", "MissingIdToken", "MissingIdTokenEncryptedResponseAlgParam", "MissingIssuer", @@ -260,17 +260,17 @@ "SlowDown", "TokenEndpointError", "UnauthorizedClient", + "UnknownActorTokenType", "UnknownIntrospectionError", + "UnknownSubjectTokenType", "UnknownTokenEndpointError", + "UnknownTokenType", "UnsupportedClientCredentials", "UnsupportedCodeChallengeMethod", "UnsupportedResponseTypeParam", "UnsupportedTokenType", - "UnknownTokenType", - "UnknownActorTokenType", - "UnknownSubjectTokenType", "UseDPoPNonce", - "requests", + "niquests", "oauth2_discovery_document_url", "oidc_discovery_document_url", "validate_dpop_proof", diff --git a/requests_oauth2client/api_client.py b/niquests_oauth2client/api_client.py similarity index 92% rename from requests_oauth2client/api_client.py rename to niquests_oauth2client/api_client.py index 9beae45..1232ff6 100644 --- a/requests_oauth2client/api_client.py +++ b/niquests_oauth2client/api_client.py @@ -2,18 +2,19 @@ from __future__ import annotations -from typing import IO, TYPE_CHECKING, Any, Callable, Iterable, Mapping, MutableMapping +from collections.abc import Iterable, Mapping, MutableMapping +from typing import IO, TYPE_CHECKING, Any, Callable from urllib.parse import quote as urlencode from urllib.parse import urljoin -import requests +import niquests from attrs import frozen from typing_extensions import Literal, Self if TYPE_CHECKING: from types import TracebackType - from requests.cookies import RequestsCookieJar + from niquests.cookies import RequestsCookieJar class InvalidBoolFieldsParam(ValueError): @@ -84,8 +85,8 @@ class ApiClient: `None` to remove that header. `base_url` will serve as root for relative urls passed to - [ApiClient.request()][requests_oauth2client.api_client.ApiClient.request], - [ApiClient.get()][requests_oauth2client.api_client.ApiClient.get], etc. + [ApiClient.request()][niquests_oauth2client.api_client.ApiClient.request], + [ApiClient.get()][niquests_oauth2client.api_client.ApiClient.get], etc. A [requests.HTTPError][] will be raised everytime an API call returns an error code (>= 400), unless you set `raise_for_status` to `False`. Additional parameters passed at init time, including @@ -93,7 +94,7 @@ class ApiClient: Example: ```python - from requests_oauth2client import ApiClient + from niquests_oauth2client import ApiClient api = ApiClient("https://myapi.local/resource", timeout=10) resp = api.get("/myid") # this will send a GET request @@ -141,29 +142,29 @@ class ApiClient: """ base_url: str - auth: requests.auth.AuthBase | None + auth: niquests.auth.AuthBase | None timeout: int | None raise_for_status: bool none_fields: Literal["include", "exclude", "empty"] bool_fields: tuple[Any, Any] | None - session: requests.Session + session: niquests.Session def __init__( self, base_url: str, *, - auth: requests.auth.AuthBase | None = None, + auth: niquests.auth.AuthBase | None = None, timeout: int | None = 60, raise_for_status: bool = True, none_fields: Literal["include", "exclude", "empty"] = "exclude", bool_fields: tuple[Any, Any] | None = ("true", "false"), cookies: Mapping[str, Any] | None = None, headers: Mapping[str, Any] | None = None, - user_agent: str | None = requests.utils.default_user_agent(), - session: requests.Session | None = None, + user_agent: str | None = niquests.utils.default_user_agent(), + session: niquests.Session | None = None, **session_kwargs: Any, ) -> None: - session = session or requests.Session() + session = session or niquests.Session() if cookies: for key, val in cookies.items(): @@ -217,8 +218,8 @@ def request( # noqa: C901, PLR0913, D417 auth: ( None | tuple[str, str] - | requests.auth.AuthBase - | Callable[[requests.PreparedRequest], requests.PreparedRequest] + | niquests.auth.AuthBase + | Callable[[niquests.PreparedRequest], niquests.PreparedRequest] ) = None, timeout: None | float | tuple[float, float] | tuple[float, None] = None, allow_redirects: bool = False, @@ -227,7 +228,7 @@ def request( # noqa: C901, PLR0913, D417 | ( MutableMapping[ str, - (Iterable[Callable[[requests.Response], Any]] | Callable[[requests.Response], Any]), + (Iterable[Callable[[niquests.Response], Any]] | Callable[[niquests.Response], Any]), ] ) = None, stream: bool | None = None, @@ -237,11 +238,11 @@ def request( # noqa: C901, PLR0913, D417 raise_for_status: bool | None = None, none_fields: Literal["include", "exclude", "empty"] | None = None, bool_fields: tuple[Any, Any] | None = None, - ) -> requests.Response: + ) -> niquests.Response: """A wrapper around [requests.Session.request][] method with extra features. Additional features are described in - [ApiClient][requests_oauth2client.api_client.ApiClient] documentation. + [ApiClient][niquests_oauth2client.api_client.ApiClient] documentation. All parameters will be passed as-is to [requests.Session.request][], expected those described below which have a special behavior. @@ -252,13 +253,13 @@ def request( # noqa: C901, PLR0913, D417 - a path, as `str`: that path will be joined to the configured API url, - an iterable of path segments: that will be joined to the root url. raise_for_status: like the parameter of the same name from - [ApiClient][requests_oauth2client.api_client.ApiClient], + [ApiClient][niquests_oauth2client.api_client.ApiClient], but this will be applied for this request only. none_fields: like the parameter of the same name from - [ApiClient][requests_oauth2client.api_client.ApiClient], + [ApiClient][niquests_oauth2client.api_client.ApiClient], but this will be applied for this request only. bool_fields: like the parameter of the same name from - [ApiClient][requests_oauth2client.api_client.ApiClient], + [ApiClient][niquests_oauth2client.api_client.ApiClient], but this will be applied for this request only. Returns: @@ -393,11 +394,11 @@ def get( path: None | str | bytes | Iterable[str | bytes | int] = None, raise_for_status: bool | None = None, **kwargs: Any, - ) -> requests.Response: + ) -> niquests.Response: """Send a GET request and return a [Response][requests.Response] object. The passed `url` is relative to the `base_url` passed at initialization time. - It takes the same parameters as [ApiClient.request()][requests_oauth2client.api_client.ApiClient.request]. + It takes the same parameters as [ApiClient.request()][niquests_oauth2client.api_client.ApiClient.request]. Args: path: the path where the request will be sent. @@ -418,11 +419,11 @@ def post( path: str | bytes | Iterable[str | bytes] | None = None, raise_for_status: bool | None = None, **kwargs: Any, - ) -> requests.Response: + ) -> niquests.Response: """Send a POST request and return a [Response][requests.Response] object. The passed `url` is relative to the `base_url` passed at initialization time. - It takes the same parameters as [ApiClient.request()][requests_oauth2client.api_client.ApiClient.request]. + It takes the same parameters as [ApiClient.request()][niquests_oauth2client.api_client.ApiClient.request]. Args: path: the path where the request will be sent. @@ -443,11 +444,11 @@ def patch( path: str | bytes | Iterable[str | bytes] | None = None, raise_for_status: bool | None = None, **kwargs: Any, - ) -> requests.Response: + ) -> niquests.Response: """Send a PATCH request. Return a [Response][requests.Response] object. The passed `url` is relative to the `base_url` passed at initialization time. - It takes the same parameters as [ApiClient.request()][requests_oauth2client.api_client.ApiClient.request]. + It takes the same parameters as [ApiClient.request()][niquests_oauth2client.api_client.ApiClient.request]. Args: path: the path where the request will be sent. @@ -468,11 +469,11 @@ def put( path: str | bytes | Iterable[str | bytes] | None = None, raise_for_status: bool | None = None, **kwargs: Any, - ) -> requests.Response: + ) -> niquests.Response: """Send a PUT request. Return a [Response][requests.Response] object. The passed `url` is relative to the `base_url` passed at initialization time. - It takes the same parameters as [ApiClient.request()][requests_oauth2client.api_client.ApiClient.request]. + It takes the same parameters as [ApiClient.request()][niquests_oauth2client.api_client.ApiClient.request]. Args: path: the path where the request will be sent. @@ -493,11 +494,11 @@ def delete( path: str | bytes | Iterable[str | bytes] | None = None, raise_for_status: bool | None = None, **kwargs: Any, - ) -> requests.Response: + ) -> niquests.Response: """Send a DELETE request. Return a [Response][requests.Response] object. The passed `url` may be relative to the url passed at initialization time. It takes the same - parameters as [ApiClient.request()][requests_oauth2client.api_client.ApiClient.request]. + parameters as [ApiClient.request()][niquests_oauth2client.api_client.ApiClient.request]. Args: path: the path where the request will be sent. @@ -524,7 +525,7 @@ def __getattr__(self, item: str) -> ApiClient: Example: ```python - from requests_oauth2client import ApiClient + from niquests_oauth2client import ApiClient api = ApiClient("https://myapi.local") resource1 = api.resource1.get() # GET https://myapi.local/resource1 @@ -545,7 +546,7 @@ def __getitem__(self, item: str) -> ApiClient: Example: ```python - from requests_oauth2client import ApiClient + from niquests_oauth2client import ApiClient api = ApiClient("https://myapi.local") resource1 = api["resource1"].get() # GET https://myapi.local/resource1 diff --git a/requests_oauth2client/auth.py b/niquests_oauth2client/auth.py similarity index 88% rename from requests_oauth2client/auth.py rename to niquests_oauth2client/auth.py index 137a20f..0b93b82 100644 --- a/requests_oauth2client/auth.py +++ b/niquests_oauth2client/auth.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any -import requests +import niquests from attrs import define, field, setters from typing_extensions import override @@ -21,14 +21,14 @@ class NonRenewableTokenError(Exception): @define(init=False) -class OAuth2AccessTokenAuth(requests.auth.AuthBase): +class OAuth2AccessTokenAuth(niquests.auth.AuthBase): """Authentication Handler for OAuth 2.0 Access Tokens and (optional) Refresh Tokens. - This [Requests Auth handler][requests.auth.AuthBase] implementation uses an access token as + This [Requests Auth handler][niquests.auth.AuthBase] implementation uses an access token as Bearer or DPoP token, and can automatically refresh it when expired, if a refresh token is available. Token can be a simple `str` containing a raw access token value, or a - [BearerToken][requests_oauth2client.tokens.BearerToken] that can contain a `refresh_token`. + [BearerToken][niquests_oauth2client.tokens.BearerToken] that can contain a `refresh_token`. In addition to adding a properly formatted `Authorization` header, this will obtain a new token once the current token is expired. Expiration is detected based on the `expires_in` hint @@ -44,14 +44,14 @@ class OAuth2AccessTokenAuth(requests.auth.AuthBase): Example: ```python - from requests_oauth2client import BearerToken, OAuth2Client, OAuth2AccessTokenAuth, requests + from niquests_oauth2client import BearerToken, OAuth2Client, OAuth2AccessTokenAuth, niquests client = OAuth2Client(token_endpoint="https://my.as.local/token", auth=("client_id", "client_secret")) # obtain a BearerToken any way you see fit, optionally including a refresh token # for this example, the token value is hardcoded token = BearerToken(access_token="access_token", expires_in=600, refresh_token="refresh_token") auth = OAuth2AccessTokenAuth(client, token, scope="my_scope") - resp = requests.post("https://my.api.local/resource", auth=auth) + resp = niquests.post("https://my.api.local/resource", auth=auth) ``` """ @@ -68,7 +68,7 @@ def __init__( token = BearerToken(token) self.__attrs_init__(client=client, token=token, leeway=leeway, token_kwargs=token_kwargs) - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Add the Access Token to the request. If Access Token is not specified or expired, obtain a new one first. @@ -101,23 +101,23 @@ def forget_token(self) -> None: class OAuth2ClientCredentialsAuth(OAuth2AccessTokenAuth): """An Auth Handler for the [Client Credentials grant](https://www.rfc-editor.org/rfc/rfc6749#section-4.4). - This [requests AuthBase][requests.auth.AuthBase] automatically gets Access Tokens from an OAuth + This [niquests AuthBase][niquests.auth.AuthBase] automatically gets Access Tokens from an OAuth 2.0 Token Endpoint with the Client Credentials grant, and will get a new one once the current one is expired. Args: - client: the [OAuth2Client][requests_oauth2client.client.OAuth2Client] to use to obtain Access Tokens. + client: the [OAuth2Client][niquests_oauth2client.client.OAuth2Client] to use to obtain Access Tokens. token: an initial Access Token, if you have one already. In most cases, leave `None`. leeway: expiration leeway, in number of seconds **token_kwargs: extra kw parameters to pass to the Token Endpoint. May include `scope`, `resource`, etc. Example: ```python - from requests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth, requests + from niquests_oauth2client import OAuth2Client, OAuth2ClientCredentialsAuth, niquests client = OAuth2Client(token_endpoint="https://my.as.local/token", auth=("client_id", "client_secret")) oauth2cc = OAuth2ClientCredentialsAuth(client, scope="my_scope") - resp = requests.post("https://my.api.local/resource", auth=oauth2cc) + resp = niquests.post("https://my.api.local/resource", auth=oauth2cc) ``` """ @@ -139,7 +139,7 @@ def renew_token(self) -> None: class OAuth2AuthorizationCodeAuth(OAuth2AccessTokenAuth): # type: ignore[override] """Authentication handler for the [Authorization Code grant](https://www.rfc-editor.org/rfc/rfc6749#section-4.1). - This [Requests Auth handler][requests.auth.AuthBase] implementation exchanges an Authorization + This [niquests Auth handler][niquests.auth.AuthBase] implementation exchanges an Authorization Code for an access token, then automatically refreshes it once it is expired. Args: @@ -151,7 +151,7 @@ class OAuth2AuthorizationCodeAuth(OAuth2AccessTokenAuth): # type: ignore[overri Example: ```python - from requests_oauth2client import ApiClient, OAuth2Client, OAuth2AuthorizationCodeAuth + from niquests_oauth2client import ApiClient, OAuth2Client, OAuth2AuthorizationCodeAuth client = OAuth2Client(token_endpoint="https://myas.local/token", auth=("client_id", "client_secret")) code = "my_code" # you must obtain this code yourself @@ -181,7 +181,7 @@ def __init__( token_kwargs=token_kwargs, ) - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Implement the Authorization Code grant as an Authentication Handler. This exchanges an Authorization Code for an access token and adds it in the request. @@ -208,7 +208,7 @@ def exchange_code_for_token(self) -> None: class OAuth2ResourceOwnerPasswordAuth(OAuth2AccessTokenAuth): # type: ignore[override] """Authentication Handler for the [Resource Owner Password Credentials Flow](https://www.rfc-editor.org/rfc/rfc6749#section-4.3). - This [Requests Auth handler][requests.auth.AuthBase] implementation exchanges the user + This [niquests Auth handler][niquests.auth.AuthBase] implementation exchanges the user credentials for an Access Token, then automatically repeats the process to get a new one once the current one is expired. @@ -222,7 +222,7 @@ class OAuth2ResourceOwnerPasswordAuth(OAuth2AccessTokenAuth): # type: ignore[ov dedicated, centralized login page managed by the AS, which makes it totally insecure for 3rd party apps. It needs the username and password and an - [OAuth2Client][requests_oauth2client.client.OAuth2Client] to be able to get a token from + [OAuth2Client][niquests_oauth2client.client.OAuth2Client] to be able to get a token from the AS Token Endpoint just before the first request using this Auth Handler is being sent. Args: @@ -235,7 +235,7 @@ class OAuth2ResourceOwnerPasswordAuth(OAuth2AccessTokenAuth): # type: ignore[ov Example: ```python - from requests_oauth2client import ApiClient, OAuth2Client, OAuth2ResourceOwnerPasswordAuth + from niquests_oauth2client import ApiClient, OAuth2Client, OAuth2ResourceOwnerPasswordAuth client = OAuth2Client( token_endpoint="https://myas.local/token", @@ -286,15 +286,15 @@ def renew_token(self) -> None: class OAuth2DeviceCodeAuth(OAuth2AccessTokenAuth): # type: ignore[override] """Authentication Handler for the [Device Code Flow](https://www.rfc-editor.org/rfc/rfc8628). - This [Requests Auth handler][requests.auth.AuthBase] implementation exchanges a Device Code for + This [niquests Auth handler][niquests.auth.AuthBase] implementation exchanges a Device Code for an Access Token, then automatically refreshes it once it is expired. - It needs a Device Code and an [OAuth2Client][requests_oauth2client.client.OAuth2Client] to be + It needs a Device Code and an [OAuth2Client][niquests_oauth2client.client.OAuth2Client] to be able to get a token from the AS Token Endpoint just before the first request using this Auth Handler is being sent. Args: - client: the [OAuth2Client][requests_oauth2client.client.OAuth2Client] to use to obtain Access Tokens. + client: the [OAuth2Client][niquests_oauth2client.client.OAuth2Client] to use to obtain Access Tokens. device_code: a Device Code obtained from the AS. interval: the interval to use to pool the Token Endpoint, in seconds. expires_in: the lifetime of the token, in seconds. @@ -304,12 +304,12 @@ class OAuth2DeviceCodeAuth(OAuth2AccessTokenAuth): # type: ignore[override] Example: ```python - from requests_oauth2client import OAuth2Client, OAuth2DeviceCodeAuth, requests + from niquests_oauth2client import OAuth2Client, OAuth2DeviceCodeAuth, niquests client = OAuth2Client(token_endpoint="https://my.as.local/token", auth=("client_id", "client_secret")) device_code = client.device_authorization() auth = OAuth2DeviceCodeAuth(client, device_code) - resp = requests.post("https://my.api.local/resource", auth=auth) + resp = niquests.post("https://my.api.local/resource", auth=auth) ``` """ @@ -342,16 +342,16 @@ def __init__( ) @override - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Implement the Device Code grant as a request Authentication Handler. - This exchanges a Device Code for an access token and adds it in HTTP requests. + This exchanges a Device Code for an access token and adds it in HTTP niquests. Args: - request: a [requests.PreparedRequest][] + request: a [niquests.PreparedRequest][] Returns: - a [requests.PreparedRequest][] with an Access Token added in Authorization Header + a [niquests.PreparedRequest][] with an Access Token added in Authorization Header """ if self.token is None: diff --git a/requests_oauth2client/authorization_request.py b/niquests_oauth2client/authorization_request.py similarity index 98% rename from requests_oauth2client/authorization_request.py rename to niquests_oauth2client/authorization_request.py index 14c5576..1123a06 100644 --- a/requests_oauth2client/authorization_request.py +++ b/niquests_oauth2client/authorization_request.py @@ -6,7 +6,7 @@ import secrets from enum import Enum from functools import cached_property -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Sequence +from typing import TYPE_CHECKING, Any, Callable, ClassVar from attrs import asdict, field, fields, frozen from binapy import BinaPy @@ -28,6 +28,7 @@ from .utils import accepts_expires_in if TYPE_CHECKING: + from collections.abc import Iterable, Sequence from datetime import datetime @@ -337,7 +338,7 @@ class AuthorizationRequest: Example: ```python - from requests_oauth2client import AuthorizationRequest + from niquests_oauth2client import AuthorizationRequest azr = AuthorizationRequest( authorization_endpoint="https://url.to.the/authorization_endpoint", @@ -521,7 +522,7 @@ def validate_callback(self, response: str) -> AuthorizationResponse: """Validate an Authorization Response against this Request. Validate a given Authorization Response URI against this Authorization Request, and return - an [AuthorizationResponse][requests_oauth2client.authorization_request.AuthorizationResponse]. + an [AuthorizationResponse][niquests_oauth2client.authorization_request.AuthorizationResponse]. This includes matching the `state` parameter, checking for returned errors, and extracting the returned `code` and other parameters. @@ -728,7 +729,7 @@ def on_response_error(self, response: str) -> AuthorizationResponse: """Error handler for Authorization Response errors. Triggered by - [validate_callback()][requests_oauth2client.authorization_request.AuthorizationRequest.validate_callback] + [validate_callback()][niquests_oauth2client.authorization_request.AuthorizationRequest.validate_callback] if the response uri contains an error. Args: @@ -778,9 +779,9 @@ class RequestParameterAuthorizationRequest: """Represent an Authorization Request that includes a `request` JWT. To construct such a request yourself, the easiest way is to initialize - an [`AuthorizationRequest`][requests_oauth2client.authorization_request.AuthorizationRequest] + an [`AuthorizationRequest`][niquests_oauth2client.authorization_request.AuthorizationRequest] then sign it with - [`AuthorizationRequest.sign()`][requests_oauth2client.authorization_request.AuthorizationRequest.sign]. + [`AuthorizationRequest.sign()`][niquests_oauth2client.authorization_request.AuthorizationRequest.sign]. Args: authorization_endpoint: the Authorization Endpoint uri diff --git a/requests_oauth2client/backchannel_authentication.py b/niquests_oauth2client/backchannel_authentication.py similarity index 98% rename from requests_oauth2client/backchannel_authentication.py rename to niquests_oauth2client/backchannel_authentication.py index 23581cf..ba2c635 100644 --- a/requests_oauth2client/backchannel_authentication.py +++ b/niquests_oauth2client/backchannel_authentication.py @@ -156,7 +156,7 @@ def token_request(self) -> BearerToken: This actually calls [OAuth2Client.ciba(auth_req_id)] on `client`. Returns: - a [BearerToken][requests_oauth2client.tokens.BearerToken] + a [BearerToken][niquests_oauth2client.tokens.BearerToken] """ return self.client.ciba(self.auth_req_id, requests_kwargs=self.requests_kwargs, **self.token_kwargs) diff --git a/requests_oauth2client/client.py b/niquests_oauth2client/client.py similarity index 95% rename from requests_oauth2client/client.py rename to niquests_oauth2client/client.py index 24dc572..434f43f 100644 --- a/requests_oauth2client/client.py +++ b/niquests_oauth2client/client.py @@ -4,9 +4,9 @@ import warnings from enum import Enum -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, TypeVar +from typing import TYPE_CHECKING, Any, Callable, ClassVar, TypeVar -import requests +import niquests from attrs import Attribute, field, frozen from jwskate import Jwk, JwkSet, Jwt, SignatureAlgs from typing_extensions import Self @@ -54,6 +54,7 @@ from .utils import InvalidUri, validate_endpoint_uri, validate_issuer_uri if TYPE_CHECKING: + from collections.abc import Iterable from types import TracebackType from mypy_extensions import DefaultNamedArg @@ -222,7 +223,7 @@ class OAuth2Client: This class is not intended to help with the end-user authentication or any request that goes in a browser. For authentication requests, see - [AuthorizationRequest][requests_oauth2client.authorization_request.AuthorizationRequest]. You + [AuthorizationRequest][niquests_oauth2client.authorization_request.AuthorizationRequest]. You may use the method `authorization_request()` to generate `AuthorizationRequest`s with the preconfigured `authorization_endpoint`, `client_id` and `redirect_uri' from this client. @@ -231,13 +232,13 @@ class OAuth2Client: auth: the authentication handler to use for client authentication on the token endpoint. Can be: - - a [requests.auth.AuthBase][] instance (which will be used as-is) + - a [niquests.auth.AuthBase][] instance (which will be used as-is) - a tuple of `(client_id, client_secret)` which will initialize an instance - of [ClientSecretPost][requests_oauth2client.client_authentication.ClientSecretPost] + of [ClientSecretPost][niquests_oauth2client.client_authentication.ClientSecretPost] - a `(client_id, jwk)` to initialize - a [PrivateKeyJwt][requests_oauth2client.client_authentication.PrivateKeyJwt], + a [PrivateKeyJwt][niquests_oauth2client.client_authentication.PrivateKeyJwt], - or a `client_id` which will - use [PublicApp][requests_oauth2client.client_authentication.PublicApp] authentication. + use [PublicApp][niquests_oauth2client.client_authentication.PublicApp] authentication. client_id: client ID (use either this or `auth`) client_secret: client secret (use either this or `auth`) @@ -251,7 +252,7 @@ class OAuth2Client: device_authorization_endpoint: the Device Authorization Endpoint URI to use to authorize devices jwks_uri: the JWKS URI to use to obtain the AS public keys code_challenge_method: challenge method to use for PKCE (should always be 'S256') - session: a requests Session to use when sending HTTP requests. + session: a `niquests.Session` to use when sending HTTP requests. Useful if some extra parameters such as proxy or client certificate must be used to connect to the AS. token_class: a custom BearerToken class, if required @@ -292,7 +293,7 @@ class OAuth2Client: """ - auth: requests.auth.AuthBase + auth: niquests.auth.AuthBase token_endpoint: str = field() revocation_endpoint: str | None = field() introspection_endpoint: str | None = field() @@ -310,7 +311,7 @@ class OAuth2Client: id_token_decryption_key: Jwk | None code_challenge_method: str | None authorization_response_iss_parameter_supported: bool - session: requests.Session + session: niquests.Session extra_metadata: dict[str, Any] testing: bool @@ -340,7 +341,7 @@ def __init__( # noqa: PLR0913 self, token_endpoint: str, auth: ( - requests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None + niquests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None ) = None, *, client_id: str | None = None, @@ -363,7 +364,7 @@ def __init__( # noqa: PLR0913 code_challenge_method: str = CodeChallengeMethods.S256, authorization_response_iss_parameter_supported: bool = False, token_class: type[BearerToken] = BearerToken, - session: requests.Session | None = None, + session: niquests.Session | None = None, dpop_bound_access_tokens: bool = False, dpop_key_generator: Callable[[str], DPoPKey] = DPoPKey.generate, dpop_alg: str = SignatureAlgs.ES256, @@ -399,7 +400,7 @@ def __init__( # noqa: PLR0913 raise InvalidDPoPAlg(dpop_alg) if session is None: - session = requests.Session() + session = niquests.Session() self.__attrs_init__( testing=testing, @@ -501,8 +502,8 @@ def _request( self, endpoint: str, *, - on_success: Callable[[requests.Response, DefaultNamedArg(DPoPKey | None, "dpop_key")], T], - on_failure: Callable[[requests.Response, DefaultNamedArg(DPoPKey | None, "dpop_key")], T], + on_success: Callable[[niquests.Response, DefaultNamedArg(DPoPKey | None, "dpop_key")], T], + on_failure: Callable[[niquests.Response, DefaultNamedArg(DPoPKey | None, "dpop_key")], T], dpop_key: DPoPKey | None = None, accept: str = "application/json", method: str = "POST", @@ -606,7 +607,7 @@ def token_request( - if `None`, defaults to `dpop_bound_access_tokens` configuration parameter for the client. dpop_key: a chosen `DPoPKey` for this request. If `None`, a new key will be generated automatically with a call to this client `dpop_key_generator`. - **requests_kwargs: additional parameters for requests.post() + **requests_kwargs: additional parameters for niquests.post() Returns: the token endpoint response @@ -628,10 +629,10 @@ def token_request( **requests_kwargs, ) - def parse_token_response(self, response: requests.Response, *, dpop_key: DPoPKey | None = None) -> BearerToken: + def parse_token_response(self, response: niquests.Response, *, dpop_key: DPoPKey | None = None) -> BearerToken: """Parse a Response returned by the Token Endpoint. - Invoked by [token_request][requests_oauth2client.client.OAuth2Client.token_request] to parse + Invoked by [token_request][niquests_oauth2client.client.OAuth2Client.token_request] to parse responses returned by the Token Endpoint. Those responses contain an `access_token` and additional attributes. @@ -653,13 +654,13 @@ def parse_token_response(self, response: requests.Response, *, dpop_key: DPoPKey def on_token_error( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> BearerToken: """Error handler for `token_request()`. - Invoked by [token_request][requests_oauth2client.client.OAuth2Client.token_request] when the + Invoked by [token_request][niquests_oauth2client.client.OAuth2Client.token_request] when the Token Endpoint returns an error. Args: @@ -717,7 +718,7 @@ def client_credentials( - if `None`, defaults to `dpop_bound_access_tokens` configuration parameter for the client. dpop_key: a chosen `DPoPKey` for this request. If `None`, a new key will be generated automatically with a call to `dpop_key_generator`. - requests_kwargs: additional parameters for the call to requests + requests_kwargs: additional parameters for the call to niquests **token_kwargs: additional parameters that will be added in the form data for the token endpoint, alongside `grant_type`. @@ -768,7 +769,7 @@ def authorization_code( dpop: Toggles DPoP binding for the Access Token, even if Authorization Code DPoP binding was not initially done. dpop_key: A chosen DPoP key. Leave `None` to automatically generate a key, if `dpop` is `True`. - requests_kwargs: Additional parameters for the call to the underlying HTTP `requests` call. + requests_kwargs: Additional parameters for the call to the underlying HTTP `niquests` call. **token_kwargs: Additional parameters that will be added in the form data for the token endpoint, alongside `grant_type`, `code`, etc. @@ -807,7 +808,7 @@ def refresh_token( Args: refresh_token: A refresh_token, as a string, or as a `BearerToken`. That `BearerToken` must have a `refresh_token`. - requests_kwargs: Additional parameters for the call to `requests`. + requests_kwargs: Additional parameters for the call to `niquests`. **token_kwargs: Additional parameters for the token endpoint, alongside `grant_type`, `refresh_token`, etc. @@ -849,7 +850,7 @@ def device_code( device_code: A device code, or a `DeviceAuthorizationResponse`. dpop: Toggles DPoP Binding. If `None`, defaults to `self.dpop_bound_access_tokens`. dpop_key: A chosen DPoP key. Leave `None` to have a new key generated for this request. - requests_kwargs: Additional parameters for the call to requests. + requests_kwargs: Additional parameters for the call to niquests. **token_kwargs: Additional parameters for the token endpoint, alongside `grant_type`, `device_code`, etc. Returns: @@ -885,7 +886,7 @@ def ciba( Args: auth_req_id: an authentication request ID, as returned by the AS - requests_kwargs: additional parameters for the call to requests + requests_kwargs: additional parameters for the call to niquests **token_kwargs: additional parameters for the token endpoint, alongside `grant_type`, `auth_req_id`, etc. Returns: @@ -937,7 +938,7 @@ def token_exchange( requested_token_type: A token type identifier for the requested token. dpop: Toggles DPoP Binding. If `None`, defaults to `self.dpop_bound_access_tokens`. dpop_key: A chosen DPoP key. Leave `None` to have a new key generated for this request. - requests_kwargs: Additional parameters to pass to the underlying `requests.post()` call. + requests_kwargs: Additional parameters to pass to the underlying `niquests.post()` call. **token_kwargs: Additional parameters to include in the request body. Returns: @@ -988,7 +989,7 @@ def jwt_bearer( assertion: A JWT (as an instance of `jwskate.Jwt` or as a `str`) to use as authorization grant. dpop: Toggles DPoP Binding. If `None`, defaults to `self.dpop_bound_access_tokens`. dpop_key: A chosen DPoP key. Leave `None` to have a new key generated for this request. - requests_kwargs: Additional parameters to pass to the underlying `requests.post()` call. + requests_kwargs: Additional parameters to pass to the underlying `niquests.post()` call. **token_kwargs: Additional parameters to include in the request body. Returns: @@ -1027,7 +1028,7 @@ def resource_owner_password( password: the resource owner password dpop: Toggles DPoP Binding. If `None`, defaults to `self.dpop_bound_access_tokens`. dpop_key: A chosen DPoP key. Leave `None` to have a new key generated for this request. - requests_kwargs: additional parameters to pass to the underlying `requests.post()` call. + requests_kwargs: additional parameters to pass to the underlying `niquests.post()` call. **token_kwargs: additional parameters to include in the request body. Returns: @@ -1120,7 +1121,7 @@ def pushed_authorization_request( Args: authorization_request: The authorization request to send. - requests_kwargs: Additional parameters for `requests.request()`. + requests_kwargs: Additional parameters for `niquests.request()`. Returns: The `RequestUriParameterAuthorizationRequest` initialized based on the AS response. @@ -1139,14 +1140,14 @@ def pushed_authorization_request( def parse_pushed_authorization_response( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, ) -> RequestUriParameterAuthorizationRequest: """Parse the response obtained by `pushed_authorization_request()`. Args: - response: The `requests.Response` returned by the PAR endpoint. + response: The `niquests.Response` returned by the PAR endpoint. dpop_key: The `DPoPKey` that was used to proof the token request, if any. Returns: @@ -1167,7 +1168,7 @@ def parse_pushed_authorization_response( def on_pushed_authorization_request_error( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> RequestUriParameterAuthorizationRequest: @@ -1214,7 +1215,7 @@ def userinfo(self, access_token: BearerToken | str) -> Any: access_token: the access token to use Returns: - the [Response][requests.Response] returned by the userinfo endpoint. + the [Response][niquests.Response] returned by the userinfo endpoint. """ if isinstance(access_token, str): @@ -1226,14 +1227,14 @@ def userinfo(self, access_token: BearerToken | str) -> Any: on_failure=self.on_userinfo_error, ) - def parse_userinfo_response(self, resp: requests.Response, *, dpop_key: DPoPKey | None = None) -> Any: # noqa: ARG002 + def parse_userinfo_response(self, resp: niquests.Response, *, dpop_key: DPoPKey | None = None) -> Any: # noqa: ARG002 """Parse the response obtained by `userinfo()`. - Invoked by [userinfo()][requests_oauth2client.client.OAuth2Client.userinfo] to parse the + Invoked by [userinfo()][niquests_oauth2client.client.OAuth2Client.userinfo] to parse the response from the UserInfo endpoint, this will extract and return its JSON content. Args: - resp: a [Response][requests.Response] returned from the UserInfo endpoint. + resp: a [Response][niquests.Response] returned from the UserInfo endpoint. dpop_key: the `DPoPKey` that was used to proof the token request, if any. Returns: @@ -1242,11 +1243,11 @@ def parse_userinfo_response(self, resp: requests.Response, *, dpop_key: DPoPKey """ return resp.json() - def on_userinfo_error(self, resp: requests.Response, *, dpop_key: DPoPKey | None = None) -> Any: # noqa: ARG002 + def on_userinfo_error(self, resp: niquests.Response, *, dpop_key: DPoPKey | None = None) -> Any: # noqa: ARG002 """Parse UserInfo error response. Args: - resp: a [Response][requests.Response] returned from the UserInfo endpoint. + resp: a [Response][niquests.Response] returned from the UserInfo endpoint. dpop_key: the `DPoPKey` that was used to proof the token request, if any. Returns: @@ -1335,7 +1336,7 @@ def revoke_access_token( Args: access_token: the access token to revoke - requests_kwargs: additional parameters for the underlying requests.post() call + requests_kwargs: additional parameters for the underlying niquests.post() call **revoke_kwargs: additional parameters to pass to the revocation endpoint """ @@ -1364,7 +1365,7 @@ def revoke_refresh_token( revocation endpoint. Raises: - MissingRefreshToken: when `refresh_token` is a [BearerToken][requests_oauth2client.tokens.BearerToken] + MissingRefreshToken: when `refresh_token` is a [BearerToken][niquests_oauth2client.tokens.BearerToken] but does not contain a `refresh_token`. """ @@ -1394,7 +1395,7 @@ def revoke_token( Args: token: the token to revoke. token_type_hint: a token_type_hint to send to the revocation endpoint. - requests_kwargs: additional parameters to the underling call to requests.post() + requests_kwargs: additional parameters to the underling call to niquests.post() **revoke_kwargs: additional parameters to send to the revocation endpoint. Returns: @@ -1426,13 +1427,13 @@ def revoke_token( **requests_kwargs, ) - def parse_revocation_response(self, response: requests.Response, *, dpop_key: DPoPKey | None = None) -> bool: # noqa: ARG002 + def parse_revocation_response(self, response: niquests.Response, *, dpop_key: DPoPKey | None = None) -> bool: # noqa: ARG002 """Parse reponses from the Revocation Endpoint. Since those do not return any meaningful information in a standardised fashion, this just returns `True`. Args: - response: the `requests.Response` as returned by the Revocation Endpoint. + response: the `niquests.Response` as returned by the Revocation Endpoint. dpop_key: the `DPoPKey` that was used to proof the token request, if any. Returns: @@ -1442,14 +1443,14 @@ def parse_revocation_response(self, response: requests.Response, *, dpop_key: DP """ return True - def on_revocation_error(self, response: requests.Response, *, dpop_key: DPoPKey | None = None) -> bool: # noqa: ARG002 + def on_revocation_error(self, response: niquests.Response, *, dpop_key: DPoPKey | None = None) -> bool: # noqa: ARG002 """Error handler for `revoke_token()`. - Invoked by [revoke_token()][requests_oauth2client.client.OAuth2Client.revoke_token] when the + Invoked by [revoke_token()][niquests_oauth2client.client.OAuth2Client.revoke_token] when the revocation endpoint returns an error. Args: - response: the `requests.Response` as returned by the Revocation Endpoint. + response: the `niquests.Response` as returned by the Revocation Endpoint. dpop_key: the `DPoPKey` that was used to proof the token request, if any. Returns: @@ -1503,7 +1504,7 @@ def introspect_token( Args: token: the token to instrospect token_type_hint: the `token_type_hint` to include in the request. - requests_kwargs: additional parameters to the underling call to requests.post() + requests_kwargs: additional parameters to the underling call to niquests.post() **introspect_kwargs: additional parameters to send to the introspection endpoint. Returns: @@ -1545,18 +1546,18 @@ def introspect_token( def parse_introspection_response( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> Any: """Parse Token Introspection Responses received by `introspect_token()`. - Invoked by [introspect_token()][requests_oauth2client.client.OAuth2Client.introspect_token] + Invoked by [introspect_token()][niquests_oauth2client.client.OAuth2Client.introspect_token] to parse the returned response. This decodes the JSON content if possible, otherwise it returns the response as a string. Args: - response: the [Response][requests.Response] as returned by the Introspection Endpoint. + response: the [Response][niquests.Response] as returned by the Introspection Endpoint. dpop_key: the `DPoPKey` that was used to proof the token request, if any. Returns: @@ -1568,10 +1569,10 @@ def parse_introspection_response( except ValueError: return response.text - def on_introspection_error(self, response: requests.Response, *, dpop_key: DPoPKey | None = None) -> Any: # noqa: ARG002 + def on_introspection_error(self, response: niquests.Response, *, dpop_key: DPoPKey | None = None) -> Any: # noqa: ARG002 """Error handler for `introspect_token()`. - Invoked by [introspect_token()][requests_oauth2client.client.OAuth2Client.introspect_token] + Invoked by [introspect_token()][niquests_oauth2client.client.OAuth2Client.introspect_token] to parse the returned response in the case an error is returned. Args: @@ -1634,7 +1635,7 @@ def backchannel_authentication_request( # noqa: PLR0913 requested_expiry: the Requested Expiry, in seconds, to include in the request. private_jwk: the JWK to use to sign the request (optional) alg: the alg to use to sign the request, if the provided JWK does not include an "alg" parameter. - requests_kwargs: additional parameters for + requests_kwargs: additional parameters for the call to `niquests.post()` **ciba_kwargs: additional parameters to include in the request. Returns: @@ -1696,14 +1697,14 @@ def backchannel_authentication_request( # noqa: PLR0913 def parse_backchannel_authentication_response( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> BackChannelAuthenticationResponse: """Parse a response received by `backchannel_authentication_request()`. Invoked by - [backchannel_authentication_request()][requests_oauth2client.client.OAuth2Client.backchannel_authentication_request] + [backchannel_authentication_request()][niquests_oauth2client.client.OAuth2Client.backchannel_authentication_request] to parse the response returned by the BackChannel Authentication Endpoint. Args: @@ -1725,14 +1726,14 @@ def parse_backchannel_authentication_response( def on_backchannel_authentication_error( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> BackChannelAuthenticationResponse: """Error handler for `backchannel_authentication_request()`. Invoked by - [backchannel_authentication_request()][requests_oauth2client.client.OAuth2Client.backchannel_authentication_request] + [backchannel_authentication_request()][niquests_oauth2client.client.OAuth2Client.backchannel_authentication_request] to parse the response returned by the BackChannel Authentication Endpoint, when it is an error. @@ -1774,7 +1775,7 @@ def authorize_device( Args: **data: additional data to send to the Device Authorization Endpoint - requests_kwargs: additional parameters for `requests.request()` + requests_kwargs: additional parameters for `niquests.request()` Returns: a Device Authorization Response @@ -1796,13 +1797,13 @@ def authorize_device( def parse_device_authorization_response( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> DeviceAuthorizationResponse: """Parse a Device Authorization Response received by `authorize_device()`. - Invoked by [authorize_device()][requests_oauth2client.client.OAuth2Client.authorize_device] + Invoked by [authorize_device()][niquests_oauth2client.client.OAuth2Client.authorize_device] to parse the response returned by the Device Authorization Endpoint. Args: @@ -1817,13 +1818,13 @@ def parse_device_authorization_response( def on_device_authorization_error( self, - response: requests.Response, + response: niquests.Response, *, dpop_key: DPoPKey | None = None, # noqa: ARG002 ) -> DeviceAuthorizationResponse: """Error handler for `authorize_device()`. - Invoked by [authorize_device()][requests_oauth2client.client.OAuth2Client.authorize_device] + Invoked by [authorize_device()][niquests_oauth2client.client.OAuth2Client.authorize_device] to parse the response returned by the Device Authorization Endpoint, when that response is an error. @@ -1885,11 +1886,11 @@ def from_discovery_endpoint( url: str | None = None, issuer: str | None = None, *, - auth: requests.auth.AuthBase | tuple[str, str] | str | None = None, + auth: niquests.auth.AuthBase | tuple[str, str] | str | None = None, client_id: str | None = None, client_secret: str | None = None, private_key: Jwk | dict[str, Any] | None = None, - session: requests.Session | None = None, + session: niquests.Session | None = None, testing: bool = False, **kwargs: Any, ) -> OAuth2Client: @@ -1912,7 +1913,7 @@ def from_discovery_endpoint( client_id: Client ID. client_secret: Client secret to use to authenticate the client. private_key: Private key to sign client assertions. - session: A `requests.Session` to use to retrieve the document and initialise the client with. + session: A `niquests.Session` to use to retrieve the document and initialise the client with. testing: If `True`, do not try to validate the issuer uri nor the endpoint urls that are part of the document. **kwargs: Additional keyword parameters to pass to `OAuth2Client`. @@ -1923,11 +1924,11 @@ def from_discovery_endpoint( Raises: InvalidIssuer: If `issuer` is not using https, or contains credentials or fragment. InvalidParam: If neither `url` nor `issuer` are suitable urls. - requests.HTTPError: If an error happens while fetching the documents. + niquests.HTTPError: If an error happens while fetching the documents. Example: ```python - from requests_oauth2client import OAuth2Client + from niquests_oauth2client import OAuth2Client client = OAuth2Client.from_discovery_endpoint( issuer="https://myserver.net", @@ -1951,7 +1952,7 @@ def from_discovery_endpoint( if not testing: validate_endpoint_uri(url, path=False) - session = session or requests.Session() + session = session or niquests.Session() discovery = session.get(url).json() jwks_uri = discovery.get("jwks_uri") @@ -1976,7 +1977,7 @@ def from_discovery_document( discovery: dict[str, Any], issuer: str | None = None, *, - auth: requests.auth.AuthBase | tuple[str, str] | str | None = None, + auth: niquests.auth.AuthBase | tuple[str, str] | str | None = None, client_id: str | None = None, client_secret: str | None = None, private_key: Jwk | dict[str, Any] | None = None, @@ -2007,7 +2008,7 @@ def from_discovery_document( Examples: ```python - from requests_oauth2client import OAuth2Client + from niquests_oauth2client import OAuth2Client client = OAuth2Client.from_discovery_document( { @@ -2030,7 +2031,7 @@ def from_discovery_document( testing = True if issuer and discovery.get("issuer") != issuer: msg = f"""\ -Mismatching `issuer` value in discovery document (received '{discovery.get('issuer')}', expected '{issuer}').""" +Mismatching `issuer` value in discovery document (received '{discovery.get("issuer")}', expected '{issuer}').""" raise InvalidParam( msg, issuer, diff --git a/requests_oauth2client/client_authentication.py b/niquests_oauth2client/client_authentication.py similarity index 92% rename from requests_oauth2client/client_authentication.py rename to niquests_oauth2client/client_authentication.py index 2f483ad..e1cfff8 100644 --- a/requests_oauth2client/client_authentication.py +++ b/niquests_oauth2client/client_authentication.py @@ -13,7 +13,7 @@ from urllib.parse import parse_qs from uuid import uuid4 -import requests +import niquests from attrs import frozen from binapy import BinaPy from jwskate import Jwk, Jwt, SignatureAlgs, SymmetricJwk, to_jwk @@ -22,14 +22,14 @@ class InvalidRequestForClientAuthentication(RuntimeError): """Raised when a request is not suitable for OAuth 2.0 client authentication.""" - def __init__(self, request: requests.PreparedRequest) -> None: + def __init__(self, request: niquests.PreparedRequest) -> None: super().__init__("This request is not suitabe for OAuth 2.0 client authentication.") self.request = request @frozen -class BaseClientAuthenticationMethod(requests.auth.AuthBase): - """Base class for all Client Authentication methods. This extends [requests.auth.AuthBase][]. +class BaseClientAuthenticationMethod(niquests.auth.AuthBase): + """Base class for all Client Authentication methods. This extends [niquests.auth.AuthBase][]. This base class checks that requests are suitable to add Client Authentication parameters to, and does not modify the request. @@ -38,7 +38,7 @@ class BaseClientAuthenticationMethod(requests.auth.AuthBase): client_id: str - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Check that the request is suitable for Client Authentication. It checks: @@ -47,10 +47,10 @@ def __call__(self, request: requests.PreparedRequest) -> requests.PreparedReques * that the Content-Type is "application/x-www-form-urlencoded" or None Args: - request: a [requests.PreparedRequest][] + request: a [niquests.PreparedRequest][] Returns: - a [requests.PreparedRequest][], unmodified + a [niquests.PreparedRequest][], unmodified Raises: RuntimeError: if the request is not suitable for OAuth 2.0 Client Authentication @@ -77,7 +77,7 @@ class ClientSecretBasic(BaseClientAuthenticationMethod): Example: ```python - from requests_oauth2client import ClientSecretBasic, OAuth2Client + from niquests_oauth2client import ClientSecretBasic, OAuth2Client auth = ClientSecretBasic("my_client_id", "my_client_secret") client = OAuth2Client("https://url.to.the/token_endpoint", auth=auth) @@ -93,7 +93,7 @@ def __init__(self, client_id: str, client_secret: str) -> None: client_secret=client_secret, ) - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Add the appropriate `Authorization` header in each request. The Authorization header is formatted as such: @@ -103,7 +103,7 @@ def __call__(self, request: requests.PreparedRequest) -> requests.PreparedReques request: the request Returns: - a [requests.PreparedRequest][] with the added Authorization header. + a [niquests.PreparedRequest][] with the added Authorization header. """ request = super().__call__(request) @@ -125,7 +125,7 @@ class ClientSecretPost(BaseClientAuthenticationMethod): Example: ```python - from requests_oauth2client import ClientSecretPost, OAuth2Client + from niquests_oauth2client import ClientSecretPost, OAuth2Client auth = ClientSecretPost("my_client_id", "my_client_secret") client = OAuth2Client("https://url.to.the/token_endpoint", auth=auth) @@ -141,14 +141,14 @@ def __init__(self, client_id: str, client_secret: str) -> None: client_secret=client_secret, ) - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Add the `client_id` and `client_secret` parameters in the request body. Args: - request: a [requests.PreparedRequest][]. + request: a [niquests.PreparedRequest][]. Returns: - a [requests.PreparedRequest][] with the added client credentials fields. + a [niquests.PreparedRequest][] with the added client credentials fields. """ request = super().__call__(request) @@ -184,14 +184,14 @@ def client_assertion(self, audience: str) -> str: """ raise NotImplementedError - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Add a `client_assertion` field in the request body. Args: - request: a [requests.PreparedRequest][]. + request: a [niquests.PreparedRequest][]. Returns: - a [requests.PreparedRequest][] with the added `client_assertion` field. + a [niquests.PreparedRequest][] with the added `client_assertion` field. """ request = super().__call__(request) @@ -228,7 +228,7 @@ class ClientSecretJwt(BaseClientAssertionAuthenticationMethod): Example: ```python - from requests_oauth2client import OAuth2Client, ClientSecretJwt + from niquests_oauth2client import OAuth2Client, ClientSecretJwt auth = ClientSecretJwt("my_client_id", "my_client_secret") client = OAuth2Client("https://url.to.the/token_endpoint", auth=auth) @@ -327,7 +327,7 @@ class PrivateKeyJwt(BaseClientAssertionAuthenticationMethod): Example: ```python from jwskate import Jwk - from requests_oauth2client import OAuth2Client, PrivateKeyJwt + from niquests_oauth2client import OAuth2Client, PrivateKeyJwt # load your private key from wherever it is stored: with open("my_private_key.pem") as f: @@ -414,7 +414,7 @@ class PublicApp(BaseClientAuthenticationMethod): Example: ```python - from requests_oauth2client import OAuth2Client, PublicApp + from niquests_oauth2client import OAuth2Client, PublicApp auth = PublicApp("my_client_id") client = OAuth2Client("https://url.to.the/token_endpoint", auth=auth) @@ -422,7 +422,7 @@ class PublicApp(BaseClientAuthenticationMethod): """ - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Add the `client_id` field in the request body. Args: @@ -448,13 +448,13 @@ class UnsupportedClientCredentials(TypeError, ValueError): def client_auth_factory( - auth: requests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None, + auth: niquests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None, *, client_id: str | None = None, client_secret: str | None = None, private_key: Jwk | dict[str, Any] | None = None, default_auth_handler: type[ClientSecretPost | ClientSecretBasic | ClientSecretJwt] = ClientSecretPost, -) -> requests.auth.AuthBase: +) -> niquests.auth.AuthBase: """Initialize the appropriate Auth Handler based on the provided parameters. This initializes a `ClientAuthenticationMethod` subclass based on the provided parameters. @@ -462,7 +462,7 @@ def client_auth_factory( Args: auth: can be: - - a `requests.auth.AuthBase` instance (which will be used directly) + - a `niquests.auth.AuthBase` instance (which will be used directly) - a tuple of (client_id, client_secret) which will be used to initialize an instance of `default_auth_handler`, - a tuple of (client_id, jwk), used to initialize a `PrivateKeyJwk` (`jwk` being an @@ -496,7 +496,7 @@ def client_auth_factory( if isinstance(auth, str): client_id = auth - elif isinstance(auth, requests.auth.AuthBase): + elif isinstance(auth, niquests.auth.AuthBase): return auth elif isinstance(auth, tuple) and len(auth) == 2: # noqa: PLR2004 client_id, credential = auth diff --git a/requests_oauth2client/device_authorization.py b/niquests_oauth2client/device_authorization.py similarity index 96% rename from requests_oauth2client/device_authorization.py rename to niquests_oauth2client/device_authorization.py index 84aea8f..dec6e5f 100644 --- a/requests_oauth2client/device_authorization.py +++ b/niquests_oauth2client/device_authorization.py @@ -87,7 +87,7 @@ class DeviceAuthorizationPoolingJob(BaseTokenEndpointPoolingJob): Example: ```python - from requests_oauth2client import DeviceAuthorizationPoolingJob, OAuth2Client + from niquests_oauth2client import DeviceAuthorizationPoolingJob, OAuth2Client client = OAuth2Client(token_endpoint="https://my.as.local/token", auth=("client_id", "client_secret")) pooler = DeviceAuthorizationPoolingJob(client=client, device_code="my_device_code") @@ -126,11 +126,11 @@ def __init__( def token_request(self) -> BearerToken: """Implement the Device Code token request. - This actually calls [OAuth2Client.device_code(device_code)][requests_oauth2client.OAuth2Client.device_code] + This actually calls [OAuth2Client.device_code(device_code)][niquests_oauth2client.OAuth2Client.device_code] on `self.client`. Returns: - a [BearerToken][requests_oauth2client.tokens.BearerToken] + a [BearerToken][niquests_oauth2client.tokens.BearerToken] """ return self.client.device_code(self.device_code, requests_kwargs=self.requests_kwargs, **self.token_kwargs) diff --git a/requests_oauth2client/discovery.py b/niquests_oauth2client/discovery.py similarity index 100% rename from requests_oauth2client/discovery.py rename to niquests_oauth2client/discovery.py diff --git a/requests_oauth2client/dpop.py b/niquests_oauth2client/dpop.py similarity index 95% rename from requests_oauth2client/dpop.py rename to niquests_oauth2client/dpop.py index 8c62ed9..85e9732 100644 --- a/requests_oauth2client/dpop.py +++ b/niquests_oauth2client/dpop.py @@ -5,21 +5,23 @@ import re from datetime import datetime, timedelta, timezone from functools import cached_property -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Sequence +from typing import TYPE_CHECKING, Any, Callable, ClassVar from uuid import uuid4 import jwskate from attrs import define, field, frozen, setters from binapy import BinaPy from furl import furl # type: ignore[import-untyped] -from requests import codes +from niquests import codes from typing_extensions import Self from .tokens import AccessTokenTypes, BearerToken, IdToken, id_token_converter from .utils import accepts_expires_in if TYPE_CHECKING: - import requests + from collections.abc import Sequence + + import niquests class InvalidDPoPAccessToken(ValueError): @@ -59,7 +61,7 @@ def __init__(self, proof: bytes, message: str) -> None: class InvalidUseDPoPNonceResponse(Exception): """Base class for invalid Responses with a `use_dpop_nonce` error.""" - def __init__(self, response: requests.Response, message: str) -> None: + def __init__(self, response: niquests.Response, message: str) -> None: super().__init__(message) self.response = response @@ -67,7 +69,7 @@ def __init__(self, response: requests.Response, message: str) -> None: class MissingDPoPNonce(InvalidUseDPoPNonceResponse): """Raised when a server requests a DPoP nonce but none is provided in its response.""" - def __init__(self, response: requests.Response) -> None: + def __init__(self, response: niquests.Response) -> None: super().__init__( response, "Server requested client to use a DPoP `nonce`, but the `DPoP-Nonce` HTTP header is missing.", @@ -77,7 +79,7 @@ def __init__(self, response: requests.Response) -> None: class RepeatedDPoPNonce(InvalidUseDPoPNonceResponse): """Raised when the server requests a DPoP nonce value that is the same as already included in the request.""" - def __init__(self, response: requests.Response) -> None: + def __init__(self, response: niquests.Response) -> None: super().__init__( response, """\ @@ -132,7 +134,7 @@ def __init__( kwargs=kwargs, ) - def _response_hook(self, response: requests.Response, **kwargs: Any) -> requests.Response: + def _response_hook(self, response: niquests.Response, **kwargs: Any) -> niquests.Response: """Handles a Resource Server provided DPoP nonce.""" if response.status_code == codes.unauthorized and response.headers.get("WWW-Authenticate", "").startswith( "DPoP" @@ -147,7 +149,7 @@ def _response_hook(self, response: requests.Response, **kwargs: Any) -> requests return response - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Add a DPoP proof in each request.""" request = super().__call__(request) add_dpop_proof(request, dpop_key=self.dpop_key, access_token=self.access_token, header_name=self.DPOP_HEADER) @@ -156,7 +158,7 @@ def __call__(self, request: requests.PreparedRequest) -> requests.PreparedReques def add_dpop_proof( - request: requests.PreparedRequest, + request: niquests.PreparedRequest, dpop_key: DPoPKey, access_token: str, header_name: str = "DPoP", @@ -283,7 +285,7 @@ def proof(self, htm: str, htu: str, ath: str | None = None, nonce: str | None = - The `iat` claim will be generated by the configured `iat_generator`, which defaults to current datetime. - The `jti` claim will be generated by the configured `jti_generator`, which defaults to a random UUID4. - The `nonce` claim will be the value stored in the `nonce` attribute. This attribute is updated - automatically when using a `DPoPToken` or one of the provided Authentication handlers as a `requests` + automatically when using a `DPoPToken` or one of the provided Authentication handlers as a `niquests` auth handler. The proof will be signed with the private key of this DPoPKey, using the configured `alg` signature algorithm. @@ -318,7 +320,7 @@ def proof(self, htm: str, htu: str, ath: str | None = None, nonce: str | None = extra_headers={"jwk": self.public_jwk}, ) - def handle_as_provided_dpop_nonce(self, response: requests.Response) -> None: + def handle_as_provided_dpop_nonce(self, response: niquests.Response) -> None: """Handle an Authorization Server response containing a `use_dpop_nonce` error. Args: @@ -332,7 +334,7 @@ def handle_as_provided_dpop_nonce(self, response: requests.Response) -> None: raise RepeatedDPoPNonce(response) self.as_nonce = nonce - def handle_rs_provided_dpop_nonce(self, response: requests.Response) -> None: + def handle_rs_provided_dpop_nonce(self, response: niquests.Response) -> None: """Handle a Resource Server response containing a `use_dpop_nonce` error. Args: diff --git a/requests_oauth2client/exceptions.py b/niquests_oauth2client/exceptions.py similarity index 95% rename from requests_oauth2client/exceptions.py rename to niquests_oauth2client/exceptions.py index b7d4180..2df84d2 100644 --- a/requests_oauth2client/exceptions.py +++ b/niquests_oauth2client/exceptions.py @@ -1,14 +1,14 @@ -"""This module contains all exception classes from `requests_oauth2client`.""" +"""This module contains all exception classes from `niquests_oauth2client`.""" from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: - import requests + import niquests - from requests_oauth2client.authorization_request import AuthorizationRequest - from requests_oauth2client.client import OAuth2Client + from niquests_oauth2client.authorization_request import AuthorizationRequest + from niquests_oauth2client.client import OAuth2Client class OAuth2Error(Exception): @@ -21,14 +21,14 @@ class OAuth2Error(Exception): """ - def __init__(self, response: requests.Response, client: OAuth2Client, description: str | None = None) -> None: + def __init__(self, response: niquests.Response, client: OAuth2Client, description: str | None = None) -> None: super().__init__(f"The remote endpoint returned an error: {description or 'no description provided'}") self.response = response self.client = client self.description = description @property - def request(self) -> requests.PreparedRequest: + def request(self) -> niquests.PreparedRequest: """The request leading to the error.""" return self.response.request @@ -49,7 +49,7 @@ class EndpointError(OAuth2Error): def __init__( self, - response: requests.Response, + response: niquests.Response, client: OAuth2Client, error: str, description: str | None = None, diff --git a/requests_oauth2client/flask/__init__.py b/niquests_oauth2client/flask/__init__.py similarity index 100% rename from requests_oauth2client/flask/__init__.py rename to niquests_oauth2client/flask/__init__.py diff --git a/requests_oauth2client/flask/auth.py b/niquests_oauth2client/flask/auth.py similarity index 95% rename from requests_oauth2client/flask/auth.py rename to niquests_oauth2client/flask/auth.py index c69ed02..011bf27 100644 --- a/requests_oauth2client/flask/auth.py +++ b/niquests_oauth2client/flask/auth.py @@ -6,8 +6,8 @@ from flask import session -from requests_oauth2client.auth import OAuth2ClientCredentialsAuth -from requests_oauth2client.tokens import BearerToken, BearerTokenSerializer +from niquests_oauth2client.auth import OAuth2ClientCredentialsAuth +from niquests_oauth2client.tokens import BearerToken, BearerTokenSerializer class FlaskSessionAuthMixin: diff --git a/requests_oauth2client/pooling.py b/niquests_oauth2client/pooling.py similarity index 86% rename from requests_oauth2client/pooling.py rename to niquests_oauth2client/pooling.py index 1beb9d0..c82a385 100644 --- a/requests_oauth2client/pooling.py +++ b/niquests_oauth2client/pooling.py @@ -21,7 +21,7 @@ class BaseTokenEndpointPoolingJob: This is used for decoupled flows like CIBA or Device Authorization. This class must be subclassed to implement actual BackChannel flows. This needs an - [OAuth2Client][requests_oauth2client.client.OAuth2Client] that will be used to pool the token + [OAuth2Client][niquests_oauth2client.client.OAuth2Client] that will be used to pool the token endpoint. The initial pooling `interval` is configurable. """ @@ -37,13 +37,13 @@ def __call__(self) -> BearerToken | None: Everytime this method is called, it will wait for the entire duration of the pooling interval before calling - [token_request()][requests_oauth2client.pooling.TokenEndpointPoolingJob.token_request]. So + [token_request()][niquests_oauth2client.pooling.TokenEndpointPoolingJob.token_request]. So you can call it immediately after initiating the BackChannel flow, and it will wait before initiating the first call. This implements the logic to handle - [AuthorizationPending][requests_oauth2client.exceptions.AuthorizationPending] or - [SlowDown][requests_oauth2client.exceptions.SlowDown] requests by the AS. + [AuthorizationPending][niquests_oauth2client.exceptions.AuthorizationPending] or + [SlowDown][niquests_oauth2client.exceptions.SlowDown] requests by the AS. Returns: a `BearerToken` if the AS returns one, or `None` if the Authorization is still pending. @@ -85,12 +85,12 @@ def token_request(self) -> BearerToken: """Abstract method for the token endpoint call. Subclasses must implement this. This method must raise - [AuthorizationPending][requests_oauth2client.exceptions.AuthorizationPending] to retry after - the pooling interval, or [SlowDown][requests_oauth2client.exceptions.SlowDown] to increase + [AuthorizationPending][niquests_oauth2client.exceptions.AuthorizationPending] to retry after + the pooling interval, or [SlowDown][niquests_oauth2client.exceptions.SlowDown] to increase the pooling interval by `slow_down_interval` seconds. Returns: - a [BearerToken][requests_oauth2client.tokens.BearerToken] + a [BearerToken][niquests_oauth2client.tokens.BearerToken] """ raise NotImplementedError diff --git a/requests_oauth2client/py.typed b/niquests_oauth2client/py.typed similarity index 100% rename from requests_oauth2client/py.typed rename to niquests_oauth2client/py.typed diff --git a/requests_oauth2client/tokens.py b/niquests_oauth2client/tokens.py similarity index 98% rename from requests_oauth2client/tokens.py rename to niquests_oauth2client/tokens.py index 5953867..e409d92 100644 --- a/requests_oauth2client/tokens.py +++ b/niquests_oauth2client/tokens.py @@ -6,10 +6,10 @@ from enum import Enum from functools import cached_property from math import ceil -from typing import TYPE_CHECKING, Any, Callable, ClassVar, Sequence +from typing import TYPE_CHECKING, Any, Callable, ClassVar import jwskate -import requests +import niquests from attrs import asdict, frozen from binapy import BinaPy from typing_extensions import Self @@ -17,6 +17,8 @@ from .utils import accepts_expires_in if TYPE_CHECKING: + from collections.abc import Sequence + from .authorization_request import AuthorizationResponse from .client import OAuth2Client @@ -248,7 +250,7 @@ def id_token_converter( @frozen(init=False) -class BearerToken(TokenResponse, requests.auth.AuthBase): +class BearerToken(TokenResponse, niquests.auth.AuthBase): """Represents a Bearer Token as returned by a Token Endpoint. This is a wrapper around a Bearer Token and associated parameters, such as expiration date and @@ -564,13 +566,13 @@ def __getattr__(self, key: str) -> Any: """ return self.kwargs.get(key) or super().__getattribute__(key) - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: """Implement the usage of Bearer Tokens in requests. This will add a properly formatted `Authorization: Bearer ` header in the request. If the configured token is an instance of BearerToken with an expires_at attribute, raises - [ExpiredAccessToken][requests_oauth2client.exceptions.ExpiredAccessToken] once the access + [ExpiredAccessToken][niquests_oauth2client.exceptions.ExpiredAccessToken] once the access token is expired. Args: diff --git a/requests_oauth2client/utils.py b/niquests_oauth2client/utils.py similarity index 97% rename from requests_oauth2client/utils.py rename to niquests_oauth2client/utils.py index a2d7f4e..ce22abe 100644 --- a/requests_oauth2client/utils.py +++ b/niquests_oauth2client/utils.py @@ -9,10 +9,13 @@ from contextlib import suppress from datetime import datetime, timedelta, timezone from functools import wraps -from typing import Any, Callable, Iterator +from typing import TYPE_CHECKING, Any, Callable from furl import furl # type: ignore[import-untyped] +if TYPE_CHECKING: + from collections.abc import Iterator + class InvalidUri(ValueError): """Raised when a URI does not pass validation by `validate_endpoint_uri()`.""" diff --git a/requests_oauth2client/vendor_specific/__init__.py b/niquests_oauth2client/vendor_specific/__init__.py similarity index 78% rename from requests_oauth2client/vendor_specific/__init__.py rename to niquests_oauth2client/vendor_specific/__init__.py index 2107f50..eb4dc29 100644 --- a/requests_oauth2client/vendor_specific/__init__.py +++ b/niquests_oauth2client/vendor_specific/__init__.py @@ -1,6 +1,6 @@ """Vendor-specific utilities. -This module contains vendor-specific subclasses of [requests_oauth2client] classes, that make it easier to work with +This module contains vendor-specific subclasses of [niquests_oauth2client] classes, that make it easier to work with specific OAuth 2.x providers and/or fix compatibility issues. """ diff --git a/requests_oauth2client/vendor_specific/auth0.py b/niquests_oauth2client/vendor_specific/auth0.py similarity index 84% rename from requests_oauth2client/vendor_specific/auth0.py rename to niquests_oauth2client/vendor_specific/auth0.py index 5354c84..9e35edb 100644 --- a/requests_oauth2client/vendor_specific/auth0.py +++ b/niquests_oauth2client/vendor_specific/auth0.py @@ -4,10 +4,10 @@ from typing import TYPE_CHECKING, Any -from requests_oauth2client import ApiClient, OAuth2Client, OAuth2ClientCredentialsAuth +from niquests_oauth2client import ApiClient, OAuth2Client, OAuth2ClientCredentialsAuth if TYPE_CHECKING: - import requests + import niquests from jwskate import Jwk @@ -39,13 +39,13 @@ def client( cls, tenant: str, auth: ( - requests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None + niquests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None ) = None, *, client_id: str | None = None, client_secret: str | None = None, private_jwk: Any | None = None, - session: requests.Session | None = None, + session: niquests.Session | None = None, **kwargs: Any, ) -> OAuth2Client: """Initialise an OAuth2Client for an Auth0 tenant.""" @@ -77,13 +77,13 @@ def management_api_client( cls, tenant: str, auth: ( - requests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None + niquests.auth.AuthBase | tuple[str, str] | tuple[str, Jwk] | tuple[str, dict[str, Any]] | str | None ) = None, *, client_id: str | None = None, client_secret: str | None = None, private_jwk: Any | None = None, - session: requests.Session | None = None, + session: niquests.Session | None = None, **kwargs: Any, ) -> ApiClient: """Initialize a client for the Auth0 Management API. @@ -94,22 +94,22 @@ def management_api_client( Args: tenant: the tenant name. - Same definition as for [Auth0.client][requests_oauth2client.vendor_specific.auth0.Auth0.client] + Same definition as for [Auth0.client][niquests_oauth2client.vendor_specific.auth0.Auth0.client] auth: client credentials. - Same definition as for [OAuth2Client][requests_oauth2client.client.OAuth2Client] + Same definition as for [OAuth2Client][niquests_oauth2client.client.OAuth2Client] client_id: the Client ID. - Same definition as for [OAuth2Client][requests_oauth2client.client.OAuth2Client] + Same definition as for [OAuth2Client][niquests_oauth2client.client.OAuth2Client] client_secret: the Client Secret. - Same definition as for [OAuth2Client][requests_oauth2client.client.OAuth2Client] + Same definition as for [OAuth2Client][niquests_oauth2client.client.OAuth2Client] private_jwk: the private key to use for client authentication. - Same definition as for [OAuth2Client][requests_oauth2client.client.OAuth2Client] - session: requests session. - Same definition as for [OAuth2Client][requests_oauth2client.client.OAuth2Client] + Same definition as for [OAuth2Client][niquests_oauth2client.client.OAuth2Client] + session: niquests Session. + Same definition as for [OAuth2Client][niquests_oauth2client.client.OAuth2Client] **kwargs: additional kwargs to pass to the ApiClient base class Example: ```python - from requests_oauth2client.vendor_specific import Auth0 + from niquests_oauth2client.vendor_specific import Auth0 a0mgmt = Auth0.management_api_client("mytenant.eu", client_id=client_id, client_secret=client_secret) users = a0mgmt.get("users", params={"page": 0, "per_page": 100}) diff --git a/requests_oauth2client/vendor_specific/ping.py b/niquests_oauth2client/vendor_specific/ping.py similarity index 91% rename from requests_oauth2client/vendor_specific/ping.py rename to niquests_oauth2client/vendor_specific/ping.py index 414345a..ab09076 100644 --- a/requests_oauth2client/vendor_specific/ping.py +++ b/niquests_oauth2client/vendor_specific/ping.py @@ -4,9 +4,9 @@ from typing import Any -import requests # noqa: TCH002 +import niquests # noqa: TC002 -from requests_oauth2client import OAuth2Client +from niquests_oauth2client import OAuth2Client class Ping: @@ -16,11 +16,11 @@ class Ping: def client( cls, issuer: str, - auth: requests.auth.AuthBase | tuple[str, str] | str | None = None, + auth: niquests.auth.AuthBase | tuple[str, str] | str | None = None, client_id: str | None = None, client_secret: str | None = None, private_jwk: Any = None, - session: requests.Session | None = None, + session: niquests.Session | None = None, ) -> OAuth2Client: """Initialize an OAuth2Client for PingFederate. diff --git a/poetry.lock b/poetry.lock index 535006c..ece4aa0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "astunparse" @@ -6,6 +6,8 @@ version = "1.6.3" description = "An AST unparser for Python" optional = false python-versions = "*" +groups = ["dev"] +markers = "python_version < \"3.9\"" files = [ {file = "astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8"}, {file = "astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872"}, @@ -21,6 +23,7 @@ version = "25.1.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"}, {file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"}, @@ -40,6 +43,7 @@ version = "2.16.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, @@ -57,6 +61,7 @@ version = "0.8.0" description = "Binary Data manipulation, for humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "binapy-0.8.0-py3-none-any.whl", hash = "sha256:8af1e1e856900ef8b79ef32236e296127c9cf26414ec355982ff7ce5f173504d"}, {file = "binapy-0.8.0.tar.gz", hash = "sha256:570c5098d42f037ffb3d2e563998f3cff69ad25ca1f43f9c3815432dccd08233"}, @@ -71,6 +76,7 @@ version = "1.8.2" description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, @@ -82,6 +88,7 @@ version = "2.5.post1" description = "Bash style brace expander." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "bracex-2.5.post1-py3-none-any.whl", hash = "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6"}, {file = "bracex-2.5.post1.tar.gz", hash = "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6"}, @@ -89,25 +96,28 @@ files = [ [[package]] name = "cachetools" -version = "5.5.0" +version = "5.5.1" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, + {file = "cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb"}, + {file = "cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95"}, ] [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] +markers = {main = "platform_python_implementation != \"CPython\" or platform_system != \"Darwin\" and platform_system != \"Windows\" and platform_system != \"Linux\" or platform_machine != \"x86_64\" and platform_machine != \"s390x\" and platform_machine != \"aarch64\" and platform_machine != \"armv7l\" and platform_machine != \"ppc64le\" and platform_machine != \"ppc64\" and platform_machine != \"AMD64\" and platform_machine != \"arm64\" and platform_machine != \"ARM64\" and platform_machine != \"i686\" and platform_machine != \"x86\""} [[package]] name = "cffi" @@ -115,6 +125,8 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -194,6 +206,7 @@ version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -205,6 +218,7 @@ version = "5.2.0" description = "Universal encoding detector for Python 3" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, @@ -212,112 +226,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +python-versions = ">=3.7" +groups = ["main", "dev"] +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -329,6 +347,7 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -340,6 +359,7 @@ version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, @@ -423,38 +443,39 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" -files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, +groups = ["main"] +files = [ + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] @@ -467,18 +488,19 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["dev"] files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -487,6 +509,8 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -501,6 +525,7 @@ version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, @@ -517,6 +542,7 @@ version = "3.0.3" description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, @@ -540,6 +566,7 @@ version = "1.5.1" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, @@ -554,6 +581,7 @@ version = "2.1.3" description = "URL manipulation made simple." optional = false python-versions = "*" +groups = ["main"] files = [ {file = "furl-2.1.3-py2.py3-none-any.whl", hash = "sha256:9ab425062c4217f9802508e45feb4a83e54324273ac4b202f1850363309666c0"}, {file = "furl-2.1.3.tar.gz", hash = "sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e"}, @@ -569,6 +597,7 @@ version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, @@ -582,25 +611,39 @@ dev = ["flake8", "markdown", "twine", "wheel"] [[package]] name = "griffe" -version = "1.3.2" +version = "1.4.0" description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "griffe-1.3.2-py3-none-any.whl", hash = "sha256:2e34b5e46507d615915c8e6288bb1a2234bd35dee44d01e40a2bc2f25bd4d10c"}, - {file = "griffe-1.3.2.tar.gz", hash = "sha256:1ec50335aa507ed2445f2dd45a15c9fa3a45f52c9527e880571dfc61912fd60c"}, + {file = "griffe-1.4.0-py3-none-any.whl", hash = "sha256:e589de8b8c137e99a46ec45f9598fc0ac5b6868ce824b24db09c02d117b89bc5"}, + {file = "griffe-1.4.0.tar.gz", hash = "sha256:8fccc585896d13f1221035d32c50dec65830c87d23f9adb9b1e6f3d63574f7f5"}, ] [package.dependencies] astunparse = {version = ">=1.6", markers = "python_version < \"3.9\""} colorama = ">=0.4" +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + [[package]] name = "identify" version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, @@ -615,6 +658,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main", "dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -629,6 +673,8 @@ version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.10\"" files = [ {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, @@ -652,6 +698,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -663,17 +710,112 @@ version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] +[[package]] +name = "jh2" +version = "5.0.7" +description = "HTTP/2 State-Machine based protocol implementation" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "jh2-5.0.7-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0169129c5bf5ac63a03dc5fc1dae6f54cd8914f2c4b67259b5b198e6a00068e6"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fd88f0945cbf7587bbbe3c58d04e0fb4445c0441a1cc200212c47987a14d326"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:01d16f47fa5893ab9895b05e5247e904b23d9ecbd8ad234d1897605d5c54a92a"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3b1b900cce69fed2a56cda58f595413dfe6155857ba9d59b56ffa5487a3e17ca"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28131ee9ce9fe0b8eaaad6ca51b678fcc2b0051413ea5b7eea43c7a04cf9bca6"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:95bdd534ac2c402c4f0011a5f0ea9d9785676dcf60da1353876f6a5afebac7f9"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b825d5b6d1569ef4d051e3817437dab490c8caad485347a9f006899826f45d7b"}, + {file = "jh2-5.0.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d803f0f7ddae471cb2155f276aedbc0bd52deba0fc960e4d605f64d7312fd4d0"}, + {file = "jh2-5.0.7-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:e66cf7d5ab4c93fba7d559baad9d642cebd4eac08e46ee8da732d3982575a338"}, + {file = "jh2-5.0.7-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:92a0ad8fe9aa0c3e99ade75f90d9c2c09b229ede7113085c289fc851654697bb"}, + {file = "jh2-5.0.7-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:4fd259269d5a949709f67919b5f13a8331f6da0786c5bca87bcbfa7620aa0b73"}, + {file = "jh2-5.0.7-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:a4ebeda6f3c92f88f11b8ae346159be5ea1b6a73721dbf0feb5bca8234f4f7a9"}, + {file = "jh2-5.0.7-cp313-cp313t-win_amd64.whl", hash = "sha256:8cc1cadc3c6fab8e13d5a9f1cbde7d9302b4afa3cbada247b78a5e30139b1627"}, + {file = "jh2-5.0.7-cp313-cp313t-win_arm64.whl", hash = "sha256:9739dc3117fb5d73795d119fcd9f9b3b779c7b8e38bac1b11488a6acb14321e9"}, + {file = "jh2-5.0.7-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:67daae8e65ffc1056334baba37e22c3a8613537d7cdf1381d4b0fdb761218830"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:453a5839a44a3b440a3874e4e102daaada8007c85e97ce4c5dd395be2aa5c6c1"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0f8907e411d4b53696057dd40f4cd21737fa496e002d85e0ce9bb515e72cf437"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:97670d3fca15065a424aacc2140621d2140e51713338bb534b49a1016c9dce15"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3cd4fc574f919af08c6416f5e98c89e865e6f3a1be03ca5521b147eddbf6d07"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d59432b0dd1f6497d2abd9a1fe5f3f34f9756b3329e9cd5fb8813eee3f66fac0"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ee73da75e63b66083e3b4f2c7deb529b864b92516d6f61ec1b5991096aeb49"}, + {file = "jh2-5.0.7-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e598677cd1b7c09154871c7f4df025de62cdf5467a4e803912d00a6ad3f1060"}, + {file = "jh2-5.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:18676b0567a820c75c3afc6491d406a61edcc37eab82a447473e2ce34495253c"}, + {file = "jh2-5.0.7-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:77715d04a1aea8919118046bf3aa8df006165a159dd8c629b5fba291d6a8214b"}, + {file = "jh2-5.0.7-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:4be38b0e498fa44a36a7668155a8e90f74e1c3f048fb20f9edd9ce441fc00d6a"}, + {file = "jh2-5.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:37ecd88972251af832813e92f83855fd35dbe281530e92e72dff064be1760554"}, + {file = "jh2-5.0.7-cp37-abi3-win32.whl", hash = "sha256:a0f76dcbc77fb963b65a5fb92b330068b03cb982e1b9ec382e86f31dbf1cfdbb"}, + {file = "jh2-5.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:ac787243ee402f89f35f9c7b66c5c7ab4c8fae4a8a6cabe35c73c5b83ef60347"}, + {file = "jh2-5.0.7-cp37-abi3-win_arm64.whl", hash = "sha256:1fb074194ecf73c85ddbd0d7326fa63ca52cb87b2b98d89080b9fab0da2830c4"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e183600bf0bff33d0b685d2d9ee064066b887595c144814eb648830a092f1f46"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8cadf59f4df736b99ad7d3e92eb1f63b6563c9d9afca4b8924f143c99c22d61"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ca0e3d3753fdbab666fbb05f9043a30e984c65f042686c9a03fa979b25c274c"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5e8fc7f4bb4921e9b226bb1559a86538f8230b7144b5fd11c288898bcee5aa01"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57922ec48ec051a21b8f09858ac051b640a4b9bf70c4eee77d1bf7d48bd08c0"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b3ebee393cefef9eb973a70afda06e51226ea2156901e2b09a1d68db3d55ad52"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54a099cfd88a26dc800dbb0dec05b79d6018f4a57a32db2260b92a0c985c450c"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f5232ee6508d8365f0e75f537208ffabfbb989da4f7ea029142626d36c00f189"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1e470ca5f917050d3b7c77da160718324bbba44749aa778474c4fc0071a44a25"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:93eb686fecf531b32912d9b3332edb74514fba1e8865e39c5f651e6e8eabcc58"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-musllinux_1_1_i686.whl", hash = "sha256:cb46c799f3990f89859950a83103104b4b5704645cfaaca074c591da5e098a7c"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1d2ca5f02fc5b9fbe622c9ec3a3803d39be5b3b9f929d4160a13095fa7d36d57"}, + {file = "jh2-5.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3f68fa5457111be93de9193da46d209515aba721cae5fa5feca7e8b5791d75bd"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:516488cbe98dc66d78daaba68e2842c5b463db77282f14feae3e8bd71e2b0e10"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db1e1bd833eb12bb356ad1abaf6d8d4d973f14286efdc2461d41c14f15e42b05"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee6138ca5c7946ab8d33d7598b481d1dd2469bea32419ce4ca3636949756571f"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3f876d92d69ad4a2db30a7735cab23c7686abc983ee08e7187d969bb18e51371"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbfff38ecb770be9fcb8cacb637cab376cb7c142c8baead17c180ab0f487c2cf"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae0acb5c3a8ee4029ad4f0121deb45520c592889d8b2cab1d851be05e855d90c"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:483c8756259b3875dec6a30b397dacfe21a0cc0d7ff1e2f89291b0ffc48e5048"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:06385087493c611ce5fdcd2b0bfcd79e28ad90e925210eea8aa2ef8c49e1c8f3"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:b53f2c8a176eb0c6250439ef5c74ff5db76dd1b68768863a4792e4a2bf70d4df"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0d7b230e6920bed516695d99190d7bb018c1820c3ae0d42cf356f635b563dc9b"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-musllinux_1_1_i686.whl", hash = "sha256:0089e99a25d0f51dabce5d16f25f9124866c05cd0704c58fd0272dd4e9b98704"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3f80e86dc0208a61e1f562f49d6897502915d9d4384e47f639819069ca64b9a3"}, + {file = "jh2-5.0.7-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:452b22dd68075edfa18f52fe59cd6ef5352d67ed90252146072d5ce227d2e9bd"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:54c3457255d595fefb17058b8c2faa482185ff975d6fedf08b72c14acf69a887"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c203d532f33f13dfee3f7a5b3de06ddb9b4456acf30cc3483d32133a331f980a"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b0ca409def15e4771dc31a595b17172f5b937e6ed354307480f106f9d12fdf33"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4ae4f1c7075419bc64dbad982879a1789447be6d1f240bb886a50b8aad1ba4e3"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4baf9c74d652f13f7534a520ac219a6d696403008185f3e3ad3c430946012515"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33a402735914c4738b3367cdcbae2f8252124bd4785195c93e9094af81154fe9"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8aa5a6049c42d422212860f4c3a318a5d4bd9746ececf4c84464620ffbd62692"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1f8bf24a48cf4232edb29bf2696156a2a038c61ae67fe69d86f10ba94044b09"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c172f967b859421be0fe9b64016993dcca618b4c3e1a2984b110bcec336c0094"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:b2d9e2248a6cda9aea283b8701d31ac6176b5cc1fc7339049d2792ff3b491285"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-musllinux_1_1_i686.whl", hash = "sha256:b0a73042388e0f256118693546785751bdd307193b586573a1f773655deddadf"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76635946a86d3ea3bd72a6d2c477ea79180918c586dcf21af69516709ac7ca6a"}, + {file = "jh2-5.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:015cdad0ae01a33b2ca1895191b0621e5c2a5f9c67f0dd35662b0b224ffbe93e"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:10316279534b209a9d2cebd102af090d5e804ad6201eb52e977618a587da4e0c"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2627b4336d26785b43e53a647f47c014fddeb3a2171b1398bf4ac4193d2fee08"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:40de7a5e45cff971dadd285f2f9fa854e6c5f863ea3225d3426cdfa39fe9a100"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6b0a0e7ad1369b0cda2431674e9d8182ff617650b86fbb75498613b2452a6cb5"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a381975fbddbb49868e3fa9805cfd2ca91df4c5afcdad3e7cf50fbc58b9f914c"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67ef17c823ed05c1fad403930509c48a87d6f41202aa250d491e4ecd9161048d"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40d4c7f6d053bb7a89769510ea8b06e91cb1075311dbdb65981703350bad7b7e"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7e49e998571c0f5e766407890c2fb71d1929bed30829743cfea89cd3576d2f37"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d0e433c45b812a2c6b5726ccd949abb9fc17da1d322136d73ac76f86137637a5"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d79c4e59b50a66f0139b5fefc9d14b9574518c7a1d3cf915908d8323f0476c41"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-musllinux_1_1_i686.whl", hash = "sha256:bebdb1418f4f3d0f7f1d94db9d8edd6bcc1c4f3ce3473080fa9e94de46269d75"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:42a8667352102099bdc3fa7319e21e3eecf3ffddf7db217a8a24d0838d900ae9"}, + {file = "jh2-5.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8a47fdbebd616dff1b0290277ee04140faf2f19d4c5b4e36335c044253d66ec9"}, + {file = "jh2-5.0.7-py3-none-any.whl", hash = "sha256:9234c2f9cda5a0e552e13813aa04977c0f844f2a1fea0e9b42039f86442b6e78"}, + {file = "jh2-5.0.7.tar.gz", hash = "sha256:43d56326d950aae3a0e7f3ebd51bc16c7c9350b3be12e8ca6cf0ed78d4ccaa57"}, +] + [[package]] name = "jinja2" version = "3.1.5" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"}, {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"}, @@ -691,6 +833,7 @@ version = "0.11.1" description = "A Pythonic implementation of the JOSE / JSON Web Crypto related RFCs (JWS, JWK, JWA, JWT, JWE)" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "jwskate-0.11.1-py3-none-any.whl", hash = "sha256:cdfa04fac10366afab08c20d2f75d1c6b57dc7d099b407b8fb4318349272f933"}, {file = "jwskate-0.11.1.tar.gz", hash = "sha256:35354b487c8e835fdd57befea5e93e9e52fe25869d884fc764511d22061e6685"}, @@ -701,12 +844,25 @@ binapy = ">=0.8" cryptography = ">=3.4" typing-extensions = ">=4.3" +[[package]] +name = "kiss-headers" +version = "2.5.0" +description = "Object-oriented HTTP and IMAP (structured) headers." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "kiss_headers-2.5.0-py3-none-any.whl", hash = "sha256:db49d2e906aa1da7a7bb98357f4c21aa857dc6ed426753d9d90c527eb1b7aa6a"}, + {file = "kiss_headers-2.5.0.tar.gz", hash = "sha256:63ce797b6d85763d4b0e9611bd62d30fe31b0c4edb601838e76a039e4a4cdb59"}, +] + [[package]] name = "livereload" version = "2.7.1" description = "Python LiveReload is an awesome tool for web developers" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564"}, {file = "livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9"}, @@ -721,6 +877,7 @@ version = "3.7" description = "Python implementation of John Gruber's Markdown." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, @@ -739,6 +896,7 @@ version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, @@ -808,6 +966,7 @@ version = "1.3.4" description = "A deep merge function for 🐍." optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, @@ -819,6 +978,7 @@ version = "1.6.1" description = "Project documentation with Markdown." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, @@ -850,6 +1010,7 @@ version = "1.2.0" description = "Automatically link across pages in MkDocs." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocs_autorefs-1.2.0-py3-none-any.whl", hash = "sha256:d588754ae89bd0ced0c70c06f58566a4ee43471eeeee5202427da7de9ef85a2f"}, {file = "mkdocs_autorefs-1.2.0.tar.gz", hash = "sha256:a86b93abff653521bda71cf3fc5596342b7a23982093915cb74273f67522190f"}, @@ -866,6 +1027,7 @@ version = "0.2.0" description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, @@ -883,6 +1045,7 @@ version = "6.2.2" description = "Mkdocs Markdown includer plugin." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocs_include_markdown_plugin-6.2.2-py3-none-any.whl", hash = "sha256:d293950f6499d2944291ca7b9bc4a60e652bbfd3e3a42b564f6cceee268694e7"}, {file = "mkdocs_include_markdown_plugin-6.2.2.tar.gz", hash = "sha256:f2bd5026650492a581d2fd44be6c22f90391910d76582b96a34c264f2d17875d"}, @@ -901,6 +1064,7 @@ version = "9.5.50" description = "Documentation that simply works" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocs_material-9.5.50-py3-none-any.whl", hash = "sha256:f24100f234741f4d423a9d672a909d859668a4f404796be3cf035f10d6050385"}, {file = "mkdocs_material-9.5.50.tar.gz", hash = "sha256:ae5fe16f3d7c9ccd05bb6916a7da7420cf99a9ce5e33debd9d40403a090d5825"}, @@ -930,6 +1094,7 @@ version = "1.3.1" description = "Extension pack for Python Markdown and MkDocs Material." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, @@ -941,6 +1106,7 @@ version = "0.26.1" description = "Automatic documentation from sources, for MkDocs." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocstrings-0.26.1-py3-none-any.whl", hash = "sha256:29738bfb72b4608e8e55cc50fb8a54f325dc7ebd2014e4e3881a49892d5983cf"}, {file = "mkdocstrings-0.26.1.tar.gz", hash = "sha256:bb8b8854d6713d5348ad05b069a09f3b79edbc6a0f33a34c6821141adb03fe33"}, @@ -970,6 +1136,7 @@ version = "1.11.1" description = "A Python handler for mkdocstrings." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mkdocstrings_python-1.11.1-py3-none-any.whl", hash = "sha256:a21a1c05acef129a618517bb5aae3e33114f569b11588b1e7af3e9d4061a71af"}, {file = "mkdocstrings_python-1.11.1.tar.gz", hash = "sha256:8824b115c5359304ab0b5378a91f6202324a849e1da907a3485b59208b797322"}, @@ -986,6 +1153,7 @@ version = "1.14.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"}, {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"}, @@ -1045,17 +1213,45 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "niquests" +version = "3.12.2" +description = "Niquests is a simple, yet elegant, HTTP library. It is a drop-in replacement for Requests, which is under feature freeze." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "niquests-3.12.2-py3-none-any.whl", hash = "sha256:5424354502a90619f183e33ce7682be8ec6d2d670b74cab65a2e7f4fb01bb9a4"}, + {file = "niquests-3.12.2.tar.gz", hash = "sha256:9b3e7dbdfa8aebf7014f5ec308544e7324765ca775b35a74ada31163682dd8e2"}, +] + +[package.dependencies] +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +kiss-headers = ">=2,<4" +urllib3-future = ">=2.12.900,<3" +wassima = ">=1.0.1,<2" + +[package.extras] +http3 = ["urllib3-future[qh3]"] +ocsp = ["urllib3-future[qh3]"] +socks = ["urllib3-future[socks]"] +speedups = ["orjson (>=3,<4)", "urllib3-future[brotli,zstd]"] +ws = ["urllib3-future[ws]"] + [[package]] name = "nodeenv" version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1067,6 +1263,7 @@ version = "1.0.1" description = "Ordered Multivalue Dictionary" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "orderedmultidict-1.0.1-py2.py3-none-any.whl", hash = "sha256:43c839a17ee3cdd62234c47deca1a8508a3f2ca1d0678a3bf791c87cf84adbf3"}, {file = "orderedmultidict-1.0.1.tar.gz", hash = "sha256:04070bbb5e87291cc9bfa51df413677faf2141c73c61d2a5f7b26bea3cd882ad"}, @@ -1081,6 +1278,7 @@ version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1092,6 +1290,7 @@ version = "0.5.7" description = "Divides large result sets into pages for easier browsing" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, @@ -1107,6 +1306,7 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -1118,6 +1318,7 @@ version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, @@ -1134,6 +1335,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -1149,6 +1351,7 @@ version = "3.5.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, @@ -1167,6 +1370,8 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -1174,13 +1379,14 @@ files = [ [[package]] name = "pygments" -version = "2.18.0" +version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, ] [package.extras] @@ -1188,13 +1394,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pymdown-extensions" -version = "10.11.2" +version = "10.14.1" description = "Extension pack for Python Markdown." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "pymdown_extensions-10.11.2-py3-none-any.whl", hash = "sha256:41cdde0a77290e480cf53892f5c5e50921a7ee3e5cd60ba91bf19837b33badcf"}, - {file = "pymdown_extensions-10.11.2.tar.gz", hash = "sha256:bc8847ecc9e784a098efd35e20cba772bc5a1b529dfcef9dc1972db9021a1049"}, + {file = "pymdown_extensions-10.14.1-py3-none-any.whl", hash = "sha256:637951cbfbe9874ba28134fb3ce4b8bcadd6aca89ac4998ec29dcbafd554ae08"}, + {file = "pymdown_extensions-10.14.1.tar.gz", hash = "sha256:b65801996a0cd4f42a3110810c306c45b7313c09b0610a6f773730f2a9e3c96b"}, ] [package.dependencies] @@ -1202,7 +1409,7 @@ markdown = ">=3.6" pyyaml = "*" [package.extras] -extra = ["pygments (>=2.12)"] +extra = ["pygments (>=2.19.1)"] [[package]] name = "pyproject-api" @@ -1210,6 +1417,7 @@ version = "1.8.0" description = "API to interact with the python pyproject.toml based projects" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pyproject_api-1.8.0-py3-none-any.whl", hash = "sha256:3d7d347a047afe796fd5d1885b1e391ba29be7169bd2f102fcd378f04273d228"}, {file = "pyproject_api-1.8.0.tar.gz", hash = "sha256:77b8049f2feb5d33eefcc21b57f1e279636277a8ac8ad6b5871037b243778496"}, @@ -1229,6 +1437,7 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -1251,6 +1460,7 @@ version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, @@ -1269,6 +1479,7 @@ version = "0.4.9" description = "Pytest plugin providing a fixture interface for spulec/freezegun" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "pytest_freezer-0.4.9-py3-none-any.whl", hash = "sha256:8b6c50523b7d4aec4590b52bfa5ff766d772ce506e2bf4846c88041ea9ccae59"}, {file = "pytest_freezer-0.4.9.tar.gz", hash = "sha256:21bf16bc9cc46bf98f94382c4b5c3c389be7056ff0be33029111ae11b3f1c82a"}, @@ -1284,6 +1495,7 @@ version = "3.14.0" description = "Thin-wrapper around the mock package for easier use with pytest" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, @@ -1301,6 +1513,7 @@ version = "0.10.3" description = "Mypy static type checker plugin for Pytest" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "pytest-mypy-0.10.3.tar.gz", hash = "sha256:f8458f642323f13a2ca3e2e61509f7767966b527b4d8adccd5032c3e7b4fd3db"}, {file = "pytest_mypy-0.10.3-py3-none-any.whl", hash = "sha256:7638d0d3906848fc1810cb2f5cc7fceb4cc5c98524aafcac58f28620e3102053"}, @@ -1325,6 +1538,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -1339,6 +1553,8 @@ version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" +groups = ["dev"] +markers = "python_version < \"3.9\"" files = [ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, @@ -1350,6 +1566,7 @@ version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, @@ -1412,6 +1629,7 @@ version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, @@ -1420,107 +1638,201 @@ files = [ [package.dependencies] pyyaml = "*" +[[package]] +name = "qh3" +version = "1.3.2" +description = "A lightway and fast implementation of QUIC and HTTP/3" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "(platform_system == \"Darwin\" or platform_system == \"Windows\" or platform_system == \"Linux\") and (platform_machine == \"x86_64\" or platform_machine == \"s390x\" or platform_machine == \"aarch64\" or platform_machine == \"armv7l\" or platform_machine == \"ppc64le\" or platform_machine == \"ppc64\" or platform_machine == \"AMD64\" or platform_machine == \"arm64\" or platform_machine == \"ARM64\" or platform_machine == \"x86\" or platform_machine == \"i686\") and (platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\") and (python_version < \"3.11\" or platform_python_implementation == \"CPython\") and (python_version >= \"3.10\" or platform_python_implementation == \"CPython\" or platform_python_implementation == \"PyPy\")" +files = [ + {file = "qh3-1.3.2-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:300d642a5efac25da22d412c6fe9598c89d92f9b4012b39a8e35f542626eb0d0"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03cdfa201b0ee829ff2d935998d10f4e8d726e29c1da2f86e73cfb7e9e54dd1f"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4586bcc1474ce3f957ccb83cd2f6409f856d82d24ff39876a7766ba03657f282"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c3f48f534e836198f956dd374d452ba2429622211f21140b60a7951d08282ba"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7bf0f18f5ec10dbf1ff7b7651acbab913c8d7eebce6488f1655902acf1d713a3"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1627956667aed27192394ff5c1c84d9b8dc78309f7546cea7a9e3dacd58cd5b"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fed209c5b79d0974958143adb819717708b6de42325b7e97cdcb4ce24a63effd"}, + {file = "qh3-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c8f1dea6da5c187aa57cf8707f374f19cb507754fd9a5a07fe70cb3dc14c0e"}, + {file = "qh3-1.3.2-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:37d87cf65d6a69ffbb40b3bdd39dabd88cb1f1f6b33debb6ed4abd7c10918226"}, + {file = "qh3-1.3.2-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:26a90948501fb70cd37cdfed899c4389a5fbd5468e40b8617eb86b0b47128be1"}, + {file = "qh3-1.3.2-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:f6d572acdfd1dcf4464d64681df6b8158c3a9dd4fbc459a5aa5c8748f104c9ba"}, + {file = "qh3-1.3.2-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d551a90149e6b63a9565bb82d0b14c70e9fe107d0d3bc4c63ae49ae34d3b3f9d"}, + {file = "qh3-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:87925d9a63eac1c9e572691bc150245d954dccbdf400e5bb5ab9749ac010b60e"}, + {file = "qh3-1.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:e64cdee9f3ec91c1ebdc1c78afc4f747ce2e22af61027fa56d2aee8b3902c6d8"}, + {file = "qh3-1.3.2-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e2d446a3a135d36e9811e50f1539f036b811de379384def3f4a82881923d50c8"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9ca3b52d86e216d0de72b63a73cc20d0e78eb797e738384ec99d3616832811"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab6e3ace7bbed2fe4e24e6bc3896231f1eef33fa577895d3a7aac8978c0dd339"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e043587801090bf7778269e2585b94fb3dac3065f69eb1ad480fe954bc8e0ed0"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:862947a5fc5a94bced11061548b672b09081173fe9452f115952f40535c61121"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ab407ecc2321b34f9c4ecf193cee73d5f52f7fd0eab08a9e58a1a83edbeaa10"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9f5aba10c0b9744cd91a30eb44129061f207a4993440439370c291c3dfc4a7e"}, + {file = "qh3-1.3.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30024dcc5fdf0a17b440e27f54503d22116f045bfe863a267ff31aa16a5c5836"}, + {file = "qh3-1.3.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3c208d0dc37320ca2d2b623a87a1ab62772d13b1b88f713c9a3952037c62ca8a"}, + {file = "qh3-1.3.2-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:981228842875f2cd4c509e471be60b5ce4dcac62d7861f501ac63faff1b54e06"}, + {file = "qh3-1.3.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:bfb55fbd7b09f71e7d1335856ada0df8abec72399d6b9cdc2a0966cbedb3f034"}, + {file = "qh3-1.3.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ed2af3eb9f2024891bab637dbacfbff1526a08a8a3d07aa2f14db5262b40f4b6"}, + {file = "qh3-1.3.2-cp37-abi3-win32.whl", hash = "sha256:b9ddedc38f0f7ef0b4f49632514a0d528eb2b99fd4b04e4b53e554d132fac7e8"}, + {file = "qh3-1.3.2-cp37-abi3-win_amd64.whl", hash = "sha256:00df3e8169c46ca3bd3f8a4f4a85c51c8c97835eb9d8fa9aadd8a0848b6a2500"}, + {file = "qh3-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:3a35e7973c9d3224604064bf045ef0eddd31274b254443e3b810f3be57d47b17"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:1bf9b936c0587aef41323e48d09c738dc96dd9631ec2f27b3b2108c58f0a8752"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d53332a1591f0f06ae1cf67646c2a5b4fa60f2a207d25655af5e4ac63c6110c"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f71e296fe5c3c2647e6de7a143213f7c60ff986fa36e1ae07f8b7761cc80329b"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01bc15aba2c8e38e752d6e765156fe06ce790a1e639ca25318a34d65854089f6"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9c2d223795bad8bfc54961bd8d3f024e4e70e45232cfa7a070cd5d23678df535"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bbbf4c59350411fa4690cf9bf1933d0c37d9b95e78690aca8e5ed60b172e6cb"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bbf75e441e486d7e582eedbaf492582428f62fcb9c2fa76d2d63f968466e26ec"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2eed8ce89f0d6d5b73e389c4b26d4db22d280cbde9b94af61d55fa3c4030229f"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:47c3c86de94fff0e9b96fab91bb7f23174c3aad017255d4e17eb382346c45931"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:70f51cc1258ccc0216cb9fb1f3451199d7b44505a12c50ac3b8f4c4041051546"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-musllinux_1_1_i686.whl", hash = "sha256:21daf8b4c7007902a33886fb322ead1b6663154ac2d7d2ef9853b933190765c3"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:edb79ff07586e9ae459396c0c7dd9619d34f150c3ce6402a6e90aa937b37ce72"}, + {file = "qh3-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b0a6c539cb855cc47196af76eea8311fe73565b053c52eaf5daf1270d221ece8"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ff01101ccb8e4f697b4e68d21e8584e348c157910586f770474a22b7e06cf2f3"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67fc895298c73c7b962e6de8cc37ad9279204b46395d63f017ee148d96544fbb"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36e1ddb251ad6d12ab08b093ee6c4d310bfd9c7773f9fe63a9c2215bc95da37e"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:055a75912fdad3d9d38652c16c6812899228140bf65663af316463eb52331020"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:106c7848b64b44bc133570a7d9dcc435da711dcaab562890221584cccb6838f0"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:08e8ccc38bbd5940f8e96ca7c1c05b675bac06fca9193eea8cce3227e8a8cacc"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a2b0d4d39f50ec5714a2e5f73eea8503665d328ead87610a683342cfa8fd932"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c5a200a6cee1a73e6c4ce06d621d97d44b3290234163b17ec40b142bdbc2e5"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3e7e40716137a202020da3f510b84f9cd3f1874389288973fa605428b716a8cb"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:846229753073c7787aeb62323e6d7cfc465a2c23891c0b9d74668a188c7cbd8f"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-musllinux_1_1_i686.whl", hash = "sha256:b726eac629af057523426c765abf072c45585eabc2eded359aee1b3c9efd3159"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fad4692fcaaf8953f0f782c5fadde62be62d1211303d1d5a76e33326251f9b78"}, + {file = "qh3-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ea21508000c029dc221947abbd71b8e8a7d109caef424e4034c4ca57bee48664"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a2c03759cef347e68d5fc38dc8ac7a36711993ec5a81004a546732381c45e302"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451e03d90fc68a1e0dbf6e6f909a5a28289fcb2907a324ec226189fad8af1a73"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f005317f01c7e9fb5513b6bc0801b88bef4e6cca0e62d192c26d3d5cad80b86"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:166cc2a75a875665b6a0758e5fc1153c53f658a55528b3a1384f6af291c41f4b"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:49f28662a92957b622684a31c982b6d1efb80f11e3e8aba963c96564b52ae162"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31b12f65334986cded33f8e68268128756569b691383322ffae22c5d063d1506"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81040acaba0f3d2e95eae56714ec9a5b8e6fbd67d4a7b86feaf5f380679a7c0a"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70eb951a963a2be1ddcfcb725720e611c9f1c85475f1c0f39a6ba6a6a0169879"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ad517e5ac81a4025853439cce32fe94f3fb3c1bda62d06ff2e7bd910e30733d6"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:edb4c00edc63ff9db584f34ca73f182e49c632c96835eb0cddaeb988dc44c3bb"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-musllinux_1_1_i686.whl", hash = "sha256:6659e50fe9f65b647def14591fa1944f6d1556699c75db203a2bbee35f6adb44"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:726d662d3233e76268a0ccd0df83ebc30eda4c576a5cd05889b117c27ba9003c"}, + {file = "qh3-1.3.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:51d831143c22439a28120dadd69dca2756264d3afa3691a8aad23b1405ae894f"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:34ab6150ceb0779d7b2cb53bab7da4769b70b14c59d8abb1e2ed697428bdc3a8"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c0df653a3e1cece467f617687f76094a493bcd0d156851c21327bb2f2c46017"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec5a3232e6ca840d011d02b8a8b7533702e66389ddcfc6cf605ec9654fab4343"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6576a6b879185ccc4d76f3544625d2c39bc4729dc63f0b286a5b927246ea508f"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1168f2f6d3a2a6bbce36df1fec7e902db500173e6c42a57645640b08d0396df6"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:765d50c12f5bfcece366edf84d9a6ed7fc883ca1a991ede406e2a4093ce5d7b3"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:137d0a014e83646b9b1f4ce280f76598c580ec2b00f3027537fdd3bbbcee3ec9"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef577069000574ca5372cfa51700c1569bf8c24a4b3e8cd57fd6b192097a547f"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bdd8475017309e7f3dc0c012cf8f157b872f688dd4e8b101d363d9959f9dbeea"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:df177b55d926fb1bccdd999e7ff033c657d31bf1b19999f2ce76514af4a46517"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-musllinux_1_1_i686.whl", hash = "sha256:f3021110cad1ad448776d10d3a30f816ea53d7432e0bb8ef938d77223f8d1195"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:2ab7db5015d0cae268e5e9b9992b9cf0fe46fbf91365334e1d0b1cc3c293ebaf"}, + {file = "qh3-1.3.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f5a5a23ae3aca3e745780a42728f3c77033975df9a1fa4f9c7292efeda92b050"}, + {file = "qh3-1.3.2.tar.gz", hash = "sha256:d95f6d437411439a5c8d0a36b14183b7d1a8f5b96d2b69310edd6ee56613e790"}, +] + [[package]] name = "regex" -version = "2024.9.11" +version = "2024.11.6" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" -files = [ - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1494fa8725c285a81d01dc8c06b55287a1ee5e0e382d8413adc0a9197aac6408"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0e12c481ad92d129c78f13a2a3662317e46ee7ef96c94fd332e1c29131875b7d"}, - {file = "regex-2024.9.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16e13a7929791ac1216afde26f712802e3df7bf0360b32e4914dca3ab8baeea5"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46989629904bad940bbec2106528140a218b4a36bb3042d8406980be1941429c"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a906ed5e47a0ce5f04b2c981af1c9acf9e8696066900bf03b9d7879a6f679fc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e9a091b0550b3b0207784a7d6d0f1a00d1d1c8a11699c1a4d93db3fbefc3ad35"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ddcd9a179c0a6fa8add279a4444015acddcd7f232a49071ae57fa6e278f1f71"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b41e1adc61fa347662b09398e31ad446afadff932a24807d3ceb955ed865cc8"}, - {file = "regex-2024.9.11-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ced479f601cd2f8ca1fd7b23925a7e0ad512a56d6e9476f79b8f381d9d37090a"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:635a1d96665f84b292e401c3d62775851aedc31d4f8784117b3c68c4fcd4118d"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c0256beda696edcf7d97ef16b2a33a8e5a875affd6fa6567b54f7c577b30a137"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3ce4f1185db3fbde8ed8aa223fc9620f276c58de8b0d4f8cc86fd1360829edb6"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:09d77559e80dcc9d24570da3745ab859a9cf91953062e4ab126ba9d5993688ca"}, - {file = "regex-2024.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a22ccefd4db3f12b526eccb129390942fe874a3a9fdbdd24cf55773a1faab1a"}, - {file = "regex-2024.9.11-cp310-cp310-win32.whl", hash = "sha256:f745ec09bc1b0bd15cfc73df6fa4f726dcc26bb16c23a03f9e3367d357eeedd0"}, - {file = "regex-2024.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:01c2acb51f8a7d6494c8c5eafe3d8e06d76563d8a8a4643b37e9b2dd8a2ff623"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268"}, - {file = "regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50"}, - {file = "regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96"}, - {file = "regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1"}, - {file = "regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9"}, - {file = "regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231"}, - {file = "regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a"}, - {file = "regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a"}, - {file = "regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a"}, - {file = "regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776"}, - {file = "regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36"}, - {file = "regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6"}, - {file = "regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554"}, - {file = "regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8"}, - {file = "regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8"}, - {file = "regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:35f4a6f96aa6cb3f2f7247027b07b15a374f0d5b912c0001418d1d55024d5cb4"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:55b96e7ce3a69a8449a66984c268062fbaa0d8ae437b285428e12797baefce7e"}, - {file = "regex-2024.9.11-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb130fccd1a37ed894824b8c046321540263013da72745d755f2d35114b81a60"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:323c1f04be6b2968944d730e5c2091c8c89767903ecaa135203eec4565ed2b2b"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be1c8ed48c4c4065ecb19d882a0ce1afe0745dfad8ce48c49586b90a55f02366"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5b029322e6e7b94fff16cd120ab35a253236a5f99a79fb04fda7ae71ca20ae8"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6fff13ef6b5f29221d6904aa816c34701462956aa72a77f1f151a8ec4f56aeb"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:587d4af3979376652010e400accc30404e6c16b7df574048ab1f581af82065e4"}, - {file = "regex-2024.9.11-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:079400a8269544b955ffa9e31f186f01d96829110a3bf79dc338e9910f794fca"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f9268774428ec173654985ce55fc6caf4c6d11ade0f6f914d48ef4719eb05ebb"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:23f9985c8784e544d53fc2930fc1ac1a7319f5d5332d228437acc9f418f2f168"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2941333154baff9838e88aa71c1d84f4438189ecc6021a12c7573728b5838e"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e93f1c331ca8e86fe877a48ad64e77882c0c4da0097f2212873a69bbfea95d0c"}, - {file = "regex-2024.9.11-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:846bc79ee753acf93aef4184c040d709940c9d001029ceb7b7a52747b80ed2dd"}, - {file = "regex-2024.9.11-cp38-cp38-win32.whl", hash = "sha256:c94bb0a9f1db10a1d16c00880bdebd5f9faf267273b8f5bd1878126e0fbde771"}, - {file = "regex-2024.9.11-cp38-cp38-win_amd64.whl", hash = "sha256:2b08fce89fbd45664d3df6ad93e554b6c16933ffa9d55cb7e01182baaf971508"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:07f45f287469039ffc2c53caf6803cd506eb5f5f637f1d4acb37a738f71dd066"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4838e24ee015101d9f901988001038f7f0d90dc0c3b115541a1365fb439add62"}, - {file = "regex-2024.9.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6edd623bae6a737f10ce853ea076f56f507fd7726bee96a41ee3d68d347e4d16"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c69ada171c2d0e97a4b5aa78fbb835e0ffbb6b13fc5da968c09811346564f0d3"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02087ea0a03b4af1ed6ebab2c54d7118127fee8d71b26398e8e4b05b78963199"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69dee6a020693d12a3cf892aba4808fe168d2a4cef368eb9bf74f5398bfd4ee8"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:297f54910247508e6e5cae669f2bc308985c60540a4edd1c77203ef19bfa63ca"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecea58b43a67b1b79805f1a0255730edaf5191ecef84dbc4cc85eb30bc8b63b9"}, - {file = "regex-2024.9.11-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eab4bb380f15e189d1313195b062a6aa908f5bd687a0ceccd47c8211e9cf0d4a"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0cbff728659ce4bbf4c30b2a1be040faafaa9eca6ecde40aaff86f7889f4ab39"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:54c4a097b8bc5bb0dfc83ae498061d53ad7b5762e00f4adaa23bee22b012e6ba"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:73d6d2f64f4d894c96626a75578b0bf7d9e56dcda8c3d037a2118fdfe9b1c664"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:e53b5fbab5d675aec9f0c501274c467c0f9a5d23696cfc94247e1fb56501ed89"}, - {file = "regex-2024.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ffbcf9221e04502fc35e54d1ce9567541979c3fdfb93d2c554f0ca583a19b35"}, - {file = "regex-2024.9.11-cp39-cp39-win32.whl", hash = "sha256:e4c22e1ac1f1ec1e09f72e6c44d8f2244173db7eb9629cc3a346a8d7ccc31142"}, - {file = "regex-2024.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:faa3c142464efec496967359ca99696c896c591c56c53506bac1ad465f66e919"}, - {file = "regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd"}, +groups = ["dev"] +files = [ + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, ] [[package]] @@ -1529,6 +1841,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -1550,6 +1863,7 @@ version = "1.12.1" description = "Mock out responses from the requests package" optional = false python-versions = ">=3.5" +groups = ["dev"] files = [ {file = "requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401"}, {file = "requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563"}, @@ -1563,13 +1877,14 @@ fixture = ["fixtures"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main", "dev"] files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -1578,6 +1893,7 @@ version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["dev"] files = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, @@ -1589,6 +1905,8 @@ version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_full_version <= \"3.11.0a6\"" files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, @@ -1630,6 +1948,7 @@ version = "6.4.2" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"}, {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"}, @@ -1650,6 +1969,7 @@ version = "4.24.1" description = "tox is a generic virtualenv management and test command line tool" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "tox-4.24.1-py3-none-any.whl", hash = "sha256:57ba7df7d199002c6df8c2db9e6484f3de6ca8f42013c083ea2d4d1e5c6bdc75"}, {file = "tox-4.24.1.tar.gz", hash = "sha256:083a720adbc6166fff0b7d1df9d154f9d00bfccb9403b8abf6bc0ee435d6a62e"}, @@ -1677,31 +1997,19 @@ version = "3.3.23.2" description = "Typing stubs for cryptography" optional = false python-versions = "*" +groups = ["dev"] files = [ {file = "types-cryptography-3.3.23.2.tar.gz", hash = "sha256:09cc53f273dd4d8c29fa7ad11fefd9b734126d467960162397bc5e3e604dea75"}, {file = "types_cryptography-3.3.23.2-py3-none-any.whl", hash = "sha256:b965d548f148f8e87f353ccf2b7bd92719fdf6c845ff7cedf2abb393a0643e4f"}, ] -[[package]] -name = "types-requests" -version = "2.32.0.20241016" -description = "Typing stubs for requests" -optional = false -python-versions = ">=3.8" -files = [ - {file = "types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95"}, - {file = "types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747"}, -] - -[package.dependencies] -urllib3 = ">=2" - [[package]] name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" +groups = ["main", "dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -1713,6 +2021,7 @@ version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, @@ -1724,12 +2033,37 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "urllib3-future" +version = "2.12.909" +description = "urllib3.future is a powerful HTTP 1.1, 2, and 3 client with both sync and async interfaces" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "urllib3_future-2.12.909-py3-none-any.whl", hash = "sha256:7841936c7d55e9f4208b0ddd622e6b88167d6d84872d3b2fa572dd49e289bf72"}, + {file = "urllib3_future-2.12.909.tar.gz", hash = "sha256:de1997d1a46f978c6add6891a4a4469785b28c6fbe1b6721d476aa696883fc34"}, +] + +[package.dependencies] +h11 = ">=0.11.0,<1.0.0" +jh2 = ">=5.0.3,<6.0.0" +qh3 = {version = ">=1.2.0,<2.0.0", markers = "(platform_python_implementation != \"CPython\" or python_full_version > \"3.7.10\") and (platform_system == \"Darwin\" or platform_system == \"Windows\" or platform_system == \"Linux\") and (platform_machine == \"x86_64\" or platform_machine == \"s390x\" or platform_machine == \"aarch64\" or platform_machine == \"armv7l\" or platform_machine == \"ppc64le\" or platform_machine == \"ppc64\" or platform_machine == \"AMD64\" or platform_machine == \"arm64\" or platform_machine == \"ARM64\" or platform_machine == \"x86\" or platform_machine == \"i686\") and (platform_python_implementation == \"CPython\" or (platform_python_implementation == \"PyPy\" and python_version < \"3.11\"))"} + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +qh3 = ["qh3 (>=1.2.0,<2.0.0)"] +socks = ["python-socks (>=2.0,<=2.6.1)"] +ws = ["wsproto (>=1.2,<2)"] +zstd = ["zstandard (>=0.18.0)"] + [[package]] name = "virtualenv" version = "20.29.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779"}, {file = "virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35"}, @@ -1744,12 +2078,104 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "wassima" +version = "1.2.1" +description = "Access your OS root certificates with utmost ease" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d25a1c5bb8b18a54fb274f123a56688525069726851f7f169e2524d03f3733ec"}, + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cec51d905a3571c5b1a927d94182b20da037ba45a9d85b58189f56636be511e6"}, + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:48fdc5c8c5bf9c5877d07c7e4626a34f6857529187472ce315eea87b4bd3e4cb"}, + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64a1dce6b0bffa1b50b089f995df684e8e9ae3d364872fba15580afea907a0f1"}, + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726974452375348a21a3676403b9085bec9f64361010e862f199c9636755fb41"}, + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f798b298904e908407dad34597e482be6f21b4ce9fd8d68af988229d31f4666c"}, + {file = "wassima-1.2.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eec6d9904a9b27d6a4ce74e5348c0e34847fe9ca09a60676006fc0262ed0543a"}, + {file = "wassima-1.2.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:75fcf7b29ce0e5b4ee27da1d42a7b944614b80ce71da66dd07e8053aa47876dc"}, + {file = "wassima-1.2.1-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:790279a3fac25595a28f480418be025c69b48a6cf21374594d46c00156a9a1ed"}, + {file = "wassima-1.2.1-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:2af9c0c1959eb0e0f96896435c31a786a8156a87ec4f2e174e5a471bed59487e"}, + {file = "wassima-1.2.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:920fb91af668c7e2e1ce79174147ab3f08b54d44ee2c3cbd272b075d0881271b"}, + {file = "wassima-1.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:64ff8c0633640e5f271de41ac09b8a72ee77042573cad3c22b2230fcbbc7c828"}, + {file = "wassima-1.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:941d34418c967b1f4891e74925149479670723d32fbae3c32c0ae11868fbf398"}, + {file = "wassima-1.2.1-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b3c03e88e87d4b8dc87756cefa452de60faf2a5a4ea4a52cd859d9d9806a6d04"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebe1a61eb9416504d7d0a825d45b703a8b9684ba03792378ecb54ed2da37e357"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c1eeb1a577f915c69a9353ef7c1ecfb5dff752ebf9259116bf497a0ebd847b5f"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f8634b2c418dfc673c5832a4b3d523bd2814d7144294f4d4d9ec2fc608610cb0"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9f69aae8f8af70647aec634658802b0362dcc9ac50c0657408b23d7f77ceb3f6"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c33bf88a4268d40d7de44c1ae551877d592a8c05c54335920b4c16ea8e8e1f59"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2db3c48779b8a514bb7de1b8ac5079dcec9781efb8b0f90197af3f30919eb87"}, + {file = "wassima-1.2.1-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:74603e51b57ddc60763b310a47ca882bc17ee789e0590a21b842bbf8f03c5454"}, + {file = "wassima-1.2.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b9939fcf31898ce236c9c5b77222e9fcbf528382db9a6268044366e837d56435"}, + {file = "wassima-1.2.1-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:10b1c6acd08e890d1c1d3a61e9956ca7e47514ab6767b4ebf5e038ef19e5f223"}, + {file = "wassima-1.2.1-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:d8ecbe60a41ae84bdf99db35b9790c31253a84bbfd85a5d4e5ad00b43867875a"}, + {file = "wassima-1.2.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:4bc4ad06f450fa289353b9c4f0459157910538513657798b8ad2371ed2689448"}, + {file = "wassima-1.2.1-cp37-abi3-win32.whl", hash = "sha256:9cdaa278e8a74ed147b7b52d5cc51b2fbf08f9ea38dc3bf080b2058583e1c4e8"}, + {file = "wassima-1.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:25efc0332996e0896c7ea11bc93815ebec50bbea1e115b9f1c92c7fd8bcb97bc"}, + {file = "wassima-1.2.1-cp37-abi3-win_arm64.whl", hash = "sha256:f7e560ee96121269c0faa8c357284d23b41b636dc65b14edb512363605de74ee"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04f22ca4dee0694230ad065dc8b21501da9f87c0cf1e7f3e5ecbe8ea0192d51d"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ea2d6353be1d6ce8fa4cf73c643e9705baf77c4dcdbdabd4d39711fefae59aa"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b87385c4fcc43730f7570e6aa937ecde395d2aed491c8a2e28237801cd583b41"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:699386e6d8f0561dc28564c0288a673e2f47ff21d50d4b784b1c1a4bbb184e97"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78962d0cb83efbc3497e9d39e174dd5bd259966c22cd225b4b847629bdef6fe9"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:650a354f614bfa008d202331752de07f81e677a842233699d043a4fef6b1de6d"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0c5f57696f6547c3dc7b6132720323baf346ceb3ad17a47f92422218434edcae"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f168f4a61a53ef420ae63e64004518008aaddd280b7170ebc50f2564c25c0939"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:9cc6e5dea2d079a8997e55d573be524a96cffe6e1c1841c3452f64f2071b65d6"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-musllinux_1_1_i686.whl", hash = "sha256:65b513017d3d0686e7d0d8914ee56d5b1de7a0d11f602364809f51ad6d54a541"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:79418677b983ae64c1081627d8753be4dd0ac6102906e66927f00f278077ba1d"}, + {file = "wassima-1.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36386f8a7b95447646d30e172aba4b4444161b3a14eb946854ac9db2a89769a9"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a924c97c158468e1c10af8e4432f2ad8ad86e60cbb17b416169ff906c558886"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f48924f09cb48844a6ae43d764ee08801cb44da0950300a5fd3884c351d54480"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:de79a68b903a9c0b2c93e5b83671cb2912e9aa706056d1ea3e7464a8b0c2163a"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c13974448c396d3449d128d020db4d94ca37ab0e11eeeb6c75e1950195be309"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87facb3e6d12bf50961e1cc85b0e8f280d3a9625892f4dcdfbd06604218882e3"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b14876a3ac290db9075a46b6c56e1034fc9019a106b024fe32d0c51f2c4f0624"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bffd8a52ed32c381116575b37961bb6346d7e9b3e1adc296c146e0f58668743a"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:48b8fb2b13ac94e2e70a676f4ab62e3feb27270d0f3cf2a85f7b566089b0118a"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:9703187bc688f269223f1e97c6ba3057a3d0421c5540d23ed359fdcd1b597e56"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-musllinux_1_1_i686.whl", hash = "sha256:6bf578d402d5f81b43f8e213d7c8ae2196b7577394534b08e8e62cab88c20230"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ab517598115ce6d4b937ef7669df6b185906454ea4fd57942b757f29831016"}, + {file = "wassima-1.2.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:38df4be58b1b7dee70e2f3d1f003ab1d9377ae2e3a455203480f9f4341cb6cbc"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559fe986f616d0119069d4a21009b920ada0567dfdee6a218e2d0e61e36b61fd"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c1b9eb9ffda03a4dd9b88e8844ffbaff2ac3073acc9831ca32d20387aa9ff14"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:74a57cf329c310d871d2d0ab22e430c389c5e5fd028bb38a96ba9637d3e320fb"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3b430994ca82d5d9b8cf83df9621125419ab281d32ecd84ddee63f3e2e75962"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a142fd068767cb36fb63cf8520a283372c16f3e40ab2c0d956427ad0592dc3bb"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f95728c2757d04708225e20acfe581f271ed8bc6a136b70d23966c1945ea97"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cccb86cc3c9320862bbc5c0effb69a5130fdac196cdecd98105035ff1259fd49"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:39de4204dd4189ac7308740a562e0500def62862837d81f4e3bbf92cdb511be5"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:712fef836bb5c81508554ecc5761ac018c9f435c394c1e1ae7067d1e5ffa10df"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-musllinux_1_1_i686.whl", hash = "sha256:f9cfa861f5a04c4d4d956ce523400771db29beabc7a76747d14e5a811898e4a8"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1aad483311b361423cff4c4dff8447453f474e96d11c257fb506443f62f1be1a"}, + {file = "wassima-1.2.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:0043cd8f6a83fe392d214e309e46cb3a510a1d6645b833f08c35a3a8905c1c80"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b96b3e332571d896340067de1283858a63cd378bd38496c3a29755e7b361a71f"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8dd2ffb79cfcab9e80a1fad3da6d81c2a963f193a911acf885fd765646b0952"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:3091056f6d6ac8ec4a364248b2d719c4744f114b87d2eec36e25c3ac707a085f"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46fc280a5e75582f3c685ba2bc78308a5d5ac9ac81a1772377934fdb4281428c"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:819b3a509127bd8765a2516d789aa3494ebebeb451dd130029f10bba1a73d1e0"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf88e8990991b03ad3a6eff147814734a304f1f6c0e54743eab4a9be072f29f1"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b914e67e7b324168a2235f677b3271463fe81911b975c24f37b210255b6e1d08"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:8956a211318c2c8f4866623d7e3e038dc2c3bd3788a165f1417180c8b784433b"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:5cfbe4f1a09f9f775062a2aefc504ea0838e703b6b4d41f53efd0629c6e216f7"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-musllinux_1_1_i686.whl", hash = "sha256:3d8e59dfb7b20c0235d3a80d8f18db22ff71b41c9cdb21195829868789212173"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:325d296014d763e45777c4bad8df1bfa3f7b5d13014f8d32be5e9d9081d0c912"}, + {file = "wassima-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5192f8f0375e3cf007d1de88b8d73ab778fbb14d947bcc3b6bdf8eca7dc44451"}, + {file = "wassima-1.2.1-py3-none-any.whl", hash = "sha256:421844634c2e0c48c5d4fa962c07f7346c1a00ae8d73aeab503356db8ba95701"}, + {file = "wassima-1.2.1.tar.gz", hash = "sha256:7798ed43e337a618650383d1630c6b66efd65ccedbd61726a3fdaab752f677a4"}, +] + +[package.dependencies] +certifi = {version = "*", markers = "platform_python_implementation != \"CPython\" or python_full_version < \"3.7.10\" or platform_system != \"Darwin\" and platform_system != \"Windows\" and platform_system != \"Linux\" or platform_machine != \"x86_64\" and platform_machine != \"s390x\" and platform_machine != \"aarch64\" and platform_machine != \"armv7l\" and platform_machine != \"ppc64le\" and platform_machine != \"ppc64\" and platform_machine != \"AMD64\" and platform_machine != \"arm64\" and platform_machine != \"ARM64\" and platform_machine != \"i686\" and platform_machine != \"x86\""} + [[package]] name = "watchdog" version = "4.0.2" description = "Filesystem events monitoring" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ede7f010f2239b97cc79e6cb3c249e72962404ae3865860855d5cbe708b0fd22"}, {file = "watchdog-4.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2cffa171445b0efa0726c561eca9a27d00a1f2b83846dbd5a4f639c4f8ca8e1"}, @@ -1797,6 +2223,7 @@ version = "10.0" description = "Wildcard/glob file name matcher." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "wcmatch-10.0-py3-none-any.whl", hash = "sha256:0dd927072d03c0a6527a20d2e6ad5ba8d0380e60870c383bc533b71744df7b7a"}, {file = "wcmatch-10.0.tar.gz", hash = "sha256:e72f0de09bba6a04e0de70937b0cf06e55f36f37b3deb422dfaf854b867b840a"}, @@ -1811,6 +2238,7 @@ version = "3.0.6" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "werkzeug-3.0.6-py3-none-any.whl", hash = "sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17"}, {file = "werkzeug-3.0.6.tar.gz", hash = "sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d"}, @@ -1824,13 +2252,15 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "wheel" -version = "0.44.0" +version = "0.45.1" description = "A built-package format for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.9\"" files = [ - {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, - {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, + {file = "wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"}, + {file = "wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729"}, ] [package.extras] @@ -1842,6 +2272,8 @@ version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.10\"" files = [ {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, @@ -1860,6 +2292,6 @@ doc = [] test = [] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = ">=3.8" -content-hash = "9fa15527fcebf811cc8e5ae510ca45abd52de2cfa25d5a550940e09a6f2e25b7" +content-hash = "00690cdf7aff2bd15e221929b797ba2bd3a351e4f7d629651b36d4996ce4d375" diff --git a/pyproject.toml b/pyproject.toml index 600c2c7..790b581 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [tool] [tool.poetry] -name = "requests_oauth2client" -version = "1.6.0" -homepage = "https://github.com/guillp/requests_oauth2client" -description = "An OAuth2.x client based on `requests`." -authors = ["Guillaume Pujol "] +name = "niquests_oauth2client" +version = "1.7.0" +homepage = "https://github.com/guillp/niquests_oauth2client" +description = "An OAuth2.x client based on `niquests`." +authors = ["Guillaume Pujol "] readme = "README.md" license = "Apache-2.0" classifiers = [ @@ -13,28 +13,28 @@ classifiers = [ 'Topic :: Security', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', ] packages = [ - { include = "requests_oauth2client" }, + { include = "niquests_oauth2client" }, { include = "tests", format = "sdist" }, ] [tool.poetry.dependencies] -python = ">=3.8" +python = ">=3.9" -requests = ">=2.19.0" +niquests = ">=3.12" binapy = ">=0.8" furl = ">=2.1.2" jwskate = ">=0.11.1" attrs = ">=23.2.0" -[tool.poetry.dev-dependencies] +[tool.poetry.group.dev.dependencies] coverage = ">=7.6.1" flask = ">=3.0.3" livereload = ">=2.6.3" @@ -54,7 +54,6 @@ pytest-mypy = ">=0.9.1" requests-mock = ">=1.9.3" toml = ">=0.10.2" tox = ">=4" -types-requests = ">=2.25.10" types-cryptography = ">=3.3.15" virtualenv = ">=20.2.2" @@ -99,7 +98,7 @@ wrap-descriptions = 120 blank = true [tool.ruff] -target-version = "py38" +target-version = "py39" line-length = 120 diff --git a/tests/.coveragerc b/tests/.coveragerc index 2020e8e..814f44f 100644 --- a/tests/.coveragerc +++ b/tests/.coveragerc @@ -1,6 +1,6 @@ [run] branch = True -source = requests_oauth2client +source = niquests_oauth2client omit = diff --git a/tests/conftest.py b/tests/conftest.py index e002068..03510cc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,18 +1,31 @@ from __future__ import annotations import base64 +import sys +from collections.abc import Iterable from datetime import datetime, timezone -from typing import TYPE_CHECKING, Any, Callable, Iterable +from typing import Any, Callable from urllib.parse import parse_qs + +import niquests +import urllib3 +# the mock utility 'requests_mock' only works with 'requests' +sys.modules["requests"] = niquests +sys.modules["requests.adapters"] = niquests.adapters +sys.modules["requests.exceptions"] = niquests.exceptions +sys.modules["requests.packages.urllib3"] = urllib3 + + import pytest -import requests import requests_mock + from furl import Query, furl # type: ignore[import-untyped] from jwskate import Jwk, JwkSet, SignedJwt, SymmetricJwk -from requests_mock import Mocker +from niquests.structures import CaseInsensitiveDict +from pytest import FixtureRequest as __FixtureRequest # noqa: PT013 -from requests_oauth2client import ( +from niquests_oauth2client import ( ApiClient, BaseClientAuthenticationMethod, BearerToken, @@ -22,27 +35,89 @@ PublicApp, ) + +class NiquestsAdapter(requests_mock.Adapter): + def build_response(self, req, resp): + """Return a niquests.Response.""" + response = niquests.Response() + + # Fallback to None if there's no status_code, for whatever reason. + response.status_code = getattr(resp, "status", None) + + # Make headers case-insensitive. + response.headers = niquests.structures.CaseInsensitiveDict(getattr(resp, "headers", {})) + + # Set encoding. + response.encoding = niquests.utils.get_encoding_from_headers(response.headers) + response.raw = resp + response.reason = response.raw.reason + + if isinstance(req.url, bytes): + response.url = req.url.decode("utf-8") + else: + response.url = req.url + + # Add new cookies from the server. + niquests.cookies.extract_cookies_to_jar(response.cookies, req, resp) + + # Give the Response some context. + response.request = req + response.connection = self + + return response + +requests_mock.response._http_adapter = NiquestsAdapter() + + +class FixtureRequest(__FixtureRequest): + param: str + + +class NiquestsMocker(requests_mock.Mocker): + def reset_mock(self) -> None: ... + + RequestValidatorType = Callable[..., None] -if TYPE_CHECKING: - from pytest import FixtureRequest as __FixtureRequest # noqa: PT013 - from requests_mock.request import _RequestObjectProxy - class FixtureRequest(__FixtureRequest): - param: str +@pytest.fixture +def niquests_mock() -> NiquestsMocker: + """This is required because pytest load plugins at boot, way before conftest. + + The only reliable way to make requests_mock use Niquests is to customize it after. + + """ + + - class RequestsMocker(Mocker): - def reset_mock(self) -> None: ... + class _WrappedMocker(requests_mock.Mocker): + """Ensure requests_mock work with the drop-in replacement Niquests!""" -else: - from pytest import FixtureRequest # noqa: PT013 + def __init__( + self, + session: niquests.Session | None = None, + *, + case_sensitive: bool = True, + adapter: requests_mock.Adapter | None = None, + json_encoder: Callable[[Any], Any] | None = None, + real_http: bool = False, + ) -> None: + # we purposely skip invoking super() to avoid the strict typecheck on session. + self._mock_target = session or niquests.Session + self.case_sensitive = case_sensitive + self._adapter = adapter or NiquestsAdapter(case_sensitive=case_sensitive) - RequestsMocker = Mocker + self._json_encoder = json_encoder + self.real_http = real_http + self._last_send = None + + with _WrappedMocker(case_sensitive=True) as m: + yield m @pytest.fixture(scope="session") -def session() -> requests.Session: - return requests.Session() +def session() -> niquests.Session: + return niquests.Session() def join_url(root: str, path: str) -> str: @@ -161,7 +236,7 @@ def client_auth_method( @pytest.fixture(scope="session") def client_secret_post_auth_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, client_id: str, client_secret: str) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, client_id: str, client_secret: str) -> None: params = parse_qs(req.text) assert params.get("client_id") == [client_id] assert params.get("client_secret") == [client_secret] @@ -172,7 +247,7 @@ def validator(req: _RequestObjectProxy, *, client_id: str, client_secret: str) - @pytest.fixture(scope="session") def public_app_auth_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, client_id: str) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, client_id: str) -> None: params = parse_qs(req.text) assert params.get("client_id") == [client_id] assert "client_secret" not in params @@ -182,7 +257,7 @@ def validator(req: _RequestObjectProxy, *, client_id: str) -> None: @pytest.fixture(scope="session") def client_secret_basic_auth_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, client_id: str, client_secret: str) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, client_id: str, client_secret: str) -> None: encoded_username_password = base64.b64encode(f"{client_id}:{client_secret}".encode("ascii")).decode() assert req.headers.get("Authorization") == f"Basic {encoded_username_password}" assert "client_secret" not in req.text @@ -192,7 +267,9 @@ def validator(req: _RequestObjectProxy, *, client_id: str, client_secret: str) - @pytest.fixture(scope="session") def client_secret_jwt_auth_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, client_id: str, client_secret: str, endpoint: str) -> None: + def validator( + req: requests_mock.request._RequestObjectProxy, *, client_id: str, client_secret: str, endpoint: str + ) -> None: params = Query(req.text).params assert params.get("client_id") == client_id assert "client_assertion" in params @@ -215,7 +292,7 @@ def validator(req: _RequestObjectProxy, *, client_id: str, client_secret: str, e @pytest.fixture(scope="session") def private_key_jwt_auth_validator() -> RequestValidatorType: def validator( - req: requests_mock.request._RequestObjectProxy, + req: niquests_mock.request._RequestObjectProxy, *, client_id: str, public_jwk: Jwk, @@ -241,15 +318,15 @@ def validator( @pytest.fixture(scope="session") def client_credentials_grant_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, scope: str | None = None, **kwargs: Any) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, scope: str | None = None, **kwargs: Any) -> None: params = Query(req.text).params assert params.get("grant_type") == "client_credentials" if scope is not None and not isinstance(scope, str): scope = " ".join(scope) - assert ( - not scope and params.get("scope") is None or scope and params.get("scope") == scope - ), f"expected {scope=}, got {params.get('scope')=}" + assert (not scope and params.get("scope") is None) or (scope and params.get("scope") == scope), ( + f"expected {scope=}, got {params.get('scope')=}" + ) for key, val in kwargs.items(): assert params.get(key) == val @@ -260,7 +337,7 @@ def validator(req: _RequestObjectProxy, *, scope: str | None = None, **kwargs: A @pytest.fixture(scope="session") def authorization_code_grant_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, code: str, **kwargs: Any) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, code: str, **kwargs: Any) -> None: params = Query(req.text).params assert params.get("grant_type") == "authorization_code" for key, val in kwargs.items(): @@ -273,7 +350,7 @@ def validator(req: _RequestObjectProxy, *, code: str, **kwargs: Any) -> None: @pytest.fixture(scope="session") def refresh_token_grant_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, refresh_token: str, **kwargs: Any) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, refresh_token: str, **kwargs: Any) -> None: params = Query(req.text).params assert params.get("grant_type") == "refresh_token" assert params.get("refresh_token") == refresh_token @@ -287,7 +364,7 @@ def validator(req: _RequestObjectProxy, *, refresh_token: str, **kwargs: Any) -> @pytest.fixture(scope="session") def device_code_grant_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, device_code: str, **kwargs: Any) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, device_code: str, **kwargs: Any) -> None: params = Query(req.text).params assert params.get("grant_type") == "urn:ietf:params:oauth:grant-type:device_code" assert params.get("device_code") == device_code @@ -301,7 +378,7 @@ def validator(req: _RequestObjectProxy, device_code: str, **kwargs: Any) -> None @pytest.fixture(scope="session") def token_exchange_grant_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, subject_token: str, **kwargs: Any) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, subject_token: str, **kwargs: Any) -> None: params = Query(req.text).params assert params.get("grant_type") == "urn:ietf:params:oauth:grant-type:token-exchange" assert params.get("subject_token") == subject_token @@ -315,7 +392,7 @@ def validator(req: _RequestObjectProxy, subject_token: str, **kwargs: Any) -> No @pytest.fixture(scope="session") def ciba_request_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, auth_req_id: str, **kwargs: Any) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, auth_req_id: str, **kwargs: Any) -> None: params = Query(req.text).params assert params.get("grant_type") == "urn:openid:params:grant-type:ciba" assert params.get("auth_req_id") == auth_req_id @@ -330,7 +407,7 @@ def validator(req: _RequestObjectProxy, *, auth_req_id: str, **kwargs: Any) -> N @pytest.fixture(scope="session") def backchannel_auth_request_validator() -> RequestValidatorType: def validator( - req: _RequestObjectProxy, + req: requests_mock.request._RequestObjectProxy, *, scope: None | str | Iterable[str], acr_values: None | str | Iterable[str] = None, @@ -372,7 +449,7 @@ def validator( @pytest.fixture(scope="session") def backchannel_auth_request_jwt_validator() -> RequestValidatorType: def validator( - req: _RequestObjectProxy, + req: requests_mock.request._RequestObjectProxy, *, public_jwk: Jwk, alg: str, @@ -410,7 +487,7 @@ def validator( @pytest.fixture(scope="session") def revocation_request_validator() -> RequestValidatorType: def validator( - req: _RequestObjectProxy, + req: requests_mock.request._RequestObjectProxy, token: str, type_hint: str | None = None, **kwargs: Any, @@ -428,7 +505,7 @@ def validator( @pytest.fixture(scope="session") def introspection_request_validator() -> RequestValidatorType: def validator( - req: _RequestObjectProxy, + req: requests_mock.request._RequestObjectProxy, token: str, type_hint: str | None = None, **kwargs: Any, @@ -552,7 +629,7 @@ def server_public_jwks(server_private_jwks: JwkSet) -> JwkSet: @pytest.fixture(scope="session") def bearer_auth_validator() -> RequestValidatorType: - def validator(req: _RequestObjectProxy, *, access_token: str) -> None: + def validator(req: requests_mock.request._RequestObjectProxy, *, access_token: str) -> None: assert req.headers.get("Authorization") == f"Bearer {access_token}" return validator diff --git a/tests/test_authorization_code.py b/tests/test_authorization_code.py index 6e1ce1e..954e5e3 100644 --- a/tests/test_authorization_code.py +++ b/tests/test_authorization_code.py @@ -3,13 +3,13 @@ import secrets from datetime import datetime, timedelta, timezone -import requests +import niquests from freezegun import freeze_time from furl import Query, furl # type: ignore[import-untyped] from jwskate import Jwk from requests_mock import Mocker -from requests_oauth2client import ( +from niquests_oauth2client import ( AuthorizationRequest, BearerToken, ClientSecretPost, @@ -21,8 +21,8 @@ @freeze_time() def test_authorization_code( - session: requests.Session, - requests_mock: Mocker, + session: niquests.Session, + niquests_mock: Mocker, issuer: str, token_endpoint: str, authorization_endpoint: str, @@ -37,8 +37,8 @@ def test_authorization_code( id_token_sig_alg = "ES256" id_token_signing_key = Jwk.generate(alg=id_token_sig_alg).with_kid_thumbprint() - requests_mock.get(issuer + "/.well-known/openid-configuration", json=discovery_document) - requests_mock.get(jwks_uri, json={"keys": [id_token_signing_key.public_jwk().to_dict()]}) + niquests_mock.get(issuer + "/.well-known/openid-configuration", json=discovery_document) + niquests_mock.get(jwks_uri, json={"keys": [id_token_signing_key.public_jwk().to_dict()]}) client = OAuth2Client.from_discovery_endpoint( issuer=issuer, client_id=client_id, @@ -94,7 +94,7 @@ def test_authorization_code( auth_response = authorization_request.validate_callback(authorization_response) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600, "id_token": str(id_token)}, ) @@ -106,8 +106,8 @@ def test_authorization_code( assert token.expires_at is not None assert token.expires_at == datetime.now(tz=timezone.utc).replace(microsecond=0) + timedelta(seconds=3600) - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.get("client_id") == client_id assert params.get("client_secret") == client_secret assert params.get("grant_type") == "authorization_code" @@ -116,8 +116,8 @@ def test_authorization_code( @freeze_time() def test_authorization_code_legacy( - session: requests.Session, - requests_mock: Mocker, + session: niquests.Session, + niquests_mock: Mocker, issuer: str, discovery_document: str, client_id: str, @@ -127,7 +127,7 @@ def test_authorization_code_legacy( audience: str, ) -> None: discovery_url = oidc_discovery_document_url(issuer) - requests_mock.get(discovery_url, json=discovery_document) + niquests_mock.get(discovery_url, json=discovery_document) discovery = session.get(discovery_url).json() authorization_endpoint = discovery.get("authorization_endpoint") assert authorization_endpoint @@ -147,24 +147,24 @@ def test_authorization_code_legacy( state = authorization_request.state authorization_response = furl(redirect_uri, query={"code": authorization_code, "state": state}).url - requests_mock.get( + niquests_mock.get( authorization_request.uri, status_code=302, headers={"Location": authorization_response}, ) - resp = requests.get(authorization_request.uri, allow_redirects=False) + resp = niquests.get(authorization_request.uri, allow_redirects=False) assert resp.status_code == 302 location = resp.headers.get("Location") assert location == authorization_response - assert requests_mock.last_request is not None - qs = Query(requests_mock.last_request.qs).params + assert niquests_mock.last_request is not None + qs = Query(niquests_mock.last_request.qs).params assert qs.get("client_id") == client_id assert qs.get("response_type") == "code" assert qs.get("redirect_uri") == redirect_uri assert qs.get("state") == state code_challenge = qs.get("code_challenge") assert code_challenge - code_challenge_method = requests_mock.last_request.qs.get("code_challenge_method") + code_challenge_method = niquests_mock.last_request.qs.get("code_challenge_method") code_verifier = authorization_request.code_verifier assert code_verifier is not None assert code_challenge_method == ["S256"] @@ -179,7 +179,7 @@ def test_authorization_code_legacy( access_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) @@ -191,8 +191,8 @@ def test_authorization_code_legacy( assert token.expires_at is not None assert token.expires_at == datetime.now(tz=timezone.utc).replace(microsecond=0) + timedelta(seconds=3600) - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.get("client_id") == client_id assert params.get("client_secret") == client_secret assert params.get("grant_type") == "authorization_code" diff --git a/tests/test_client_credentials.py b/tests/test_client_credentials.py index ccbd471..c3f4f6f 100644 --- a/tests/test_client_credentials.py +++ b/tests/test_client_credentials.py @@ -1,9 +1,9 @@ from urllib.parse import parse_qs -import requests +import niquests from requests_mock import Mocker -from requests_oauth2client import ( +from niquests_oauth2client import ( ClientSecretPost, OAuth2Client, OAuth2ClientCredentialsAuth, @@ -11,14 +11,14 @@ def test_client_credentials_get_token( - requests_mock: Mocker, + niquests_mock: Mocker, client_id: str, client_secret: str, token_endpoint: str, target_api: str, access_token: str, ) -> None: - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) @@ -26,15 +26,15 @@ def test_client_credentials_get_token( token_response = client.client_credentials() assert token_response.access_token == access_token - assert requests_mock.last_request is not None - params = parse_qs(requests_mock.last_request.text) + assert niquests_mock.last_request is not None + params = parse_qs(niquests_mock.last_request.text) assert params["client_id"][0] == client_id assert params["client_secret"][0] == client_secret assert params["grant_type"][0] == "client_credentials" def test_client_credentials_api( - requests_mock: Mocker, + niquests_mock: Mocker, access_token: str, token_endpoint: str, client_id: str, @@ -44,16 +44,16 @@ def test_client_credentials_api( client = OAuth2Client(token_endpoint, ClientSecretPost(client_id, client_secret)) auth = OAuth2ClientCredentialsAuth(client) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) - requests_mock.get(target_api, request_headers={"Authorization": f"Bearer {access_token}"}) - response = requests.get(target_api, auth=auth) + niquests_mock.get(target_api, request_headers={"Authorization": f"Bearer {access_token}"}) + response = niquests.get(target_api, auth=auth) assert response.ok - assert len(requests_mock.request_history) == 2 - token_request = requests_mock.request_history[0] - api_request = requests_mock.request_history[1] + assert len(niquests_mock.request_history) == 2 + token_request = niquests_mock.request_history[0] + api_request = niquests_mock.request_history[1] params = parse_qs(token_request.text) assert params.get("client_id") == [client_id] assert params.get("client_secret") == [client_secret] diff --git a/tests/test_device_authorization.py b/tests/test_device_authorization.py index 86ca26a..e7da0ae 100644 --- a/tests/test_device_authorization.py +++ b/tests/test_device_authorization.py @@ -4,7 +4,7 @@ from furl import Query # type: ignore[import-untyped] from requests_mock import Mocker -from requests_oauth2client import ( +from niquests_oauth2client import ( BearerToken, ClientSecretBasic, DeviceAuthorizationError, @@ -23,7 +23,7 @@ def device_authorization_endpoint(request: FixtureRequest, issuer: str) -> str: @pytest.mark.slow def test_device_authorization( - requests_mock: Mocker, + niquests_mock: Mocker, device_authorization_endpoint: str, token_endpoint: str, client_id: str, @@ -39,7 +39,7 @@ def test_device_authorization( auth=(client_id, client_secret), ) - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, json={ "device_code": device_code, @@ -55,14 +55,14 @@ def test_device_authorization( assert device_auth_resp.verification_uri assert not device_auth_resp.is_expired() - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.get("client_id") == client_id assert params.get("client_secret") == client_secret access_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, [ {"json": {"error": "authorization_pending"}, "status_code": 400}, @@ -86,8 +86,8 @@ def test_device_authorization( # 1st attempt: authorization_pending resp = pool_job() - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.get("client_id") == client_id assert params.get("client_secret") == client_secret @@ -96,8 +96,8 @@ def test_device_authorization( # 2nd attempt: slow down resp = pool_job() - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.get("client_id") == client_id assert params.get("client_secret") == client_secret @@ -107,8 +107,8 @@ def test_device_authorization( # 3rd attempt: access token delivered resp = pool_job() assert isinstance(resp, BearerToken) - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.get("client_id") == client_id assert params.get("client_secret") == client_secret @@ -141,7 +141,7 @@ def test_auth_handler( def test_invalid_response( - requests_mock: Mocker, + niquests_mock: Mocker, token_endpoint: str, device_authorization_endpoint: str, client_id: str, @@ -153,7 +153,7 @@ def test_invalid_response( auth=(client_id, client_secret), ) - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, status_code=500, json={"error": "unknown_error"}, @@ -161,7 +161,7 @@ def test_invalid_response( with pytest.raises(DeviceAuthorizationError): da_client.authorize_device() - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, status_code=500, json={"foo": "bar"}, diff --git a/tests/test_oidc.py b/tests/test_oidc.py index e336a2c..de0d6f7 100644 --- a/tests/test_oidc.py +++ b/tests/test_oidc.py @@ -2,12 +2,12 @@ from furl import furl # type: ignore[import-untyped] from jwskate import EncryptionAlgs, Jwk, Jwt -from requests_oauth2client import IdToken, OAuth2Client -from tests.conftest import RequestsMocker +from niquests_oauth2client import IdToken, OAuth2Client +from tests.conftest import NiquestsMocker @freeze_time("2024-01-01 00:00:00") -def test_encrypted_id_token(requests_mock: RequestsMocker) -> None: +def test_encrypted_id_token(niquests_mock: NiquestsMocker) -> None: id_token_decryption_key = Jwk( { "kty": "EC", @@ -82,7 +82,7 @@ def test_encrypted_id_token(requests_mock: RequestsMocker) -> None: access_token = "my_access_token" - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600, "id_token": str(id_token)}, ) diff --git a/tests/test_refresh_token.py b/tests/test_refresh_token.py index 35a344e..11a5a9c 100644 --- a/tests/test_refresh_token.py +++ b/tests/test_refresh_token.py @@ -1,12 +1,12 @@ import secrets -from requests_oauth2client import OAuth2Client +from niquests_oauth2client import OAuth2Client -from .conftest import RequestsMocker, RequestValidatorType +from .conftest import NiquestsMocker, RequestValidatorType def test_refresh_token( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, refresh_token: str, @@ -24,7 +24,7 @@ def test_refresh_token( new_access_token = secrets.token_urlsafe() new_refresh_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -38,17 +38,17 @@ def test_refresh_token( assert token_resp.access_token == new_access_token assert token_resp.refresh_token == new_refresh_token - refresh_token_grant_validator(requests_mock.last_request, refresh_token=refresh_token) - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + refresh_token_grant_validator(niquests_mock.last_request, refresh_token=refresh_token) + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) - requests_mock.post(revocation_endpoint) + niquests_mock.post(revocation_endpoint) assert client.revoke_access_token(token_resp.access_token) is True - revocation_request_validator(requests_mock.last_request, new_access_token, "access_token") - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + revocation_request_validator(niquests_mock.last_request, new_access_token, "access_token") + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) assert client.revoke_refresh_token(token_resp.refresh_token) is True - revocation_request_validator(requests_mock.last_request, new_refresh_token, "refresh_token") - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + revocation_request_validator(niquests_mock.last_request, new_refresh_token, "refresh_token") + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) diff --git a/tests/test_token_exchange.py b/tests/test_token_exchange.py index 07db06e..31c7016 100644 --- a/tests/test_token_exchange.py +++ b/tests/test_token_exchange.py @@ -4,13 +4,13 @@ from freezegun import freeze_time from furl import Query # type: ignore[import-untyped] -from requests_oauth2client import BearerToken, ClientSecretPost, IdToken, OAuth2Client, UnknownTokenType -from tests.conftest import RequestsMocker +from niquests_oauth2client import BearerToken, ClientSecretPost, IdToken, OAuth2Client, UnknownTokenType +from tests.conftest import NiquestsMocker @freeze_time() def test_token_exchange( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, client_id: str, client_secret: str, token_endpoint: str, @@ -19,7 +19,7 @@ def test_token_exchange( client = OAuth2Client(token_endpoint, ClientSecretPost(client_id, client_secret)) - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -38,8 +38,8 @@ def test_token_exchange( assert token_response.token_type == "Bearer" assert token_response.expires_in == 60 - assert requests_mock.last_request is not None - params = Query(requests_mock.last_request.text).params + assert niquests_mock.last_request is not None + params = Query(niquests_mock.last_request.text).params assert params.pop("client_id") == client_id assert params.pop("client_secret") == client_secret assert params.pop("grant_type") == "urn:ietf:params:oauth:grant-type:token-exchange" @@ -94,7 +94,7 @@ def test_token_type() -> None: assert OAuth2Client.get_token_type("saml2") == "urn:ietf:params:oauth:token-type:saml2" assert OAuth2Client.get_token_type("jwt") == "urn:ietf:params:oauth:token-type:jwt" - with pytest.raises(TypeError, match="token is of type ''") as exc: + with pytest.raises(TypeError, match="token is of type ''") as exc: OAuth2Client.get_token_type( token_type="access_token", token=IdToken( @@ -121,6 +121,6 @@ def test_token_type() -> None: OAuth2Client.get_token_type(token_type="refresh_token", token=BearerToken("mytoken")) assert exc.type is UnknownTokenType - with pytest.raises(TypeError, match="token is of type '") as exc2: + with pytest.raises(TypeError, match="token is of type '") as exc2: OAuth2Client.get_token_type(token_type="id_token", token=BearerToken("mytoken")) assert exc2.type is UnknownTokenType diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 0520dc8..6a95475 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -4,12 +4,12 @@ import hashlib from typing import TYPE_CHECKING, Any +import niquests import pytest -import requests from furl import furl # type: ignore[import-untyped] from jwskate import Jwk -from requests_oauth2client import ( +from niquests_oauth2client import ( ApiClient, AuthorizationRequest, AuthorizationResponse, @@ -23,13 +23,13 @@ ) if TYPE_CHECKING: - from requests_oauth2client.client_authentication import BaseClientAuthenticationMethod + from niquests_oauth2client.client_authentication import BaseClientAuthenticationMethod from tests.conftest import FixtureRequest @pytest.fixture(scope="session") -def session() -> requests.Session: - return requests.Session() +def session() -> niquests.Session: + return niquests.Session() def join_url(root: str, path: str) -> str: @@ -467,9 +467,9 @@ def authorization_request( # noqa: C901 if code_verifier is None: assert isinstance(generated_code_challenge, str) assert len(generated_code_challenge) == 43 - assert base64.urlsafe_b64decode( - generated_code_challenge.encode() + b"=" - ), f"Invalid B64U for generated code_challenge: {generated_code_challenge}" + assert base64.urlsafe_b64decode(generated_code_challenge.encode() + b"="), ( + f"Invalid B64U for generated code_challenge: {generated_code_challenge}" + ) else: assert azr.code_verifier == code_verifier assert generated_code_challenge == base64.urlsafe_b64encode( diff --git a/tests/unit_tests/test_api_client.py b/tests/unit_tests/test_api_client.py index 576b04b..0208ab1 100644 --- a/tests/unit_tests/test_api_client.py +++ b/tests/unit_tests/test_api_client.py @@ -1,21 +1,20 @@ from urllib.parse import urljoin +import niquests import pytest -import requests -from requests import HTTPError -from requests_oauth2client import ApiClient, BearerToken, InvalidBoolFieldsParam, InvalidPathParam -from tests.conftest import RequestsMocker, RequestValidatorType, join_url +from niquests_oauth2client import ApiClient, BearerToken, InvalidBoolFieldsParam, InvalidPathParam +from tests.conftest import NiquestsMocker, RequestValidatorType, join_url def test_session_at_init() -> None: - session = requests.Session() + session = niquests.Session() api = ApiClient("https://test.local", session=session) assert api.session == session def test_get( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, api: ApiClient, access_token: str, target_api: str, @@ -23,18 +22,18 @@ def test_get( bearer_auth_validator: RequestValidatorType, ) -> None: target_uri = join_url(target_api, target_path) - requests_mock.get(target_uri) + niquests_mock.get(target_uri) response = api.get(target_path) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.url == target_uri - assert requests_mock.last_request.method == "GET" - bearer_auth_validator(requests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.url == target_uri + assert niquests_mock.last_request.method == "GET" + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) def test_post( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, api: ApiClient, access_token: str, target_api: str, @@ -42,18 +41,18 @@ def test_post( bearer_auth_validator: RequestValidatorType, ) -> None: target_uri = join_url(target_api, target_path) - requests_mock.post(target_uri) + niquests_mock.post(target_uri) response = api.post(target_path) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "POST" - assert requests_mock.last_request.url == target_uri - bearer_auth_validator(requests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "POST" + assert niquests_mock.last_request.url == target_uri + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) def test_patch( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, api: ApiClient, access_token: str, target_api: str, @@ -61,18 +60,18 @@ def test_patch( bearer_auth_validator: RequestValidatorType, ) -> None: target_uri = join_url(target_api, target_path) - requests_mock.patch(target_uri) + niquests_mock.patch(target_uri) response = api.patch(target_path) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "PATCH" - assert requests_mock.last_request.url == target_uri - bearer_auth_validator(requests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "PATCH" + assert niquests_mock.last_request.url == target_uri + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) def test_put( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, api: ApiClient, access_token: str, target_api: str, @@ -80,18 +79,18 @@ def test_put( bearer_auth_validator: RequestValidatorType, ) -> None: target_uri = join_url(target_api, target_path) - requests_mock.put(target_uri) + niquests_mock.put(target_uri) response = api.put(target_path) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "PUT" - assert requests_mock.last_request.url == target_uri - bearer_auth_validator(requests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "PUT" + assert niquests_mock.last_request.url == target_uri + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) def test_delete( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, api: ApiClient, access_token: str, target_api: str, @@ -99,64 +98,64 @@ def test_delete( bearer_auth_validator: RequestValidatorType, ) -> None: target_uri = join_url(target_api, target_path) - requests_mock.delete(target_uri) + niquests_mock.delete(target_uri) response = api.delete(target_path) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "DELETE" - assert requests_mock.last_request.url == target_uri - bearer_auth_validator(requests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "DELETE" + assert niquests_mock.last_request.url == target_uri + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) def test_fail( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, api: ApiClient, access_token: str, target_api: str, bearer_auth_validator: RequestValidatorType, ) -> None: - requests_mock.get(target_api, status_code=400) - with pytest.raises(HTTPError): + niquests_mock.get(target_api, status_code=400) + with pytest.raises(niquests.HTTPError): api.get() - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "GET" - assert requests_mock.last_request.url == target_api - bearer_auth_validator(requests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "GET" + assert niquests_mock.last_request.url == target_api + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) -def test_url_as_bytes(requests_mock: RequestsMocker, target_api: str) -> None: +def test_url_as_bytes(niquests_mock: NiquestsMocker, target_api: str) -> None: api = ApiClient(target_api) - requests_mock.get(urljoin(target_api, "foo/bar")) + niquests_mock.get(urljoin(target_api, "foo/bar")) resp = api.get((b"foo", b"bar")) assert resp.ok assert api.get(b"foo/bar").ok -def test_url_as_iterable(requests_mock: RequestsMocker, target_api: str) -> None: +def test_url_as_iterable(niquests_mock: NiquestsMocker, target_api: str) -> None: api = ApiClient(target_api) target_uri = join_url(target_api, "/resource/1234/foo") - requests_mock.get(target_uri) + niquests_mock.get(target_uri) response = api.get(["resource", "1234", "foo"]) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "GET" - assert requests_mock.last_request.url == target_uri + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "GET" + assert niquests_mock.last_request.url == target_uri response = api.get(["resource", b"1234", "foo"]) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "GET" - assert requests_mock.last_request.url == target_uri + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "GET" + assert niquests_mock.last_request.url == target_uri response = api.get(["resource", 1234, "/foo"]) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.method == "GET" - assert requests_mock.last_request.url == target_uri + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.method == "GET" + assert niquests_mock.last_request.url == target_uri class NonStringableObject: def __str__(self) -> str: @@ -167,17 +166,17 @@ def __str__(self) -> str: assert exc.type is InvalidPathParam -def test_raise_for_status(requests_mock: RequestsMocker, target_api: str) -> None: +def test_raise_for_status(niquests_mock: NiquestsMocker, target_api: str) -> None: api = ApiClient(target_api, raise_for_status=False) - requests_mock.get(target_api, status_code=400, json={"status": "error"}) + niquests_mock.get(target_api, status_code=400, json={"status": "error"}) resp = api.get() assert not resp.ok - with pytest.raises(HTTPError): + with pytest.raises(niquests.HTTPError): api.get(raise_for_status=True) api_raises = ApiClient(target_api, raise_for_status=True) - with pytest.raises(HTTPError): + with pytest.raises(niquests.HTTPError): api_raises.get() assert not api_raises.get(raise_for_status=False).ok @@ -207,135 +206,135 @@ def test_additional_kwargs(target_api: str) -> None: assert api.timeout == 10 -def test_none_fields(requests_mock: RequestsMocker, target_api: str) -> None: - requests_mock.post(target_api) +def test_none_fields(niquests_mock: NiquestsMocker, target_api: str) -> None: + niquests_mock.post(target_api) api_exclude = ApiClient(target_api) assert api_exclude.none_fields == "exclude" api_exclude.post(json={"foo": "bar", "none": None}) - assert requests_mock.last_request is not None - assert requests_mock.last_request.json() == {"foo": "bar"} + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.json() == {"foo": "bar"} - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None api_exclude.post(data={"foo": "bar", "none": None}) - assert requests_mock.last_request is not None - assert requests_mock.last_request.text == "foo=bar" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.text == "foo=bar" api_include = ApiClient(target_api, none_fields="include") api_include.post(json={"foo": "bar", "none": None}) - assert requests_mock.last_request is not None - assert requests_mock.last_request.json() == {"foo": "bar", "none": None} + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.json() == {"foo": "bar", "none": None} api_include.post(data={"foo": "bar", "none": None}) - assert requests_mock.last_request is not None - assert requests_mock.last_request.text == "foo=bar" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.text == "foo=bar" api_include = ApiClient(target_api, none_fields="empty") api_include.post(json={"foo": "bar", "none": None}) - assert requests_mock.last_request is not None - assert requests_mock.last_request.json() == {"foo": "bar", "none": ""} + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.json() == {"foo": "bar", "none": ""} api_include.post(data={"foo": "bar", "none": None}) - assert requests_mock.last_request is not None - assert requests_mock.last_request.text == "foo=bar&none=" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.text == "foo=bar&none=" -def test_bool_fields(requests_mock: RequestsMocker, target_api: str) -> None: - requests_mock.post(target_api) +def test_bool_fields(niquests_mock: NiquestsMocker, target_api: str) -> None: + niquests_mock.post(target_api) api_default = ApiClient(target_api) api_default.post( data={"foo": "bar", "true": True, "false": False}, params={"foo": "bar", "true": True, "false": False}, ) - assert requests_mock.last_request is not None - assert requests_mock.last_request.query == "foo=bar&true=true&false=false" - assert requests_mock.last_request.text == "foo=bar&true=true&false=false" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.query == "foo=bar&true=true&false=false" + assert niquests_mock.last_request.text == "foo=bar&true=true&false=false" api_default.post( data={"foo": "bar", "true": True, "false": False}, params={"foo": "bar", "true": True, "false": False}, bool_fields=("OK", "KO"), ) - assert requests_mock.last_request is not None - assert requests_mock.last_request.query == "foo=bar&true=OK&false=KO" - assert requests_mock.last_request.text == "foo=bar&true=OK&false=KO" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.query == "foo=bar&true=OK&false=KO" + assert niquests_mock.last_request.text == "foo=bar&true=OK&false=KO" api_none = ApiClient(target_api, bool_fields=None) # default behviour or requests api_none.post( data={"foo": "bar", "true": True, "false": False}, params={"foo": "bar", "true": True, "false": False}, ) - assert requests_mock.last_request is not None - assert requests_mock.last_request.query == "foo=bar&true=True&false=False" - assert requests_mock.last_request.text == "foo=bar&true=True&false=False" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.query == "foo=bar&true=True&false=False" + assert niquests_mock.last_request.text == "foo=bar&true=True&false=False" api_yesno = ApiClient(target_api, bool_fields=("yes", "no")) api_yesno.post( data={"foo": "bar", "true": True, "false": False}, params={"foo": "bar", "true": True, "false": False}, ) - assert requests_mock.last_request is not None - assert requests_mock.last_request.query == "foo=bar&true=yes&false=no" - assert requests_mock.last_request.text == "foo=bar&true=yes&false=no" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.query == "foo=bar&true=yes&false=no" + assert niquests_mock.last_request.text == "foo=bar&true=yes&false=no" api_1_0 = ApiClient(target_api, bool_fields=(1, 0)) api_1_0.post( data={"foo": "bar", "true": True, "false": False}, params={"foo": "bar", "true": True, "false": False}, ) - assert requests_mock.last_request is not None - assert requests_mock.last_request.query == "foo=bar&true=1&false=0" - assert requests_mock.last_request.text == "foo=bar&true=1&false=0" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.query == "foo=bar&true=1&false=0" + assert niquests_mock.last_request.text == "foo=bar&true=1&false=0" with pytest.raises(ValueError, match="Invalid value for `bool_fields`") as exc: ApiClient(target_api).get(bool_fields=(1, 2, 3)) assert exc.type is InvalidBoolFieldsParam -def test_getattr(requests_mock: RequestsMocker, target_api: str) -> None: +def test_getattr(niquests_mock: NiquestsMocker, target_api: str) -> None: api = ApiClient(target_api) - requests_mock.post(target_api) + niquests_mock.post(target_api) assert api.post().ok - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None - requests_mock.reset_mock() - requests_mock.post(urljoin(target_api, "foo")) + niquests_mock.reset_mock() + niquests_mock.post(urljoin(target_api, "foo")) assert api.foo.post().ok - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None - requests_mock.reset_mock() - requests_mock.post(urljoin(target_api, "bar")) + niquests_mock.reset_mock() + niquests_mock.post(urljoin(target_api, "bar")) assert api.bar.post().ok - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None -def test_getitem(requests_mock: RequestsMocker, target_api: str) -> None: +def test_getitem(niquests_mock: NiquestsMocker, target_api: str) -> None: api = ApiClient(target_api) - requests_mock.post(target_api) + niquests_mock.post(target_api) assert api.post().ok - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None - requests_mock.reset_mock() - requests_mock.post(urljoin(target_api, "foo")) + niquests_mock.reset_mock() + niquests_mock.post(urljoin(target_api, "foo")) assert api["foo"].post().ok - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None - requests_mock.reset_mock() - requests_mock.post(urljoin(target_api, "bar")) + niquests_mock.reset_mock() + niquests_mock.post(urljoin(target_api, "bar")) assert api["bar"].post().ok - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None -def test_contextmanager(requests_mock: RequestsMocker, target_api: str) -> None: - requests_mock.post(target_api) +def test_contextmanager(niquests_mock: NiquestsMocker, target_api: str) -> None: + niquests_mock.post(target_api) with ApiClient(target_api) as api: api.post() - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None def test_cookies_and_headers(target_api: str) -> None: diff --git a/tests/unit_tests/test_auth.py b/tests/unit_tests/test_auth.py index 967542f..d909f0c 100644 --- a/tests/unit_tests/test_auth.py +++ b/tests/unit_tests/test_auth.py @@ -1,10 +1,10 @@ from datetime import datetime, timedelta, timezone from urllib.parse import parse_qs +import niquests import pytest -import requests -from requests_oauth2client import ( +from niquests_oauth2client import ( BearerToken, ExpiredAccessToken, NonRenewableTokenError, @@ -15,7 +15,7 @@ OAuth2DeviceCodeAuth, OAuth2ResourceOwnerPasswordAuth, ) -from tests.conftest import RequestsMocker +from tests.conftest import NiquestsMocker @pytest.fixture @@ -24,26 +24,26 @@ def minutes_ago() -> datetime: def test_bearer_auth( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, target_api: str, bearer_token: BearerToken, access_token: str, ) -> None: - requests_mock.post(target_api) - response = requests.post(target_api, auth=bearer_token) + niquests_mock.post(target_api) + response = niquests.post(target_api, auth=bearer_token) assert response.ok - assert requests_mock.last_request is not None - assert requests_mock.last_request.headers.get("Authorization") == f"Bearer {access_token}" + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.headers.get("Authorization") == f"Bearer {access_token}" def test_expired_token(minutes_ago: datetime) -> None: token = BearerToken(access_token="foo", expires_at=minutes_ago) with pytest.raises(ExpiredAccessToken): - requests.post("http://localhost/test", auth=token) + niquests.post("http://localhost/test", auth=token) def test_access_token_auth( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, target_uri: str, token_endpoint: str, client_id: str, @@ -62,8 +62,8 @@ def test_access_token_auth( assert auth.client is client assert auth.token is token - requests_mock.post(target_uri) - requests_mock.post( + niquests_mock.post(target_uri) + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -72,11 +72,11 @@ def test_access_token_auth( "token_type": "Bearer", }, ) - requests.post(target_uri, auth=auth) + niquests.post(target_uri, auth=auth) - assert len(requests_mock.request_history) == 2 - refresh_request = requests_mock.request_history[0] - api_request = requests_mock.request_history[-1] + assert len(niquests_mock.request_history) == 2 + refresh_request = niquests_mock.request_history[0] + api_request = niquests_mock.request_history[-1] assert refresh_request.url == token_endpoint refresh_params = parse_qs(refresh_request.body) @@ -96,7 +96,7 @@ def test_access_token_auth( def test_client_credentials_auth( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, target_api: str, token_endpoint: str, client_id: str, @@ -110,8 +110,8 @@ def test_client_credentials_auth( assert auth.client is client assert auth.token is None - requests_mock.post(target_api) - requests_mock.post( + niquests_mock.post(target_api) + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -120,11 +120,11 @@ def test_client_credentials_auth( "token_type": "Bearer", }, ) - requests.post(target_api, auth=auth) + niquests.post(target_api, auth=auth) - assert len(requests_mock.request_history) == 2 - cc_request = requests_mock.request_history[0] - api_request = requests_mock.request_history[-1] + assert len(niquests_mock.request_history) == 2 + cc_request = niquests_mock.request_history[0] + api_request = niquests_mock.request_history[-1] assert cc_request.url == token_endpoint refresh_params = parse_qs(cc_request.body) @@ -139,16 +139,16 @@ def test_client_credentials_auth( assert auth.token.access_token == access_token assert auth.token.refresh_token == refresh_token - requests_mock.reset_mock() - requests.post(target_api, auth=auth) - assert len(requests_mock.request_history) == 1 + niquests_mock.reset_mock() + niquests.post(target_api, auth=auth) + assert len(niquests_mock.request_history) == 1 assert OAuth2ClientCredentialsAuth(client, token=access_token).token == BearerToken(access_token) assert OAuth2ClientCredentialsAuth(client, token=BearerToken(access_token)).token == BearerToken(access_token) def test_authorization_code_auth( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, target_api: str, token_endpoint: str, client_id: str, @@ -164,8 +164,8 @@ def test_authorization_code_auth( assert auth.code is authorization_code assert auth.token is None - requests_mock.post(target_api) - requests_mock.post( + niquests_mock.post(target_api) + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -174,11 +174,11 @@ def test_authorization_code_auth( "token_type": "Bearer", }, ) - requests.post(target_api, auth=auth) + niquests.post(target_api, auth=auth) - assert len(requests_mock.request_history) == 2 - code_request = requests_mock.request_history[0] - api_request = requests_mock.request_history[-1] + assert len(niquests_mock.request_history) == 2 + code_request = niquests_mock.request_history[0] + api_request = niquests_mock.request_history[-1] assert code_request.url == token_endpoint refresh_params = parse_qs(code_request.body) @@ -194,9 +194,9 @@ def test_authorization_code_auth( assert auth.token.access_token == access_token assert auth.token.refresh_token == refresh_token - requests_mock.reset_mock() - requests.post(target_api, auth=auth) - assert len(requests_mock.request_history) == 1 + niquests_mock.reset_mock() + niquests.post(target_api, auth=auth) + assert len(niquests_mock.request_history) == 1 assert OAuth2AuthorizationCodeAuth(client, code=authorization_code, token=access_token).token == BearerToken( access_token @@ -204,7 +204,7 @@ def test_authorization_code_auth( def test_ropc_auth( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, target_api: str, token_endpoint: str, client_id: str, @@ -227,7 +227,7 @@ def test_ropc_auth( assert auth.password is password assert auth.token is None - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -236,19 +236,19 @@ def test_ropc_auth( "expires_in": "3600", }, ) - requests_mock.post(target_api) + niquests_mock.post(target_api) - assert requests.post(target_api, auth=auth).ok + assert niquests.post(target_api, auth=auth).ok - assert len(requests_mock.request_history) == 2 + assert len(niquests_mock.request_history) == 2 - token_request = requests_mock.request_history[0] + token_request = niquests_mock.request_history[0] token_params = parse_qs(token_request.body) assert token_params["grant_type"] == ["password"] assert token_params["username"] == [username] assert token_params["password"] == [password] - api_request = requests_mock.request_history[1] + api_request = niquests_mock.request_history[1] assert api_request.url == target_api assert api_request.headers.get("Authorization") == f"Bearer {access_token}" @@ -256,10 +256,10 @@ def test_ropc_auth( assert auth.token.access_token == access_token assert auth.token.refresh_token == refresh_token - requests_mock.reset_mock() - requests.post(target_api, auth=auth) - assert requests_mock.last_request is not None - assert requests_mock.last_request.url == target_api + niquests_mock.reset_mock() + niquests.post(target_api, auth=auth) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.url == target_api assert OAuth2ResourceOwnerPasswordAuth( oauth2client, username=username, password=password, token=access_token @@ -267,7 +267,7 @@ def test_ropc_auth( def test_device_code_auth( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, target_api: str, device_authorization_endpoint: str, token_endpoint: str, @@ -285,7 +285,7 @@ def test_device_code_auth( device_authorization_endpoint=device_authorization_endpoint, auth=(client_id, client_secret), ) - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, json={ "device_code": device_code, @@ -299,8 +299,8 @@ def test_device_code_auth( da_resp = oauth2client.authorize_device() - requests_mock.reset_mock() - requests_mock.post( + niquests_mock.reset_mock() + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -308,17 +308,17 @@ def test_device_code_auth( "refresh_token": refresh_token, }, ) - requests_mock.post(target_api) + niquests_mock.post(target_api) auth = OAuth2DeviceCodeAuth(client=oauth2client, device_code=da_resp.device_code, interval=1, expires_in=60) assert auth.client is oauth2client assert auth.device_code is da_resp.device_code assert auth.token is None - assert requests.post(target_api, auth=auth) - assert len(requests_mock.request_history) == 2 - device_code_request = requests_mock.request_history[0] - api_request = requests_mock.request_history[1] + assert niquests.post(target_api, auth=auth) + assert len(niquests_mock.request_history) == 2 + device_code_request = niquests_mock.request_history[0] + api_request = niquests_mock.request_history[1] assert device_code_request.url == token_endpoint da_params = parse_qs(device_code_request.body) @@ -334,14 +334,14 @@ def test_device_code_auth( assert auth.token.access_token == access_token assert auth.token.refresh_token == refresh_token - requests_mock.reset_mock() - requests.post(target_api, auth=auth) - assert requests_mock.last_request is not None - assert requests_mock.last_request.url == target_api + niquests_mock.reset_mock() + niquests.post(target_api, auth=auth) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.url == target_api auth.forget_token() with pytest.raises(NonRenewableTokenError): - requests.post(target_api, auth=auth) + niquests.post(target_api, auth=auth) assert OAuth2DeviceCodeAuth(oauth2client, device_code=device_code, token=access_token).token == BearerToken( access_token diff --git a/tests/unit_tests/test_authorization_request.py b/tests/unit_tests/test_authorization_request.py index bf99f84..c5ddd2f 100644 --- a/tests/unit_tests/test_authorization_request.py +++ b/tests/unit_tests/test_authorization_request.py @@ -7,7 +7,7 @@ from freezegun import freeze_time from jwskate import JweCompact, Jwk, Jwt, SignedJwt -from requests_oauth2client import ( +from niquests_oauth2client import ( AuthorizationRequest, AuthorizationRequestSerializer, AuthorizationResponse, diff --git a/tests/unit_tests/test_backchannel_authentication.py b/tests/unit_tests/test_backchannel_authentication.py index a3afe03..e29271e 100644 --- a/tests/unit_tests/test_backchannel_authentication.py +++ b/tests/unit_tests/test_backchannel_authentication.py @@ -7,7 +7,7 @@ import pytest from freezegun import freeze_time -from requests_oauth2client import ( +from niquests_oauth2client import ( BackChannelAuthenticationPoolingJob, BackChannelAuthenticationResponse, BaseClientAuthenticationMethod, @@ -23,7 +23,7 @@ from jwskate import Jwk from pytest_mock import MockerFixture - from tests.conftest import RequestsMocker, RequestValidatorType + from tests.conftest import NiquestsMocker, RequestValidatorType @freeze_time() @@ -72,7 +72,7 @@ def bca_client( @freeze_time() def test_backchannel_authentication( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, auth_req_id: str, @@ -82,33 +82,33 @@ def test_backchannel_authentication( token_endpoint: str, access_token: str, ) -> None: - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, json={"auth_req_id": auth_req_id, "expires_in": 360, "interval": 3}, ) bca_resp = bca_client.backchannel_authentication_request(scope=scope, login_hint="user@example.com") - assert requests_mock.called_once - backchannel_auth_request_validator(requests_mock.last_request, scope=scope, login_hint="user@example.com") + assert niquests_mock.called_once + backchannel_auth_request_validator(niquests_mock.last_request, scope=scope, login_hint="user@example.com") assert isinstance(bca_resp, BackChannelAuthenticationResponse) assert bca_resp.expires_in == 360 - requests_mock.post(token_endpoint, json={"access_token": access_token, "token_type": "Bearer"}) + niquests_mock.post(token_endpoint, json={"access_token": access_token, "token_type": "Bearer"}) token_resp = bca_client.ciba(bca_resp) assert isinstance(token_resp, BearerToken) - ciba_request_validator(requests_mock.last_request, auth_req_id=auth_req_id) + ciba_request_validator(niquests_mock.last_request, auth_req_id=auth_req_id) - requests_mock.reset() + niquests_mock.reset() bca_client.ciba(BackChannelAuthenticationResponse(auth_req_id=auth_req_id)) - assert requests_mock.called_once - ciba_request_validator(requests_mock.last_request, auth_req_id=auth_req_id) + assert niquests_mock.called_once + ciba_request_validator(niquests_mock.last_request, auth_req_id=auth_req_id) @freeze_time() def test_backchannel_authentication_scope_acr_values_as_list( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, auth_req_id: str, @@ -117,7 +117,7 @@ def test_backchannel_authentication_scope_acr_values_as_list( scope = ("openid", "email", "profile") acr_values = ("reinforced", "strong") - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, json={"auth_req_id": auth_req_id, "expires_in": 360, "interval": 3}, ) @@ -125,9 +125,9 @@ def test_backchannel_authentication_scope_acr_values_as_list( scope=scope, acr_values=acr_values, login_hint="user@example.com" ) - assert requests_mock.called_once + assert niquests_mock.called_once backchannel_auth_request_validator( - requests_mock.last_request, scope=scope, acr_values=acr_values, login_hint="user@example.com" + niquests_mock.last_request, scope=scope, acr_values=acr_values, login_hint="user@example.com" ) assert isinstance(bca_resp, BackChannelAuthenticationResponse) @@ -139,25 +139,25 @@ def test_backchannel_authentication_scope_acr_values_as_list( def test_backchannel_authentication_invalid_response( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, scope: None | str | list[str], backchannel_auth_request_validator: RequestValidatorType, ) -> None: - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, json={"foo": "bar"}, ) with pytest.raises(InvalidBackChannelAuthenticationResponse): bca_client.backchannel_authentication_request(scope=scope, login_hint="user@example.com") - assert requests_mock.called_once - backchannel_auth_request_validator(requests_mock.last_request, scope=scope, login_hint="user@example.com") + assert niquests_mock.called_once + backchannel_auth_request_validator(niquests_mock.last_request, scope=scope, login_hint="user@example.com") def test_backchannel_authentication_jwt( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, private_jwk: Jwk, @@ -166,7 +166,7 @@ def test_backchannel_authentication_jwt( scope: None | str | list[str], backchannel_auth_request_jwt_validator: RequestValidatorType, ) -> None: - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, json={"auth_req_id": auth_req_id, "expires_in": 360, "interval": 3}, ) @@ -174,9 +174,9 @@ def test_backchannel_authentication_jwt( private_jwk=private_jwk, scope=scope, login_hint="user@example.com", alg="RS256" ) - assert requests_mock.called_once + assert niquests_mock.called_once backchannel_auth_request_jwt_validator( - requests_mock.last_request, + niquests_mock.last_request, public_jwk=public_jwk, alg="RS256", scope=scope, @@ -187,13 +187,13 @@ def test_backchannel_authentication_jwt( def test_backchannel_authentication_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, scope: None | str | list[str], backchannel_auth_request_validator: RequestValidatorType, ) -> None: - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, status_code=400, json={"error": "unauthorized_client"}, @@ -201,18 +201,18 @@ def test_backchannel_authentication_error( with pytest.raises(UnauthorizedClient): bca_client.backchannel_authentication_request(scope=scope, login_hint="user@example.com") - assert requests_mock.called_once - backchannel_auth_request_validator(requests_mock.last_request, scope=scope, login_hint="user@example.com") + assert niquests_mock.called_once + backchannel_auth_request_validator(niquests_mock.last_request, scope=scope, login_hint="user@example.com") def test_backchannel_authentication_invalid_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, scope: None | str | list[str], backchannel_auth_request_validator: RequestValidatorType, ) -> None: - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, status_code=400, json={"foo": "bar"}, @@ -220,18 +220,18 @@ def test_backchannel_authentication_invalid_error( with pytest.raises(InvalidBackChannelAuthenticationResponse): bca_client.backchannel_authentication_request(scope=scope, login_hint="user@example.com") - assert requests_mock.called_once - backchannel_auth_request_validator(requests_mock.last_request, scope=scope, login_hint="user@example.com") + assert niquests_mock.called_once + backchannel_auth_request_validator(niquests_mock.last_request, scope=scope, login_hint="user@example.com") def test_backchannel_authentication_not_json_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, backchannel_authentication_endpoint: str, bca_client: OAuth2Client, scope: None | str | list[str], backchannel_auth_request_validator: RequestValidatorType, ) -> None: - requests_mock.post( + niquests_mock.post( backchannel_authentication_endpoint, status_code=400, text="Error!", @@ -239,8 +239,8 @@ def test_backchannel_authentication_not_json_error( with pytest.raises(InvalidBackChannelAuthenticationResponse): bca_client.backchannel_authentication_request(scope=scope, login_hint="user@example.com") - assert requests_mock.called_once - backchannel_auth_request_validator(requests_mock.last_request, scope=scope, login_hint="user@example.com") + assert niquests_mock.called_once + backchannel_auth_request_validator(niquests_mock.last_request, scope=scope, login_hint="user@example.com") def test_backchannel_authentication_missing_hint( @@ -265,7 +265,7 @@ def test_backchannel_authentication_invalid_scope(bca_client: OAuth2Client) -> N def test_pooling_job( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, bca_client: OAuth2Client, token_endpoint: str, auth_req_id: str, @@ -284,38 +284,38 @@ def test_pooling_job( BackChannelAuthenticationResponse(auth_req_id, interval=interval), ) - requests_mock.post(token_endpoint, status_code=401, json={"error": "authorization_pending"}) + niquests_mock.post(token_endpoint, status_code=401, json={"error": "authorization_pending"}) mocker.patch("time.sleep") assert job() is None time.sleep.assert_called_once_with(job.interval) # type: ignore[attr-defined] time.sleep.reset_mock() # type: ignore[attr-defined] - assert requests_mock.called_once + assert niquests_mock.called_once assert job.interval == interval - ciba_request_validator(requests_mock.last_request, auth_req_id=auth_req_id) + ciba_request_validator(niquests_mock.last_request, auth_req_id=auth_req_id) freezer.tick(job.interval) - requests_mock.reset_mock() - requests_mock.post(token_endpoint, status_code=401, json={"error": "slow_down"}) + niquests_mock.reset_mock() + niquests_mock.post(token_endpoint, status_code=401, json={"error": "slow_down"}) assert job() is None time.sleep.assert_called_once_with(interval) # type: ignore[attr-defined] time.sleep.reset_mock() # type: ignore[attr-defined] - assert requests_mock.called_once + assert niquests_mock.called_once assert job.interval == interval + job.slow_down_interval - ciba_request_validator(requests_mock.last_request, auth_req_id=auth_req_id) + ciba_request_validator(niquests_mock.last_request, auth_req_id=auth_req_id) freezer.tick(job.interval) - requests_mock.reset_mock() - requests_mock.post(token_endpoint, json={"access_token": access_token}) + niquests_mock.reset_mock() + niquests_mock.post(token_endpoint, json={"access_token": access_token}) token = job() time.sleep.assert_called_once_with(interval + job.slow_down_interval) # type: ignore[attr-defined] time.sleep.reset_mock() # type: ignore[attr-defined] - assert requests_mock.called_once + assert niquests_mock.called_once assert job.interval == interval + job.slow_down_interval - ciba_request_validator(requests_mock.last_request, auth_req_id=auth_req_id) + ciba_request_validator(niquests_mock.last_request, auth_req_id=auth_req_id) assert isinstance(token, BearerToken) assert token.access_token == access_token diff --git a/tests/unit_tests/test_client.py b/tests/unit_tests/test_client.py index 53685b5..ca1a0bb 100644 --- a/tests/unit_tests/test_client.py +++ b/tests/unit_tests/test_client.py @@ -4,12 +4,11 @@ from datetime import datetime, timedelta, timezone from typing import TYPE_CHECKING +import niquests import pytest -import requests.auth from jwskate import Jwk, JwkSet, Jwt, KeyManagementAlgs, SignatureAlgs -from requests import HTTPError -from requests_oauth2client import ( +from niquests_oauth2client import ( AuthorizationRequest, BackChannelAuthenticationResponse, BaseClientAuthenticationMethod, @@ -36,7 +35,7 @@ ) if TYPE_CHECKING: - from tests.conftest import RequestsMocker, RequestValidatorType + from tests.conftest import NiquestsMocker, RequestValidatorType def test_public_client_auth(token_endpoint: str, client_id: str) -> None: @@ -89,7 +88,7 @@ def test_invalid_auth(token_endpoint: str) -> None: def test_client_credentials_grant( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, access_token: str, @@ -111,7 +110,7 @@ def test_client_credentials_grant( It sends a request to the Token Endpoint using the Client Credentials grant. """ - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -123,33 +122,33 @@ def test_client_credentials_grant( oauth2client.client_credentials(scope=scope) - assert requests_mock.called_once - client_credentials_grant_validator(requests_mock.last_request, scope=scope) + assert niquests_mock.called_once + client_credentials_grant_validator(niquests_mock.last_request, scope=scope) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=token_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=token_endpoint, public_jwk=public_jwk, @@ -162,11 +161,11 @@ def test_client_credentials_invalid_scope(oauth2client: OAuth2Client) -> None: def test_token_endpoint_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, ) -> None: - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "error": "server_error", @@ -186,7 +185,7 @@ def test_token_endpoint_error( def test_authorization_code_grant( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, authorization_code: str, @@ -208,7 +207,7 @@ def test_authorization_code_grant( It sends a request to the Token Endpoint using the Authorization Code grant. """ - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -220,33 +219,33 @@ def test_authorization_code_grant( oauth2client.authorization_code(code=authorization_code) - assert requests_mock.called_once - authorization_code_grant_validator(requests_mock.last_request, code=authorization_code) + assert niquests_mock.called_once + authorization_code_grant_validator(niquests_mock.last_request, code=authorization_code) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=token_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=token_endpoint, public_jwk=public_jwk, @@ -254,7 +253,7 @@ def test_authorization_code_grant( def test_refresh_token_grant( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, refresh_token: str, @@ -276,7 +275,7 @@ def test_refresh_token_grant( """ new_access_token = secrets.token_urlsafe() new_refresh_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -286,38 +285,38 @@ def test_refresh_token_grant( }, ) token_resp = oauth2client.refresh_token(refresh_token) - assert requests_mock.called_once + assert niquests_mock.called_once assert not token_resp.is_expired() assert token_resp.access_token == new_access_token assert token_resp.refresh_token == new_refresh_token - refresh_token_grant_validator(requests_mock.last_request, refresh_token=refresh_token) + refresh_token_grant_validator(niquests_mock.last_request, refresh_token=refresh_token) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=token_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=token_endpoint, public_jwk=public_jwk, @@ -325,7 +324,7 @@ def test_refresh_token_grant( def test_refresh_token_with_bearer_instance_as_param( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, access_token: str, @@ -343,7 +342,7 @@ def test_refresh_token_with_bearer_instance_as_param( ) -> None: new_access_token = secrets.token_urlsafe() new_refresh_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -353,38 +352,38 @@ def test_refresh_token_with_bearer_instance_as_param( }, ) token_resp = oauth2client.refresh_token(BearerToken(access_token=access_token, refresh_token=refresh_token)) - assert requests_mock.called_once + assert niquests_mock.called_once assert not token_resp.is_expired() assert token_resp.access_token == new_access_token assert token_resp.refresh_token == new_refresh_token - refresh_token_grant_validator(requests_mock.last_request, refresh_token=refresh_token) + refresh_token_grant_validator(niquests_mock.last_request, refresh_token=refresh_token) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=token_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=token_endpoint, public_jwk=public_jwk, @@ -392,7 +391,7 @@ def test_refresh_token_with_bearer_instance_as_param( def test_ressource_owner_password_grant( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, ) -> None: @@ -401,7 +400,7 @@ def test_ressource_owner_password_grant( scope = "foo" new_access_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -412,7 +411,7 @@ def test_ressource_owner_password_grant( ) oauth2client.resource_owner_password(username, password, scope=scope) - assert requests_mock.called_once + assert niquests_mock.called_once def test_grants_with_invalid_response_objects_as_parameter(oauth2client: OAuth2Client) -> None: @@ -425,7 +424,7 @@ def test_grants_with_invalid_response_objects_as_parameter(oauth2client: OAuth2C def test_device_code_grant( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, device_code: str, @@ -443,7 +442,7 @@ def test_device_code_grant( """.device_code() sends a requests to the Token Endpoint using the Device Code grant.""" new_access_token = secrets.token_urlsafe() new_refresh_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -454,52 +453,52 @@ def test_device_code_grant( ) token_resp = oauth2client.device_code(device_code) - assert requests_mock.called_once + assert niquests_mock.called_once assert not token_resp.is_expired() assert token_resp.access_token == new_access_token assert token_resp.refresh_token == new_refresh_token - device_code_grant_validator(requests_mock.last_request, device_code=device_code) + device_code_grant_validator(niquests_mock.last_request, device_code=device_code) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=token_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=token_endpoint, public_jwk=public_jwk, ) - requests_mock.reset() + niquests_mock.reset() oauth2client.device_code( DeviceAuthorizationResponse(device_code=device_code, user_code="user_code", verification_uri="https://foo.bar") ) - assert requests_mock.called_once - device_code_grant_validator(requests_mock.last_request, device_code=device_code) + assert niquests_mock.called_once + device_code_grant_validator(niquests_mock.last_request, device_code=device_code) def test_token_exchange_grant( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, client_id: str, @@ -518,7 +517,7 @@ def test_token_exchange_grant( actor_token = secrets.token_urlsafe() new_access_token = secrets.token_urlsafe() new_refresh_token = secrets.token_urlsafe() - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": new_access_token, @@ -533,41 +532,41 @@ def test_token_exchange_grant( actor_token=actor_token, actor_token_type="access_token", ) - assert requests_mock.called_once + assert niquests_mock.called_once assert not token_resp.is_expired() assert token_resp.access_token == new_access_token assert token_resp.refresh_token == new_refresh_token token_exchange_grant_validator( - requests_mock.last_request, + niquests_mock.last_request, subject_token=subject_token, subject_token_type="urn:ietf:params:oauth:token-type:access_token", ) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=token_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=token_endpoint, public_jwk=public_jwk, @@ -583,7 +582,7 @@ def test_token_exchange_invalid_tokens(oauth2client: OAuth2Client) -> None: def test_userinfo( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, userinfo_endpoint: str, bearer_auth_validator: RequestValidatorType, @@ -592,12 +591,12 @@ def test_userinfo( ) -> None: """.userinfo_endpoint() sends a requests to the Userinfo Endpoint and returns a JSON.""" userinfo = {"sub": sub} - requests_mock.post(userinfo_endpoint, json=userinfo) + niquests_mock.post(userinfo_endpoint, json=userinfo) resp = oauth2client.userinfo(access_token) - assert requests_mock.last_request is not None + assert niquests_mock.last_request is not None assert resp == userinfo - bearer_auth_validator(requests_mock.last_request, access_token=access_token) - assert requests_mock.last_request.headers["Accept"] == "application/json" + bearer_auth_validator(niquests_mock.last_request, access_token=access_token) + assert niquests_mock.last_request.headers["Accept"] == "application/json" def test_userinfo_no_uri(token_endpoint: str, client_id: str) -> None: @@ -608,13 +607,13 @@ def test_userinfo_no_uri(token_endpoint: str, client_id: str) -> None: def test_userinfo_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, userinfo_endpoint: str, access_token: str, ) -> None: - requests_mock.post(userinfo_endpoint, json={"error": "access_denied"}, status_code=401) - with pytest.raises(HTTPError): + niquests_mock.post(userinfo_endpoint, json={"error": "access_denied"}, status_code=401) + with pytest.raises(niquests.HTTPError): oauth2client.userinfo(access_token) @@ -713,7 +712,7 @@ def test_from_discovery_document_test_issuer(token_endpoint: str, client_id: str def test_from_discovery_endpoint( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, issuer: str, discovery_document: dict[str, str], jwks_uri: str, @@ -722,13 +721,13 @@ def test_from_discovery_endpoint( ) -> None: discovery_url = oidc_discovery_document_url(issuer) - requests_mock.get(discovery_url, json=discovery_document) - requests_mock.get(jwks_uri, json=as_public_jwks.to_dict()) + niquests_mock.get(discovery_url, json=discovery_document) + niquests_mock.get(jwks_uri, json=as_public_jwks.to_dict()) client = OAuth2Client.from_discovery_endpoint(discovery_url, issuer, auth=client_auth_method) - assert requests_mock.request_history[0].url == discovery_url - assert requests_mock.request_history[1].url == jwks_uri + assert niquests_mock.request_history[0].url == discovery_url + assert niquests_mock.request_history[1].url == jwks_uri assert isinstance(client, OAuth2Client) assert client.auth == client_auth_method assert client.authorization_server_jwks == as_public_jwks @@ -737,44 +736,44 @@ def test_from_discovery_endpoint( OAuth2Client.from_discovery_endpoint() -def test_invalid_token_response(requests_mock: RequestsMocker, token_endpoint: str, client_id: str) -> None: +def test_invalid_token_response(niquests_mock: NiquestsMocker, token_endpoint: str, client_id: str) -> None: """Token Endpoint error responses outside the standard raises an InvalidTokenResponse.""" client = OAuth2Client(token_endpoint, auth=client_id) - requests_mock.post(token_endpoint, status_code=500, json={"confusing": "data"}) + niquests_mock.post(token_endpoint, status_code=500, json={"confusing": "data"}) with pytest.raises(InvalidTokenResponse): client.authorization_code("mycode") - requests_mock.reset_mock() - requests_mock.post( + niquests_mock.reset_mock() + niquests_mock.post( token_endpoint, status_code=500, json={"error_description": "this shouldn't happen"}, ) with pytest.raises(InvalidTokenResponse): client.authorization_code("mycode") - assert requests_mock.called_once + assert niquests_mock.called_once -def test_invalid_token_response_200(requests_mock: RequestsMocker, token_endpoint: str, client_id: str) -> None: +def test_invalid_token_response_200(niquests_mock: NiquestsMocker, token_endpoint: str, client_id: str) -> None: """Token Endpoint successful responses outside the standard raises an InvalidTokenResponse.""" client = OAuth2Client(token_endpoint, auth=client_id) - requests_mock.post(token_endpoint, status_code=200, json={"confusing": "data"}) + niquests_mock.post(token_endpoint, status_code=200, json={"confusing": "data"}) with pytest.raises(InvalidTokenResponse): client.authorization_code("mycode") - requests_mock.reset_mock() - requests_mock.post( + niquests_mock.reset_mock() + niquests_mock.post( token_endpoint, status_code=200, json={"foo": "this shouldn't happen"}, ) with pytest.raises(InvalidTokenResponse): client.authorization_code("mycode") - assert requests_mock.called_once + assert niquests_mock.called_once def test_revoke_access_token( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -797,37 +796,37 @@ def test_revoke_access_token( """ client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) - requests_mock.post(revocation_endpoint) + niquests_mock.post(revocation_endpoint) assert client.revoke_access_token(access_token) is True - assert requests_mock.called_once - revocation_request_validator(requests_mock.last_request, token=access_token, type_hint="access_token") + assert niquests_mock.called_once + revocation_request_validator(niquests_mock.last_request, token=access_token, type_hint="access_token") if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=revocation_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=revocation_endpoint, public_jwk=public_jwk, @@ -835,7 +834,7 @@ def test_revoke_access_token( def test_revoke_refresh_token( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -857,35 +856,35 @@ def test_revoke_refresh_token( """ client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) - requests_mock.post(revocation_endpoint) + niquests_mock.post(revocation_endpoint) assert client.revoke_refresh_token(refresh_token) is True - assert requests_mock.called_once - revocation_request_validator(requests_mock.last_request, token=refresh_token, type_hint="refresh_token") + assert niquests_mock.called_once + revocation_request_validator(niquests_mock.last_request, token=refresh_token, type_hint="refresh_token") if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=revocation_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=revocation_endpoint, public_jwk=public_jwk, @@ -893,7 +892,7 @@ def test_revoke_refresh_token( def test_revoke_refresh_token_with_bearer_token_as_param( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -909,12 +908,12 @@ def test_revoke_refresh_token_with_bearer_token_as_param( """ client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) bearer = BearerToken(access_token, refresh_token=refresh_token) - requests_mock.post(revocation_endpoint) + niquests_mock.post(revocation_endpoint) assert client.revoke_refresh_token(bearer) is True - assert requests_mock.called_once + assert niquests_mock.called_once revocation_request_validator( - requests_mock.last_request, + niquests_mock.last_request, token=bearer.refresh_token, type_hint="refresh_token", ) @@ -925,7 +924,7 @@ def test_revoke_refresh_token_with_bearer_token_as_param( def test_revoke_token( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -943,37 +942,37 @@ def test_revoke_token( ) -> None: """.revoke_token() sends a Revocation request to the Revocation Endpoint.""" client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) - requests_mock.post(revocation_endpoint, status_code=200) + niquests_mock.post(revocation_endpoint, status_code=200) assert client.revoke_token(refresh_token) is True - assert requests_mock.called_once - revocation_request_validator(requests_mock.last_request, refresh_token) + assert niquests_mock.called_once + revocation_request_validator(niquests_mock.last_request, refresh_token) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=revocation_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=revocation_endpoint, public_jwk=public_jwk, @@ -981,7 +980,7 @@ def test_revoke_token( def test_revoke_token_with_bearer_token_as_param( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -996,12 +995,12 @@ def test_revoke_token_with_bearer_token_as_param( """ client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) bearer = BearerToken(access_token, refresh_token=refresh_token) - requests_mock.post(revocation_endpoint, status_code=200) + niquests_mock.post(revocation_endpoint, status_code=200) assert client.revoke_token(bearer, token_type_hint="refresh_token") is True - assert requests_mock.called_once - revocation_request_validator(requests_mock.last_request, refresh_token) + assert niquests_mock.called_once + revocation_request_validator(niquests_mock.last_request, refresh_token) bearer_no_refresh = BearerToken(access_token) with pytest.raises(ValueError): @@ -1009,7 +1008,7 @@ def test_revoke_token_with_bearer_token_as_param( def test_revoke_token_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -1027,38 +1026,38 @@ def test_revoke_token_error( ) -> None: """Test for OAuth2Client.revoke_token() error cases.""" client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) - requests_mock.post(revocation_endpoint, status_code=400, json={"error": "server_error"}) + niquests_mock.post(revocation_endpoint, status_code=400, json={"error": "server_error"}) with pytest.raises(ServerError): client.revoke_token(refresh_token) - assert requests_mock.called_once - revocation_request_validator(requests_mock.last_request, refresh_token) + assert niquests_mock.called_once + revocation_request_validator(niquests_mock.last_request, refresh_token) if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=revocation_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=revocation_endpoint, public_jwk=public_jwk, @@ -1066,7 +1065,7 @@ def test_revoke_token_error( def test_revoke_token_error_non_standard( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, revocation_endpoint: str, client_auth_method: BaseClientAuthenticationMethod, @@ -1078,15 +1077,15 @@ def test_revoke_token_error_non_standard( """ client = OAuth2Client(token_endpoint, revocation_endpoint=revocation_endpoint, auth=client_auth_method) - requests_mock.post(revocation_endpoint, status_code=400, text="Error") + niquests_mock.post(revocation_endpoint, status_code=400, text="Error") assert client.revoke_token(refresh_token) is False - assert requests_mock.called_once + assert niquests_mock.called_once - requests_mock.reset_mock() - requests_mock.post(revocation_endpoint, status_code=400, json={"foo": "bar"}) + niquests_mock.reset_mock() + niquests_mock.post(revocation_endpoint, status_code=400, json={"foo": "bar"}) assert client.revoke_token(refresh_token) is False - assert requests_mock.called_once + assert niquests_mock.called_once def test_revoke_token_no_revocation_endpoint(token_endpoint: str, client_id: str) -> None: @@ -1098,17 +1097,17 @@ def test_revoke_token_no_revocation_endpoint(token_endpoint: str, client_id: str def test_server_jwks( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, jwks_uri: str, server_public_jwks: JwkSet, ) -> None: """Use OAuth2Client as a context manager to automatically get public JWKS from its JWKS URI.""" assert not oauth2client.authorization_server_jwks - requests_mock.get(jwks_uri, json=server_public_jwks.to_dict()) + niquests_mock.get(jwks_uri, json=server_public_jwks.to_dict()) with oauth2client as client: assert client.authorization_server_jwks == server_public_jwks - assert requests_mock.called_once + assert niquests_mock.called_once def test_server_jwks_no_jwks_uri(token_endpoint: str) -> None: @@ -1118,21 +1117,21 @@ def test_server_jwks_no_jwks_uri(token_endpoint: str) -> None: client.update_authorization_server_public_keys() -def test_server_jwks_not_json(requests_mock: RequestsMocker, token_endpoint: str, jwks_uri: str) -> None: +def test_server_jwks_not_json(niquests_mock: NiquestsMocker, token_endpoint: str, jwks_uri: str) -> None: """If JWKS URI is not known, get_public_jwks() raises an exception.""" - requests_mock.get(jwks_uri, text="Hello World!") + niquests_mock.get(jwks_uri, text="Hello World!") client = OAuth2Client(token_endpoint=token_endpoint, jwks_uri=jwks_uri, auth=("foo", "bar")) with pytest.raises(ValueError): client.update_authorization_server_public_keys() - assert requests_mock.called_once + assert niquests_mock.called_once -def test_server_jwks_invalid_doc(requests_mock: RequestsMocker, token_endpoint: str, jwks_uri: str) -> None: +def test_server_jwks_invalid_doc(niquests_mock: NiquestsMocker, token_endpoint: str, jwks_uri: str) -> None: """If JWKS URI is an invalid document, get_public_jwks() raises an exception.""" - requests_mock.get(jwks_uri, json={"foo": "bar"}) + niquests_mock.get(jwks_uri, json={"foo": "bar"}) client = OAuth2Client(token_endpoint=token_endpoint, jwks_uri=jwks_uri, auth=("foo", "bar")) jwks = client.update_authorization_server_public_keys() - assert requests_mock.called_once + assert niquests_mock.called_once assert not jwks.jwks @@ -1193,7 +1192,7 @@ def test_get_token_type() -> None: def test_introspection( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, introspection_endpoint: str, introspection_request_validator: RequestValidatorType, @@ -1208,36 +1207,36 @@ def test_introspection( public_jwk: Jwk, ) -> None: introspection_data = {"active": False} - requests_mock.post(introspection_endpoint, json=introspection_data) + niquests_mock.post(introspection_endpoint, json=introspection_data) data = oauth2client.introspect_token("access_token") assert data == introspection_data - assert requests_mock.called_once - introspection_request_validator(requests_mock.last_request, token="access_token") + assert niquests_mock.called_once + introspection_request_validator(niquests_mock.last_request, token="access_token") if client_auth_method_handler == PublicApp: - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) elif client_auth_method_handler == ClientSecretPost: client_secret_post_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretBasic: client_secret_basic_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, ) elif client_auth_method_handler == ClientSecretJwt: client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_credential, endpoint=introspection_endpoint, ) elif client_auth_method_handler == PrivateKeyJwt: private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, endpoint=introspection_endpoint, public_jwk=public_jwk, @@ -1256,72 +1255,72 @@ def test_introspection_no_introspection_endpoint( def test_introspection_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, introspection_endpoint: str, introspection_request_validator: RequestValidatorType, ) -> None: - requests_mock.post(introspection_endpoint, status_code=400, json={"error": "unauthorized_client"}) + niquests_mock.post(introspection_endpoint, status_code=400, json={"error": "unauthorized_client"}) with pytest.raises(UnauthorizedClient): oauth2client.introspect_token("access_token") - assert requests_mock.called_once - introspection_request_validator(requests_mock.last_request, token="access_token") + assert niquests_mock.called_once + introspection_request_validator(niquests_mock.last_request, token="access_token") def test_introspection_jwt( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, introspection_endpoint: str, introspection_request_validator: RequestValidatorType, ) -> None: introspection = "This.ShouldBe.aJWT" - requests_mock.post(introspection_endpoint, text=introspection) + niquests_mock.post(introspection_endpoint, text=introspection) assert oauth2client.introspect_token("access_token") == introspection - assert requests_mock.called_once - introspection_request_validator(requests_mock.last_request, token="access_token") + assert niquests_mock.called_once + introspection_request_validator(niquests_mock.last_request, token="access_token") def test_introspection_unknown_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, introspection_endpoint: str, introspection_request_validator: RequestValidatorType, ) -> None: - requests_mock.post(introspection_endpoint, status_code=400, text="Error") + niquests_mock.post(introspection_endpoint, status_code=400, text="Error") with pytest.raises(UnknownIntrospectionError): oauth2client.introspect_token("access_token") - assert requests_mock.called_once - introspection_request_validator(requests_mock.last_request, token="access_token") + assert niquests_mock.called_once + introspection_request_validator(niquests_mock.last_request, token="access_token") - requests_mock.reset_mock() - requests_mock.post(introspection_endpoint, status_code=400, json={"foo": "bar"}) + niquests_mock.reset_mock() + niquests_mock.post(introspection_endpoint, status_code=400, json={"foo": "bar"}) with pytest.raises(UnknownIntrospectionError): oauth2client.introspect_token("access_token") - assert requests_mock.called_once + assert niquests_mock.called_once def test_introspection_with_bearer_token_as_param( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, introspection_endpoint: str, access_token: str, refresh_token: str, introspection_request_validator: RequestValidatorType, ) -> None: - requests_mock.post(introspection_endpoint, status_code=200, json={"active": False}) + niquests_mock.post(introspection_endpoint, status_code=200, json={"active": False}) bearer = BearerToken(access_token, refresh_token=refresh_token) assert oauth2client.introspect_token(bearer, "refresh_token") - assert requests_mock.called_once - introspection_request_validator(requests_mock.last_request, token=refresh_token, type_hint="refresh_token") + assert niquests_mock.called_once + introspection_request_validator(niquests_mock.last_request, token=refresh_token, type_hint="refresh_token") - requests_mock.reset() + niquests_mock.reset() assert oauth2client.introspect_token(bearer, token_type_hint="access_token") - assert requests_mock.called_once - introspection_request_validator(requests_mock.last_request, token=access_token, type_hint="access_token") + assert niquests_mock.called_once + introspection_request_validator(niquests_mock.last_request, token=access_token, type_hint="access_token") bearer_no_refresh = BearerToken(access_token, refresh_token=None) with pytest.raises(ValueError): @@ -1332,22 +1331,22 @@ def test_introspection_with_bearer_token_as_param( def test_ciba( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, auth_req_id: str, token_endpoint: str, access_token: str, ciba_request_validator: RequestValidatorType, ) -> None: - requests_mock.post(token_endpoint, json={"access_token": access_token, "expires_in": 60}) + niquests_mock.post(token_endpoint, json={"access_token": access_token, "expires_in": 60}) token = oauth2client.ciba(auth_req_id=auth_req_id) assert isinstance(token, BearerToken) - assert requests_mock.called_once - ciba_request_validator(requests_mock.last_request, auth_req_id=auth_req_id) + assert niquests_mock.called_once + ciba_request_validator(niquests_mock.last_request, auth_req_id=auth_req_id) def test_pushed_authorization_request( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, pushed_authorization_request_endpoint: str, authorization_request: AuthorizationRequest, @@ -1355,7 +1354,7 @@ def test_pushed_authorization_request( request_uri = "request_uri" expires_in = 60 - requests_mock.post( + niquests_mock.post( pushed_authorization_request_endpoint, json={"request_uri": request_uri, "expires_in": expires_in}, ) @@ -1368,28 +1367,28 @@ def test_pushed_authorization_request( def test_pushed_authorization_request_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, pushed_authorization_request_endpoint: str, authorization_request: AuthorizationRequest, ) -> None: - requests_mock.post(pushed_authorization_request_endpoint, json={"error": "server_error"}, status_code=500) + niquests_mock.post(pushed_authorization_request_endpoint, json={"error": "server_error"}, status_code=500) with pytest.raises(ServerError): oauth2client.pushed_authorization_request(authorization_request) - requests_mock.post(pushed_authorization_request_endpoint, text="foobar", status_code=500) + niquests_mock.post(pushed_authorization_request_endpoint, text="foobar", status_code=500) with pytest.raises(InvalidPushedAuthorizationResponse): oauth2client.pushed_authorization_request(authorization_request) -def test_jwt_bearer_grant(requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: +def test_jwt_bearer_grant(niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: key = Jwk.generate(alg="ES256") assertion = Jwt.sign({"iat": 1661759343, "exp": 1661759403, "sub": "some_user_id"}, key) scope = "my_scope" - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": "access_token", "token_type": "Bearer", "scope": scope}, ) @@ -1397,14 +1396,14 @@ def test_jwt_bearer_grant(requests_mock: RequestsMocker, oauth2client: OAuth2Cli # pass the assertion as a `Jwt` token = oauth2client.jwt_bearer(assertion=assertion, scope=scope) assert isinstance(token, BearerToken) - assert requests_mock.called_once + assert niquests_mock.called_once assert token.scope == scope # pass the assertion as `str` - requests_mock.reset_mock() + niquests_mock.reset_mock() token = oauth2client.jwt_bearer(assertion=str(assertion), scope=scope) assert isinstance(token, BearerToken) - assert requests_mock.called_once + assert niquests_mock.called_once assert token.scope == scope @@ -1421,13 +1420,13 @@ def test_authorization_request(oauth2client: OAuth2Client, authorization_endpoin assert exc.type is UnsupportedResponseTypeParam -def test_custom_token_type(requests_mock: RequestsMocker, token_endpoint: str) -> None: +def test_custom_token_type(niquests_mock: NiquestsMocker, token_endpoint: str) -> None: class CustomBearerToken(BearerToken): TOKEN_TYPE = "CustomBearerToken" client = OAuth2Client(token_endpoint, ("client_id", "client_secret"), token_class=CustomBearerToken) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": "access_token", "token_type": "CustomBearerToken"}, ) @@ -1499,8 +1498,8 @@ def test_client_id_token_decryption_key() -> None: def test_client_custom_auth_method() -> None: - class CustomAuthHandler(requests.auth.AuthBase): - def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest: + class CustomAuthHandler(niquests.auth.AuthBase): + def __call__(self, request: niquests.PreparedRequest) -> niquests.PreparedRequest: request.headers["Super-Secure"] = "true" return request @@ -1533,40 +1532,40 @@ def test_testing_oauth2client() -> None: assert test_client.issuer == issuer -def test_proxy_authorization(requests_mock: RequestsMocker, target_api: str) -> None: +def test_proxy_authorization(niquests_mock: NiquestsMocker, target_api: str) -> None: access_token = "my_proxy_auth_token" auth_header = "Proxy-Authorization" class ProxyAuthorizationBearerToken(BearerToken): AUTHORIZATION_HEADER = auth_header - requests_mock.post(target_api) + niquests_mock.post(target_api) - requests.post(target_api, auth=ProxyAuthorizationBearerToken(access_token)) - assert requests_mock.last_request is not None - assert requests_mock.last_request.headers[auth_header] == f"Bearer {access_token}" + niquests.post(target_api, auth=ProxyAuthorizationBearerToken(access_token)) + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.headers[auth_header] == f"Bearer {access_token}" -def test_custom_ports_in_endpoints(requests_mock: RequestsMocker) -> None: +def test_custom_ports_in_endpoints(niquests_mock: NiquestsMocker) -> None: issuer = "https://as.local:8443" token_endpoint = "https://as.local:8443/token" client = OAuth2Client(token_endpoint=token_endpoint, client_id="client_id", client_secret="client_secret") assert client.token_endpoint == token_endpoint - assert not requests_mock.called_once + assert not niquests_mock.called_once with pytest.raises(InvalidIssuer, match="must use https"): OAuth2Client.from_discovery_endpoint(issuer="http://as.local") - assert not requests_mock.called_once + assert not niquests_mock.called_once with pytest.raises(InvalidIssuer, match="must use https"): OAuth2Client.from_discovery_endpoint(issuer="http://as.local:8080") - assert not requests_mock.called_once + assert not niquests_mock.called_once with pytest.raises(InvalidUri, match="must use https"): OAuth2Client.from_discovery_endpoint(url="http://as.local/.well-known/openid-configuration") - assert not requests_mock.called_once + assert not niquests_mock.called_once - requests_mock.get( + niquests_mock.get( "https://as.local/.well-known/openid-configuration", json={"issuer": issuer, "token_endpoint": token_endpoint} ) with pytest.raises( @@ -1574,23 +1573,23 @@ def test_custom_ports_in_endpoints(requests_mock: RequestsMocker) -> None: match=rf"Mismatching `issuer` value in discovery document \(received '{issuer}', expected 'https://as.local'\)", ): OAuth2Client.from_discovery_endpoint(issuer="https://as.local", client_id="client_id") - assert requests_mock.called_once + assert niquests_mock.called_once discovery_url = "https://as.local:8443/.well-known/openid-configuration" - requests_mock.get(discovery_url, json={"issuer": issuer, "token_endpoint": token_endpoint}) + niquests_mock.get(discovery_url, json={"issuer": issuer, "token_endpoint": token_endpoint}) - requests_mock.reset() + niquests_mock.reset() assert ( OAuth2Client.from_discovery_endpoint( url="https://as.local:8443/.well-known/openid-configuration", client_id="client_id" ).token_endpoint == token_endpoint ) - assert requests_mock.called_once + assert niquests_mock.called_once - requests_mock.reset() + niquests_mock.reset() assert ( OAuth2Client.from_discovery_endpoint(issuer="https://as.local:8443", client_id="client_id").token_endpoint == token_endpoint ) - assert requests_mock.called_once + assert niquests_mock.called_once diff --git a/tests/unit_tests/test_client_authentication.py b/tests/unit_tests/test_client_authentication.py index 26e38cb..ed839c9 100644 --- a/tests/unit_tests/test_client_authentication.py +++ b/tests/unit_tests/test_client_authentication.py @@ -3,7 +3,7 @@ from jwskate import InvalidJwk, Jwk from requests_mock import ANY -from requests_oauth2client import ( +from niquests_oauth2client import ( ClientSecretBasic, ClientSecretJwt, ClientSecretPost, @@ -13,11 +13,11 @@ PrivateKeyJwt, UnsupportedClientCredentials, ) -from tests.conftest import RequestsMocker, RequestValidatorType +from tests.conftest import NiquestsMocker, RequestValidatorType def test_client_secret_post( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, access_token: str, token_endpoint: str, client_id: str, @@ -26,18 +26,18 @@ def test_client_secret_post( ) -> None: client = OAuth2Client(token_endpoint, ClientSecretPost(client_id, client_secret)) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) assert client.client_credentials() - assert requests_mock.called_once - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + assert niquests_mock.called_once + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) def test_client_secret_basic( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, access_token: str, token_endpoint: str, client_id: str, @@ -46,18 +46,18 @@ def test_client_secret_basic( ) -> None: client = OAuth2Client(token_endpoint, ClientSecretBasic(client_id, client_secret)) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) assert client.client_credentials() - assert requests_mock.called_once - client_secret_basic_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + assert niquests_mock.called_once + client_secret_basic_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) def test_private_key_jwt( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, access_token: str, token_endpoint: str, client_id: str, @@ -67,15 +67,15 @@ def test_private_key_jwt( ) -> None: client = OAuth2Client(token_endpoint, PrivateKeyJwt(client_id, private_jwk=private_jwk)) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) assert client.client_credentials() - assert requests_mock.called_once + assert niquests_mock.called_once private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, public_jwk=public_jwk, endpoint=token_endpoint, @@ -87,7 +87,7 @@ def test_private_key_jwt( def test_private_key_jwt_with_kid( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, access_token: str, token_endpoint: str, client_id: str, @@ -97,15 +97,15 @@ def test_private_key_jwt_with_kid( ) -> None: client = OAuth2Client(token_endpoint, PrivateKeyJwt(client_id, private_jwk=private_jwk)) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) assert client.client_credentials() - assert requests_mock.called_once + assert niquests_mock.called_once private_key_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, public_jwk=public_jwk, endpoint=token_endpoint, @@ -113,7 +113,7 @@ def test_private_key_jwt_with_kid( def test_client_secret_jwt( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, access_token: str, token_endpoint: str, client_id: str, @@ -122,15 +122,15 @@ def test_client_secret_jwt( ) -> None: client = OAuth2Client(token_endpoint, ClientSecretJwt(client_id, client_secret)) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) assert client.client_credentials() - assert requests_mock.called_once + assert niquests_mock.called_once client_secret_jwt_auth_validator( - requests_mock.last_request, + niquests_mock.last_request, client_id=client_id, client_secret=client_secret, endpoint=token_endpoint, @@ -138,7 +138,7 @@ def test_client_secret_jwt( def test_public_client( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, access_token: str, token_endpoint: str, client_id: str, @@ -147,18 +147,18 @@ def test_public_client( ) -> None: client = OAuth2Client(token_endpoint, client_id) - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) assert client.client_credentials() - assert requests_mock.called_once - public_app_auth_validator(requests_mock.last_request, client_id=client_id) + assert niquests_mock.called_once + public_app_auth_validator(niquests_mock.last_request, client_id=client_id) -def test_invalid_request(requests_mock: RequestsMocker, client_id: str, client_secret: str) -> None: - requests_mock.get(ANY) +def test_invalid_request(niquests_mock: NiquestsMocker, client_id: str, client_secret: str) -> None: + niquests_mock.get(ANY) with pytest.raises(RuntimeError) as exc: requests.get("http://localhost", auth=ClientSecretBasic(client_id, client_secret)) assert exc.type is InvalidRequestForClientAuthentication diff --git a/tests/unit_tests/test_device_authorization.py b/tests/unit_tests/test_device_authorization.py index 2fc8687..2dc5dca 100644 --- a/tests/unit_tests/test_device_authorization.py +++ b/tests/unit_tests/test_device_authorization.py @@ -6,7 +6,7 @@ from freezegun.api import FrozenDateTimeFactory from pytest_mock import MockerFixture -from requests_oauth2client import ( +from niquests_oauth2client import ( BearerToken, ClientSecretPost, DeviceAuthorizationError, @@ -16,7 +16,7 @@ OAuth2Client, UnauthorizedClient, ) -from tests.conftest import RequestsMocker, RequestValidatorType +from tests.conftest import NiquestsMocker, RequestValidatorType def test_device_authorization_response( @@ -114,7 +114,7 @@ def device_authorization_client( def test_device_authorization_client( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, device_authorization_client: OAuth2Client, device_authorization_endpoint: str, device_code: str, @@ -125,7 +125,7 @@ def test_device_authorization_client( client_id: str, client_secret: str, ) -> None: - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, json={ "device_code": device_code, @@ -138,19 +138,19 @@ def test_device_authorization_client( ) device_authorization_client.authorize_device() - assert requests_mock.called_once - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + assert niquests_mock.called_once + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) def test_device_authorization_client_error( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, device_authorization_client: OAuth2Client, device_authorization_endpoint: str, client_secret_post_auth_validator: RequestValidatorType, client_id: str, client_secret: str, ) -> None: - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, status_code=400, json={ @@ -160,19 +160,19 @@ def test_device_authorization_client_error( with pytest.raises(UnauthorizedClient): device_authorization_client.authorize_device() - assert requests_mock.called_once - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + assert niquests_mock.called_once + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) def test_device_authorization_invalid_errors( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, device_authorization_client: OAuth2Client, device_authorization_endpoint: str, client_secret_post_auth_validator: RequestValidatorType, client_id: str, client_secret: str, ) -> None: - requests_mock.post( + niquests_mock.post( device_authorization_endpoint, status_code=400, json={ @@ -182,11 +182,11 @@ def test_device_authorization_invalid_errors( with pytest.raises(DeviceAuthorizationError): device_authorization_client.authorize_device() - assert requests_mock.called_once - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + assert niquests_mock.called_once + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) - requests_mock.reset_mock() - requests_mock.post( + niquests_mock.reset_mock() + niquests_mock.post( device_authorization_endpoint, status_code=400, json={ @@ -196,13 +196,13 @@ def test_device_authorization_invalid_errors( with pytest.raises(InvalidDeviceAuthorizationResponse): device_authorization_client.authorize_device() - assert requests_mock.called_once - client_secret_post_auth_validator(requests_mock.last_request, client_id=client_id, client_secret=client_secret) + assert niquests_mock.called_once + client_secret_post_auth_validator(niquests_mock.last_request, client_id=client_id, client_secret=client_secret) @freeze_time() def test_device_authorization_pooling_job( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, client_id: str, client_secret: str, @@ -229,32 +229,32 @@ def test_device_authorization_pooling_job( ), ) - requests_mock.post(token_endpoint, status_code=401, json={"error": "authorization_pending"}) + niquests_mock.post(token_endpoint, status_code=401, json={"error": "authorization_pending"}) mocker.patch("time.sleep") assert job() is None time.sleep.assert_called_once_with(interval) # type: ignore[attr-defined] - assert requests_mock.called_once + assert niquests_mock.called_once assert job.interval == interval - device_code_grant_validator(requests_mock.last_request, device_code=device_code) + device_code_grant_validator(niquests_mock.last_request, device_code=device_code) - requests_mock.reset_mock() - requests_mock.post(token_endpoint, status_code=401, json={"error": "slow_down"}) + niquests_mock.reset_mock() + niquests_mock.post(token_endpoint, status_code=401, json={"error": "slow_down"}) time.sleep.reset_mock() # type: ignore[attr-defined] assert job() is None time.sleep.assert_called_once_with(interval) # type: ignore[attr-defined] - assert requests_mock.called_once + assert niquests_mock.called_once assert job.interval == interval + job.slow_down_interval - device_code_grant_validator(requests_mock.last_request, device_code=device_code) + device_code_grant_validator(niquests_mock.last_request, device_code=device_code) - requests_mock.reset_mock() - requests_mock.post(token_endpoint, json={"access_token": access_token}) + niquests_mock.reset_mock() + niquests_mock.post(token_endpoint, json={"access_token": access_token}) time.sleep.reset_mock() # type: ignore[attr-defined] token = job() time.sleep.assert_called_once_with(interval + job.slow_down_interval) # type: ignore[attr-defined] - assert requests_mock.called_once + assert niquests_mock.called_once assert isinstance(token, BearerToken) assert token.access_token == access_token diff --git a/tests/unit_tests/test_discovery.py b/tests/unit_tests/test_discovery.py index d057715..de7818c 100644 --- a/tests/unit_tests/test_discovery.py +++ b/tests/unit_tests/test_discovery.py @@ -1,4 +1,4 @@ -from requests_oauth2client import ( +from niquests_oauth2client import ( oauth2_discovery_document_url, oidc_discovery_document_url, well_known_uri, diff --git a/tests/unit_tests/test_dpop.py b/tests/unit_tests/test_dpop.py index be99543..901e3a1 100644 --- a/tests/unit_tests/test_dpop.py +++ b/tests/unit_tests/test_dpop.py @@ -1,12 +1,12 @@ import secrets +import niquests import pytest -import requests from binapy import BinaPy from freezegun import freeze_time from jwskate import Jwk, Jwt, KeyManagementAlgs, SignatureAlgs, SignedJwt -from requests_oauth2client import ( +from niquests_oauth2client import ( DPoPKey, DPoPToken, InvalidDPoPAccessToken, @@ -21,7 +21,7 @@ RequestUriParameterAuthorizationRequest, validate_dpop_proof, ) -from tests.conftest import RequestsMocker +from tests.conftest import NiquestsMocker @pytest.mark.parametrize("alg", SignatureAlgs.ALL_ASYMMETRIC) @@ -44,14 +44,14 @@ def test_dpop_key(alg: str) -> None: @freeze_time() -def test_dpop_client_credentials_request(requests_mock: RequestsMocker) -> None: +def test_dpop_client_credentials_request(niquests_mock: NiquestsMocker) -> None: token_endpoint = "https://url.to.the/token_endpoint" client = OAuth2Client( token_endpoint=token_endpoint, client_id="foo", client_secret="bar", dpop_bound_access_tokens=True ) access_token = "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU" - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": access_token, @@ -67,8 +67,8 @@ def test_dpop_client_credentials_request(requests_mock: RequestsMocker) -> None: dpop_key = dpop_token.dpop_key assert isinstance(dpop_key, DPoPKey) - assert requests_mock.called_once - token_request = requests_mock.last_request + assert niquests_mock.called_once + token_request = niquests_mock.last_request assert token_request is not None dpop = Jwt(token_request.headers["DPoP"]) assert isinstance(dpop, SignedJwt) @@ -86,17 +86,17 @@ def test_dpop_client_credentials_request(requests_mock: RequestsMocker) -> None: @freeze_time() @pytest.mark.parametrize("alg", SignatureAlgs.ALL_ASYMMETRIC) -def test_dpop_token_api_request(requests_mock: RequestsMocker, alg: str) -> None: +def test_dpop_token_api_request(niquests_mock: NiquestsMocker, alg: str) -> None: private_key = Jwk.generate(alg=alg) dpop_key = DPoPKey(private_key=private_key) access_token = secrets.token_urlsafe(64) dpop_token = DPoPToken(access_token=access_token, _dpop_key=dpop_key) target_api = "https://my.api/resource" - requests_mock.put(target_api) - requests.put(target_api, params={"key": "value"}, auth=dpop_token) - assert requests_mock.called_once - api_request = requests_mock.last_request + niquests_mock.put(target_api) + niquests.put(target_api, params={"key": "value"}, auth=dpop_token) + assert niquests_mock.called_once + api_request = niquests_mock.last_request assert api_request is not None assert api_request.headers["Authorization"] == f"DPoP {access_token}" dpop = Jwt(api_request.headers["DPoP"]) @@ -115,7 +115,7 @@ def test_dpop_token_api_request(requests_mock: RequestsMocker, alg: str) -> None @freeze_time() -def test_dpop_access_token_request_with_choosen_key(requests_mock: RequestsMocker) -> None: +def test_dpop_access_token_request_with_choosen_key(niquests_mock: NiquestsMocker) -> None: dpop_alg = "ES512" dpop_key = DPoPKey.generate(alg=dpop_alg) token_endpoint = "https://url.to.the/token_endpoint" @@ -123,7 +123,7 @@ def test_dpop_access_token_request_with_choosen_key(requests_mock: RequestsMocke token_endpoint=token_endpoint, client_id="foo", client_secret="bar", dpop_bound_access_tokens=True ) - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "access_token": "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU", @@ -138,8 +138,8 @@ def test_dpop_access_token_request_with_choosen_key(requests_mock: RequestsMocke assert dpop_token.token_type == "DPoP" assert dpop_token.dpop_key == dpop_key - assert requests_mock.called_once - token_request = requests_mock.last_request + assert niquests_mock.called_once + token_request = niquests_mock.last_request assert token_request is not None dpop = Jwt(token_request.headers["DPoP"]) assert isinstance(dpop, SignedJwt) @@ -151,8 +151,8 @@ def test_dpop_access_token_request_with_choosen_key(requests_mock: RequestsMocke # make sure that passing a dpop_key is enough to toggle DPoP, even if dpop=False assert isinstance(client.client_credentials(dpop=False, dpop_key=dpop_key), DPoPToken) - assert requests_mock.last_request is not None - assert "DPoP" in requests_mock.last_request.headers + assert niquests_mock.last_request is not None + assert "DPoP" in niquests_mock.last_request.headers def test_dpop_proof() -> None: @@ -198,7 +198,7 @@ def test_dpop_errors() -> None: @freeze_time() def test_dpop_authorization_code_flow( - requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str ) -> None: azreq = oauth2client.authorization_request(dpop=True) assert isinstance(azreq.dpop_key, DPoPKey) @@ -213,7 +213,7 @@ def test_dpop_authorization_code_flow( azresp = azreq.validate_callback(callback_uri) assert azresp.dpop_key == azreq.dpop_key - requests_mock.post( + niquests_mock.post( token_endpoint, json={ "token_type": "DPoP", @@ -226,10 +226,10 @@ def test_dpop_authorization_code_flow( assert isinstance(token, DPoPToken) assert token.dpop_key == azreq.dpop_key - assert requests_mock.last_request is not None - assert "DPoP" in requests_mock.last_request.headers + assert niquests_mock.last_request is not None + assert "DPoP" in niquests_mock.last_request.headers dpop_proof = validate_dpop_proof( - requests_mock.last_request.headers["DPoP"], alg=oauth2client.dpop_alg, htm="POST", htu=token_endpoint + niquests_mock.last_request.headers["DPoP"], alg=oauth2client.dpop_alg, htm="POST", htu=token_endpoint ) assert isinstance(dpop_proof, SignedJwt) assert dpop_proof.iat == Jwt.timestamp() @@ -237,7 +237,7 @@ def test_dpop_authorization_code_flow( refreshed_token = oauth2client.refresh_token(token) assert isinstance(refreshed_token, DPoPToken) assert refreshed_token.dpop_key == azreq.dpop_key - dpop_proof2 = validate_dpop_proof(requests_mock.last_request.headers["DPoP"], htm="POST", htu=token_endpoint) + dpop_proof2 = validate_dpop_proof(niquests_mock.last_request.headers["DPoP"], htm="POST", htu=token_endpoint) assert isinstance(dpop_proof2, SignedJwt) assert dpop_proof2.iat == Jwt.timestamp() assert dpop_proof.jwt_token_id != dpop_proof2.jwt_token_id @@ -245,7 +245,7 @@ def test_dpop_authorization_code_flow( @freeze_time() def test_dpop_pushed_authorization_code_flow( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str, pushed_authorization_request_endpoint: str, @@ -259,7 +259,7 @@ def test_dpop_pushed_authorization_code_flow( request_uri = "https://my.request.uri" expires_in = 30 - requests_mock.post( + niquests_mock.post( pushed_authorization_request_endpoint, [ {"status_code": 401, "headers": {"DPoP-Nonce": dpop_nonce}, "json": {"error": "use_dpop_nonce"}}, @@ -270,8 +270,8 @@ def test_dpop_pushed_authorization_code_flow( par_resp = oauth2client.pushed_authorization_request(azreq) assert isinstance(par_resp, RequestUriParameterAuthorizationRequest) - assert requests_mock.call_count == 2 - first_request, second_request = requests_mock.request_history + assert niquests_mock.call_count == 2 + first_request, second_request = niquests_mock.request_history assert first_request.url == pushed_authorization_request_endpoint assert second_request.url == pushed_authorization_request_endpoint assert "DPoP" in first_request.headers @@ -436,9 +436,9 @@ def test_validate_dpop_proof() -> None: ) -def test_dpop_as_provided_nonce(requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: +def test_dpop_as_provided_nonce(niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: dpop_nonce = "my_dpop_nonce" - requests_mock.post( + niquests_mock.post( token_endpoint, [ { @@ -455,9 +455,9 @@ def test_dpop_as_provided_nonce(requests_mock: RequestsMocker, oauth2client: OAu token = oauth2client.client_credentials(scope="my_scope", dpop=True) assert isinstance(token, DPoPToken) - assert requests_mock.call_count == 2 - request_without_nonce = requests_mock.request_history[0] - request_with_nonce = requests_mock.request_history[1] + assert niquests_mock.call_count == 2 + request_without_nonce = niquests_mock.request_history[0] + request_with_nonce = niquests_mock.request_history[1] assert "DPoP" in request_without_nonce.headers assert "DPop-Nonce" not in request_without_nonce.headers @@ -470,14 +470,14 @@ def test_dpop_as_provided_nonce(requests_mock: RequestsMocker, oauth2client: OAu def test_dpop_with_rs_provided_nonce( - requests_mock: RequestsMocker, oauth2client: OAuth2Client, target_api: str, token_endpoint: str + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, target_api: str, token_endpoint: str ) -> None: dpop_nonce = "my_dpop_nonce" - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": "my_access_token", "token_type": "DPoP", "expires_in": 3600} ) - requests_mock.post( + niquests_mock.post( target_api, [ { @@ -492,16 +492,16 @@ def test_dpop_with_rs_provided_nonce( ], ) - session = requests.Session() + session = niquests.Session() session.auth = OAuth2ClientCredentialsAuth(oauth2client, dpop=True) response = session.post(target_api) assert response.status_code == 200 - assert requests_mock.call_count == 3 + assert niquests_mock.call_count == 3 - token_req = requests_mock.request_history[0] - api_req_without_nonce = requests_mock.request_history[1] - api_req_with_nonce = requests_mock.request_history[2] + token_req = niquests_mock.request_history[0] + api_req_without_nonce = niquests_mock.request_history[1] + api_req_with_nonce = niquests_mock.request_history[2] assert token_req.url == token_endpoint assert api_req_without_nonce.url == api_req_with_nonce.url == target_api @@ -511,19 +511,19 @@ def test_dpop_with_rs_provided_nonce( proof_with_nonce = SignedJwt(api_req_with_nonce.headers["DPoP"]) assert proof_with_nonce.claims["nonce"] == dpop_nonce - requests_mock.reset_mock() + niquests_mock.reset_mock() second_response = session.post(target_api) assert second_response.status_code == 200 - assert requests_mock.called_once - assert requests_mock.last_request is not None - assert requests_mock.last_request.url == target_api - second_proof_with_nonce = SignedJwt(requests_mock.last_request.headers["DPoP"]) + assert niquests_mock.called_once + assert niquests_mock.last_request is not None + assert niquests_mock.last_request.url == target_api + second_proof_with_nonce = SignedJwt(niquests_mock.last_request.headers["DPoP"]) assert second_proof_with_nonce.claims["nonce"] == dpop_nonce -def test_as_missing_dpop_nonce(requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: +def test_as_missing_dpop_nonce(niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: """Raise an exception if the RS requires a nonce but forgets to include its value in the response.""" - requests_mock.post( + niquests_mock.post( token_endpoint, [ { @@ -541,10 +541,10 @@ def test_as_missing_dpop_nonce(requests_mock: RequestsMocker, oauth2client: OAut oauth2client.client_credentials(scope="my_scope", dpop=True) -def test_as_repeated_dpop_nonce(requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: +def test_as_repeated_dpop_nonce(niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: """Protect against infinite looping if the AS requires the same nonce that is already included in the proof.""" dpop_nonce = "my_dpop_nonce" - requests_mock.post( + niquests_mock.post( token_endpoint, [ { @@ -571,11 +571,11 @@ def test_as_repeated_dpop_nonce(requests_mock: RequestsMocker, oauth2client: OAu def test_as_dpop_nonce_in_response_to_non_dpop_request( - requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str + niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str ) -> None: """Raise an exception if the AS requires a DPoP nonce as reply to a non-DPoP token request.""" dpop_nonce = "my_dpop_nonce" - requests_mock.post( + niquests_mock.post( token_endpoint, [ { @@ -594,9 +594,9 @@ def test_as_dpop_nonce_in_response_to_non_dpop_request( oauth2client.client_credentials(scope="my_scope", dpop=False) -def test_as_dpop_nonce_loop(requests_mock: RequestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: +def test_as_dpop_nonce_loop(niquests_mock: NiquestsMocker, oauth2client: OAuth2Client, token_endpoint: str) -> None: """Protect against infinite looping if the AS keeps requesting new nonces on every request.""" - requests_mock.post( + niquests_mock.post( token_endpoint, [ { @@ -630,9 +630,9 @@ def test_as_dpop_nonce_loop(requests_mock: RequestsMocker, oauth2client: OAuth2C oauth2client.client_credentials(scope="my_scope", dpop=True) -def test_rs_missing_nonce(requests_mock: RequestsMocker, target_api: str) -> None: +def test_rs_missing_nonce(niquests_mock: NiquestsMocker, target_api: str) -> None: """Raise an exception if the RS requires a nonce but forgets to include its value in the response.""" - requests_mock.get( + niquests_mock.get( target_api, status_code=401, headers={ @@ -644,13 +644,13 @@ def test_rs_missing_nonce(requests_mock: RequestsMocker, target_api: str) -> Non dpop_token = DPoPToken(access_token="my_dpop_access_token", _dpop_key=dpop_key) with pytest.raises(MissingDPoPNonce): - requests.get(target_api, auth=dpop_token) + niquests.get(target_api, auth=dpop_token) -def test_rs_repeated_nonce(requests_mock: RequestsMocker, target_api: str) -> None: +def test_rs_repeated_nonce(niquests_mock: NiquestsMocker, target_api: str) -> None: """Protect against infinite looping if the RS requires the same nonce that is already included in the proof.""" dpop_nonce = "my_dpop_nonce" - requests_mock.get( + niquests_mock.get( target_api, status_code=401, headers={ @@ -663,14 +663,14 @@ def test_rs_repeated_nonce(requests_mock: RequestsMocker, target_api: str) -> No dpop_token = DPoPToken(access_token="my_dpop_access_token", _dpop_key=dpop_key) with pytest.raises(RepeatedDPoPNonce): - requests.get(target_api, auth=dpop_token) + niquests.get(target_api, auth=dpop_token) def test_rs_dpop_nonce_loop( - requests_mock: RequestsMocker, target_api: str, oauth2client: OAuth2Client, token_endpoint: str + niquests_mock: NiquestsMocker, target_api: str, oauth2client: OAuth2Client, token_endpoint: str ) -> None: """Protection against infinite looping if the RS keeps requesting new nonces on every request.""" - requests_mock.get( + niquests_mock.get( target_api, [ { @@ -700,6 +700,6 @@ def test_rs_dpop_nonce_loop( dpop_key = DPoPKey.generate() dpop_token = DPoPToken(access_token="my_dpop_access_token", _dpop_key=dpop_key) - resp = requests.get(target_api, auth=dpop_token) + resp = niquests.get(target_api, auth=dpop_token) assert resp.status_code == 401 assert resp.headers["DPoP-Nonce"] == "nonce2" diff --git a/tests/unit_tests/test_flask.py b/tests/unit_tests/test_flask.py index 471ece8..52b60c0 100644 --- a/tests/unit_tests/test_flask.py +++ b/tests/unit_tests/test_flask.py @@ -1,17 +1,18 @@ -from typing import Any, Iterable +from collections.abc import Iterable +from typing import Any from urllib.parse import parse_qs import pytest from flask import request -from requests_oauth2client import ApiClient, ClientSecretPost, OAuth2Client -from tests.conftest import RequestsMocker +from niquests_oauth2client import ApiClient, ClientSecretPost, OAuth2Client +from tests.conftest import NiquestsMocker session_key = "session_key" def test_flask( - requests_mock: RequestsMocker, + niquests_mock: NiquestsMocker, token_endpoint: str, client_id: str, client_secret: str, @@ -21,7 +22,7 @@ def test_flask( try: from flask import Flask - from requests_oauth2client.flask import FlaskOAuth2ClientCredentialsAuth + from niquests_oauth2client.flask import FlaskOAuth2ClientCredentialsAuth except ImportError: pytest.skip("Flask is not available") @@ -45,11 +46,11 @@ def get() -> Any: access_token = "access_token" json_resp = {"status": "success"} - requests_mock.post( + niquests_mock.post( token_endpoint, json={"access_token": access_token, "token_type": "Bearer", "expires_in": 3600}, ) - requests_mock.get(target_api, json=json_resp) + niquests_mock.get(target_api, json=json_resp) with app.test_client() as client: resp = client.get("/api?call=1") @@ -64,7 +65,7 @@ def get() -> Any: resp = client.get("/api?call=3") assert resp.json == json_resp - token_request1 = requests_mock.request_history[0] + token_request1 = niquests_mock.request_history[0] assert token_request1.url == token_endpoint token_params = parse_qs(token_request1.text) assert token_params.get("client_id") == [client_id] @@ -76,15 +77,15 @@ def get() -> Any: assert token_params.get("scope") == [" ".join(scope)] assert token_params.get("client_secret") == [client_secret] - api_request1 = requests_mock.request_history[1] + api_request1 = niquests_mock.request_history[1] assert api_request1.url == "https://myapi.local/root/?call=1" assert api_request1.headers.get("Authorization") == f"Bearer {access_token}" - api_request2 = requests_mock.request_history[2] + api_request2 = niquests_mock.request_history[2] assert api_request2.url == "https://myapi.local/root/?call=2" assert api_request2.headers.get("Authorization") == f"Bearer {access_token}" - token_request2 = requests_mock.request_history[3] + token_request2 = niquests_mock.request_history[3] assert token_request2.url == token_endpoint token_params = parse_qs(token_request2.text) assert token_params.get("client_id") == [client_id] @@ -96,6 +97,6 @@ def get() -> Any: assert token_params.get("scope") == [" ".join(scope)] assert token_params.get("client_secret") == [client_secret] - api_request3 = requests_mock.request_history[4] + api_request3 = niquests_mock.request_history[4] assert api_request3.url == "https://myapi.local/root/?call=3" assert api_request3.headers.get("Authorization") == f"Bearer {access_token}" diff --git a/tests/unit_tests/test_oidc.py b/tests/unit_tests/test_oidc.py index 50d3d38..a4ab89c 100644 --- a/tests/unit_tests/test_oidc.py +++ b/tests/unit_tests/test_oidc.py @@ -5,7 +5,7 @@ from freezegun import freeze_time from jwskate import EncryptionAlgs, InvalidSignature, Jwk, Jwt, KeyManagementAlgs, SignatureAlgs -from requests_oauth2client import ( +from niquests_oauth2client import ( AuthorizationResponse, BearerToken, ExpiredIdToken, @@ -20,7 +20,7 @@ MissingIdToken, OAuth2Client, ) -from requests_oauth2client.tokens import UnsupportedIdTokenAlg +from niquests_oauth2client.tokens import UnsupportedIdTokenAlg @freeze_time("2011-07-21 20:42:55") diff --git a/tests/unit_tests/test_pkce.py b/tests/unit_tests/test_pkce.py index d805865..e9b6649 100644 --- a/tests/unit_tests/test_pkce.py +++ b/tests/unit_tests/test_pkce.py @@ -4,7 +4,7 @@ import pytest -from requests_oauth2client import PkceUtils +from niquests_oauth2client import PkceUtils def test_generate_code_verifier_and_challenge() -> None: diff --git a/tests/unit_tests/test_tokens.py b/tests/unit_tests/test_tokens.py index 8c04e35..f813321 100644 --- a/tests/unit_tests/test_tokens.py +++ b/tests/unit_tests/test_tokens.py @@ -15,7 +15,7 @@ SignedJwt, ) -from requests_oauth2client import BearerToken, BearerTokenSerializer, IdToken +from niquests_oauth2client import BearerToken, BearerTokenSerializer, IdToken ID_TOKEN = ( "eyJhbGciOiJSUzI1NiIsImtpZCI6Im15X2tleSJ9.eyJhY3IiOiIyIiwiYW1yIjpbInB3ZCIsIm90cCJdLCJhdWQiOiJjbGllbnRfaWQiL" diff --git a/tests/unit_tests/test_utils.py b/tests/unit_tests/test_utils.py index 7cc2e01..8cb3f55 100644 --- a/tests/unit_tests/test_utils.py +++ b/tests/unit_tests/test_utils.py @@ -4,8 +4,8 @@ import pytest -from requests_oauth2client import InvalidUri, validate_endpoint_uri -from requests_oauth2client.utils import accepts_expires_in +from niquests_oauth2client import InvalidUri, validate_endpoint_uri +from niquests_oauth2client.utils import accepts_expires_in def test_validate_uri() -> None: diff --git a/tests/unit_tests/vendor_specific/test_auth0.py b/tests/unit_tests/vendor_specific/test_auth0.py index f84a1a1..966b0ba 100644 --- a/tests/unit_tests/vendor_specific/test_auth0.py +++ b/tests/unit_tests/vendor_specific/test_auth0.py @@ -1,7 +1,7 @@ import pytest -from requests_oauth2client import OAuth2ClientCredentialsAuth -from requests_oauth2client.vendor_specific import Auth0 +from niquests_oauth2client import OAuth2ClientCredentialsAuth +from niquests_oauth2client.vendor_specific import Auth0 def test_auth0_management() -> None: diff --git a/tests/unit_tests/vendor_specific/test_ping.py b/tests/unit_tests/vendor_specific/test_ping.py index 38f6429..5c53aca 100644 --- a/tests/unit_tests/vendor_specific/test_ping.py +++ b/tests/unit_tests/vendor_specific/test_ping.py @@ -1,6 +1,6 @@ import pytest -from requests_oauth2client.vendor_specific import Ping +from niquests_oauth2client.vendor_specific import Ping def test_ping_client() -> None: diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 0d30f6d..0000000 --- a/tox.ini +++ /dev/null @@ -1,45 +0,0 @@ -[tox] -isolated_build = true -envlist = py37, py38, py39, py310, py311, lint - -[gh-actions] -python = - 3.11: py311 - 3.10: py310 - 3.9: py39 - 3.8: py38 - 3.7: py37 - -[testenv:lint] -whitelist_externals = - isort - black - flake8 - poetry - mkdocs - twine -extras = - test - doc - dev -commands = - mdformat --wrap 120 README.md - isort requests_oauth2client - black requests_oauth2client tests - flake8 requests_oauth2client tests - mypy requests_oauth2client - poetry build - mkdocs build - twine check dist/* - -[testenv] -allowlist_externals = - poetry -commands_pre = - poetry install --no-root --sync -E test -passenv = * -setenv = - PYTHONPATH = {toxinidir} - PYTHONWARNINGS = ignore -commands = - poetry run pytest -s --cov=requests_oauth2client --cov-append --cov-report=xml --cov-report term-missing tests