From ed3d2efe4b156c794b3d6afae368b203af82bbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20S=C3=A1nchez?= Date: Thu, 4 Jan 2024 11:53:38 +0000 Subject: [PATCH] Add strict mypy check, update docs on type checking --- .github/workflows/build.yml | 2 +- docs/index.rst | 1 + docs/testing.rst | 18 +++++++++++++++- docs/typing.rst | 43 +++++++++++++++++++++++++++++++++++++ tiny_api_client/__init__.py | 2 +- 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 docs/typing.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2a9d5aa..4dd139a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: run: flake8 tiny_api_client - name: Run type checker - run: mypy tiny_api_client + run: mypy --strict tiny_api_client - name: Run test suite run: pytest -vvvv diff --git a/docs/index.rst b/docs/index.rst index 59257c7..dc73cf3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,6 +37,7 @@ To learn how to test your own API clients, see the :doc:`testing`. :caption: Contents: quick + typing testing api_reference diff --git a/docs/testing.rst b/docs/testing.rst index f08d22f..0f0df79 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -35,7 +35,7 @@ Usage :: from my_api import MyClient - + def test_my_client(api_call): # set your fake api response api_call.return_value = [{"id": 0, "name": "Mary Jane"}, ...] @@ -46,6 +46,22 @@ Usage assert users[0].name == "Mary Jane" +Using a Context Manager +----------------------- + +In some circumstances it might not be possible to use a function-scoped fixture. +One example of this is when using the property-based testing library ``hypothesis``. +It is still possible to use a context manager to temporarily patch the api call. + +:: + + from unittest.mock import patch + + def test_my_client(): + with patch('pytest_tiny_api_client._api_call') as api_call: + ... + + Not Using Pytest ---------------- diff --git a/docs/typing.rst b/docs/typing.rst new file mode 100644 index 0000000..7b2597b --- /dev/null +++ b/docs/typing.rst @@ -0,0 +1,43 @@ +Type Checking +============= + +You should be able to use *mypy* and other type checkers to verify the +correctness of your code. The library itself is checked with the ``--strict`` +flag. + +For the most part, you should not have issues with type checking except when +passing keyword arguments to your endpoints. Unfortunately you will see the +following error. + +:: + + error: Unexpected keyword argument "arg" for "call" of "Client" + [call-arg] + +This is due to inherent limitations with the typing spec as of Python 3.12, +and the fact that keyword arguments cannot be concatenated for type checking +purposes. For more information, see `pep`_ 612. + +.. _pep: https://peps.python.org/pep-0612/#concatenating-keyword-parameters + +Mitigations +----------- + +One way around this is to include arbitrary keyword-only arguments in your +endpoint definition. This will let mypy know that the wrapper function can +also accept arbitrary keyword-only arguments. The obvious downside is that +it does not look very clean and if you have multiple endpoints it can get +tiring to write them like this. + +:: + + from typing import Any + + @get('/my_endpoint/{item_id}') + def my_call(self, response, /, **_: Any) -> str: + return response + +The other way is to manually silence this error for a certain scope. +For more information, see the `mypy`_ docs. + +.. _mypy: https://mypy.readthedocs.io/en/stable/error_codes.html diff --git a/tiny_api_client/__init__.py b/tiny_api_client/__init__.py index f638cb6..d78996d 100644 --- a/tiny_api_client/__init__.py +++ b/tiny_api_client/__init__.py @@ -248,7 +248,7 @@ def request(route: str, *, version: int = 1, use_api: bool = True, :param int version: Replaces version placeholder in API URL :param bool json: Toggle JSON parsing of response :param bool xml: Toggle XML parsing of response - :param dict g_kwargs: Any keyword arguments passed to requests + :param dict request_kwargs: Any keyword arguments passed to requests """ endpoint = Endpoint(route, version, use_api, json, xml, request_kwargs)