From f84703fb725e865a346d8ea3efa49cc7e5bcb10c Mon Sep 17 00:00:00 2001 From: Axel H Date: Sat, 22 Apr 2023 15:11:15 +0200 Subject: [PATCH 1/3] build(typing): add type hinting linting using MyPy --- setup.cfg | 4 ++++ tox.ini | 6 ++++++ typing-requirements.txt | 3 +++ 3 files changed, 13 insertions(+) create mode 100644 typing-requirements.txt diff --git a/setup.cfg b/setup.cfg index c8c3b12..62ac7f4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,3 +50,7 @@ fixture = [entry_points] pytest11 = requests_mock = requests_mock.contrib._pytest_plugin + +[mypy] +[mypy-fixtures] +ignore_missing_imports = True diff --git a/tox.ini b/tox.ini index 9500c77..8483531 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,7 @@ envlist = pypy pypy3 pep8 + typing [testenv] setenv = @@ -92,3 +93,8 @@ deps = six -egit+https://github.com/kennethreitz/requests.git#egg=requests -r{toxinidir}/test-requirements.txt + +[testenv:typing] +commands = mypy requests_mock +deps = + -r{toxinidir}/typing-requirements.txt diff --git a/typing-requirements.txt b/typing-requirements.txt new file mode 100644 index 0000000..142c5a0 --- /dev/null +++ b/typing-requirements.txt @@ -0,0 +1,3 @@ +mypy +types-requests +types-six From 5aa8038cb5db3ca4fa3eed679acc21926d17c5f0 Mon Sep 17 00:00:00 2001 From: Axel H Date: Sat, 22 Apr 2023 15:17:43 +0200 Subject: [PATCH 2/3] style(typing): expose public TypeAliases for type intended for library users --- .../public-type-aliases-f389506932adfa2c.yaml | 14 +++ requests_mock/__init__.pyi | 36 +++++- requests_mock/adapter.pyi | 47 +++++--- requests_mock/contrib/_pytest_plugin.pyi | 6 + requests_mock/mocker.pyi | 103 +++++++++--------- requests_mock/request.pyi | 5 +- requests_mock/response.pyi | 4 +- 7 files changed, 140 insertions(+), 75 deletions(-) create mode 100644 releasenotes/notes/public-type-aliases-f389506932adfa2c.yaml create mode 100644 requests_mock/contrib/_pytest_plugin.pyi diff --git a/releasenotes/notes/public-type-aliases-f389506932adfa2c.yaml b/releasenotes/notes/public-type-aliases-f389506932adfa2c.yaml new file mode 100644 index 0000000..2af8a49 --- /dev/null +++ b/releasenotes/notes/public-type-aliases-f389506932adfa2c.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Exposes some public type aliases (for type hinting only, they can't be instanciated) + for the types intended to be used by `requests_mock` users. + The following types are now exposed: + - `requests_mock.Context` used in callbacks + - `requests_mock.Request` used in callbacks, which is a `requests.PreparedRequest` proxy. + - `requests_mock.Callback[T]` which is the callbacks type. + +fixes: + - | + Some typing inconsistencies have been fixed. + Especially for `request` object in signatures which is in fact a `requests_mock.Request` object. diff --git a/requests_mock/__init__.pyi b/requests_mock/__init__.pyi index 4947871..9d8dd00 100644 --- a/requests_mock/__init__.pyi +++ b/requests_mock/__init__.pyi @@ -1,7 +1,33 @@ # Stubs for requests_mock -from requests_mock.adapter import ANY as ANY, Adapter as Adapter -from requests_mock.exceptions import MockException as MockException, NoMockAddress as NoMockAddress -from requests_mock.mocker import DELETE as DELETE, GET as GET, HEAD as HEAD, Mocker as Mocker, MockerCore as MockerCore, OPTIONS as OPTIONS, PATCH as PATCH, POST as POST, PUT as PUT, mock as mock -from requests_mock.request import _RequestObjectProxy as _RequestObjectProxy -from requests_mock.response import CookieJar as CookieJar, create_response as create_response +from requests_mock.adapter import ( + ANY as ANY, + Adapter as Adapter, + Callback as Callback, + AdditionalMatcher as AdditionalMatcher, +) +from requests_mock.exceptions import ( + MockException as MockException, + NoMockAddress as NoMockAddress, +) +from requests_mock.mocker import ( + DELETE as DELETE, + GET as GET, + HEAD as HEAD, + Mocker as Mocker, + MockerCore as MockerCore, + OPTIONS as OPTIONS, + PATCH as PATCH, + POST as POST, + PUT as PUT, + mock as mock, +) +from requests_mock.request import ( + Request as Request, + _RequestObjectProxy as _RequestObjectProxy, # For backward compatibility +) +from requests_mock.response import ( + CookieJar as CookieJar, + create_response as create_response, + Context as Context, +) diff --git a/requests_mock/adapter.pyi b/requests_mock/adapter.pyi index 0aa08ce..dbeba49 100644 --- a/requests_mock/adapter.pyi +++ b/requests_mock/adapter.pyi @@ -2,24 +2,29 @@ from http.cookiejar import CookieJar from io import IOBase -from typing import Any, Callable, Dict, List, NewType, Optional, Pattern, Type, Union +from typing import Any, Callable, Dict, List, NewType, Optional, Pattern, Type, TypeVar, Union -from requests import Request, Response +from requests import Response from requests.adapters import BaseAdapter -from requests.packages.urllib3.response import HTTPResponse +from urllib3.response import HTTPResponse -from requests_mock.request import _RequestObjectProxy -from requests_mock.response import _Context +from requests_mock.request import Request +from requests_mock.response import Context AnyMatcher = NewType("AnyMatcher", object) ANY: AnyMatcher = ... +T = TypeVar('T') +Callback = Callable[[Request, Context], T] +Matcher = Callable[[Request], Optional[Response]] +AdditionalMatcher = Callable[[Request], bool] + class _RequestHistoryTracker: - request_history: List[_RequestObjectProxy] = ... + request_history: List[Request] = ... def __init__(self) -> None: ... @property - def last_request(self) -> Optional[_RequestObjectProxy]: ... + def last_request(self) -> Optional[Request]: ... @property def called(self) -> bool: ... @property @@ -30,9 +35,19 @@ class _RequestHistoryTracker: class _RunRealHTTP(Exception): ... class _Matcher(_RequestHistoryTracker): - def __init__(self, method: Any, url: Any, responses: Any, complete_qs: Any, request_headers: Any, additional_matcher: Any, real_http: Any, case_sensitive: Any) -> None: ... + def __init__( + self, + method: Any, + url: Any, + responses: Any, + complete_qs: Any, + request_headers: Any, + additional_matcher: AdditionalMatcher, + real_http: Any, + case_sensitive: Any + ) -> None: ... def __call__(self, request: Request) -> Optional[Response]: ... - + class Adapter(BaseAdapter, _RequestHistoryTracker): def __init__(self, case_sensitive: bool = ...) -> None: ... def register_uri( @@ -47,14 +62,14 @@ class Adapter(BaseAdapter, _RequestHistoryTracker): reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., **kwargs: Any ) -> _Matcher: ... - def add_matcher(self, matcher: Callable[[Request], Optional[Response]]) -> None: ... - def reset(self) -> None: ... \ No newline at end of file + def add_matcher(self, matcher: Matcher) -> None: ... + def reset(self) -> None: ... diff --git a/requests_mock/contrib/_pytest_plugin.pyi b/requests_mock/contrib/_pytest_plugin.pyi new file mode 100644 index 0000000..3ffb573 --- /dev/null +++ b/requests_mock/contrib/_pytest_plugin.pyi @@ -0,0 +1,6 @@ + +from typing import Literal, Optional, Union + + +_case_type = Optional[str] +_case_default = Union[Literal['false'], Literal[False]] diff --git a/requests_mock/mocker.pyi b/requests_mock/mocker.pyi index dc643d3..891e7d6 100644 --- a/requests_mock/mocker.pyi +++ b/requests_mock/mocker.pyi @@ -5,12 +5,11 @@ from http.cookiejar import CookieJar from io import IOBase from typing import Any, Callable, Dict, List, Optional, Pattern, Type, TypeVar, Union -from requests import Request, Response, Session -from requests.packages.urllib3.response import HTTPResponse +from requests import Response, Session +from urllib3.response import HTTPResponse -from requests_mock.adapter import AnyMatcher, _Matcher -from requests_mock.request import _RequestObjectProxy -from requests_mock.response import _Context +from requests_mock.adapter import AnyMatcher, _Matcher, Callback, AdditionalMatcher +from requests_mock.request import Request DELETE: str GET: str @@ -27,9 +26,9 @@ class MockerCore: def stop(self) -> None: ... def add_matcher(self, matcher: Callable[[Request], Optional[Response]]) -> None: ... @property - def request_history(self) -> List[_RequestObjectProxy]: ... + def request_history(self) -> List[Request]: ... @property - def last_request(self) -> Optional[_RequestObjectProxy]: ... + def last_request(self) -> Optional[Request]: ... @property def called(self) -> bool: ... @property @@ -51,13 +50,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -74,13 +73,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -96,13 +95,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -118,13 +117,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -140,13 +139,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -162,13 +161,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -184,13 +183,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -206,13 +205,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... @@ -228,13 +227,13 @@ class MockerCore: reason: str = ..., headers: Dict[str, str] = ..., cookies: Union[CookieJar, Dict[str, str]] = ..., - json: Union[Any, Callable[[_RequestObjectProxy, _Context], Any]] = ..., - text: Union[str, Callable[[_RequestObjectProxy, _Context], str]] = ..., - content: Union[bytes, Callable[[_RequestObjectProxy, _Context], bytes]] = ..., - body: Union[IOBase, Callable[[_RequestObjectProxy, _Context], IOBase]] = ..., + json: Union[Any, Callback[Any]] = ..., + text: Union[str, Callback[str]] = ..., + content: Union[bytes, Callback[bytes]] = ..., + body: Union[IOBase, Callback[IOBase]] = ..., raw: HTTPResponse = ..., exc: Union[Exception, Type[Exception]] = ..., - additional_matcher: Callable[[_RequestObjectProxy], bool] = ..., + additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., **kwargs: Any, ) -> _Matcher: ... diff --git a/requests_mock/request.pyi b/requests_mock/request.pyi index 63de19e..5e2fb30 100644 --- a/requests_mock/request.pyi +++ b/requests_mock/request.pyi @@ -35,4 +35,7 @@ class _RequestObjectProxy: def text(self) -> str: ... def json(self, **kwargs: Any) -> Any: ... @property - def matcher(self) -> Any: ... \ No newline at end of file + def matcher(self) -> Any: ... + + +Request = _RequestObjectProxy diff --git a/requests_mock/response.pyi b/requests_mock/response.pyi index 575b721..e7c8977 100644 --- a/requests_mock/response.pyi +++ b/requests_mock/response.pyi @@ -1,6 +1,6 @@ # Stubs for requests_mock.response -from typing import Any, Dict, Optional +from typing import Any, Dict import six @@ -34,3 +34,5 @@ class _Context: class _MatcherResponse: def __init__(self, **kwargs: Any) -> None: ... def get_response(self, request: Request) -> Response: ... + +Context = _Context From a5ebf1c2edf4d0fdfeaee6b272ecdda070e2b791 Mon Sep 17 00:00:00 2001 From: Axel H Date: Sat, 22 Apr 2023 17:43:45 +0200 Subject: [PATCH 3/3] ci(typing): renamed `flake8.yml` workflow into `lint.yml` and add mypy linting --- .github/workflows/{flake8.yaml => lint.yaml} | 4 ++++ 1 file changed, 4 insertions(+) rename .github/workflows/{flake8.yaml => lint.yaml} (79%) diff --git a/.github/workflows/flake8.yaml b/.github/workflows/lint.yaml similarity index 79% rename from .github/workflows/flake8.yaml rename to .github/workflows/lint.yaml index 947ee35..003a281 100644 --- a/.github/workflows/flake8.yaml +++ b/.github/workflows/lint.yaml @@ -20,6 +20,10 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt pip install flake8 + pip install -r typing-requirements.txt - name: Lint with flake8 run: flake8 requests_mock tests + + - name: Lint type hinting with MyPy + run: mypy requests_mock