Skip to content

Commit

Permalink
Add support for params parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
jocke-l committed Oct 5, 2020
1 parent f368452 commit dfc9027
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 3 deletions.
24 changes: 23 additions & 1 deletion respx/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from typing import Callable, Optional, Pattern, Union, overload

from .mocks import MockTransport
from .models import ContentDataTypes, DefaultType, HeaderTypes, RequestPattern
from .models import (
ContentDataTypes,
DefaultType,
HeaderTypes,
QueryParamTypes,
RequestPattern,
)

mock = MockTransport(assert_all_called=False)

Expand Down Expand Up @@ -49,6 +55,7 @@ def add(
method: Union[str, Callable],
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -60,6 +67,7 @@ def add(
return mock.add(
method,
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -72,6 +80,7 @@ def add(
def get(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -82,6 +91,7 @@ def get(
global mock
return mock.get(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -94,6 +104,7 @@ def get(
def post(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -104,6 +115,7 @@ def post(
global mock
return mock.post(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -116,6 +128,7 @@ def post(
def put(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -126,6 +139,7 @@ def put(
global mock
return mock.put(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -138,6 +152,7 @@ def put(
def patch(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -148,6 +163,7 @@ def patch(
global mock
return mock.patch(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -160,6 +176,7 @@ def patch(
def delete(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -170,6 +187,7 @@ def delete(
global mock
return mock.delete(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -182,6 +200,7 @@ def delete(
def head(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -192,6 +211,7 @@ def head(
global mock
return mock.head(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -204,6 +224,7 @@ def head(
def options(
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -214,6 +235,7 @@ def options(
global mock
return mock.options(
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand Down
19 changes: 17 additions & 2 deletions respx/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
URLPatternTypes = Union[str, Pattern[str], URL]
JSONTypes = Union[str, List, Dict]
ContentDataTypes = Union[bytes, str, JSONTypes, Callable, Exception]
QueryParamTypes = Union[bytes, str, List[Tuple[str, Any]], Dict[str, Any]]

istype = lambda t, o: isinstance(o, t)
isregex = partial(istype, Regex)
Expand Down Expand Up @@ -262,6 +263,7 @@ def __init__(
self,
method: Union[str, Callable],
url: Optional[URLPatternTypes],
params: Optional[QueryParamTypes] = None,
response: Optional[ResponseTemplate] = None,
pass_through: bool = False,
alias: Optional[str] = None,
Expand All @@ -276,7 +278,7 @@ def __init__(
self._match_func = method
else:
self.method = method.upper()
self.set_url(url, base=base_url)
self.set_url(url, base=base_url, params=params)
self.pass_through = pass_through

self.response = response or ResponseTemplate()
Expand All @@ -301,26 +303,39 @@ def get_url(self) -> Optional[URLPatternTypes]:
return self._url

def set_url(
self, url: Optional[URLPatternTypes], base: Optional[str] = None
self,
url: Optional[URLPatternTypes],
base: Optional[str] = None,
params: Optional[QueryParamTypes] = None,
) -> None:
params = str(httpx.QueryParams(params))
url = url or None
if url is None:
url = base
if base is not None and params:
url = url + f"?{params}"
elif isinstance(url, str):
url = url if base is None else urljoin(base, url)
parsed_url = urlparse(url)
if not parsed_url.path:
url = parsed_url._replace(path="/").geturl()
if url and params:
url = url + f"?{params}"
elif isinstance(url, tuple):
url = self.build_url(url)
if url and params:
url = url + f"?{params}"
elif isregex(url):
url = url if base is None else re.compile(urljoin(base, url.pattern))
if params:
url = re.compile(url.pattern + re.escape(f"?{params}"))
else:
raise ValueError(
"Request url pattern must be str or compiled regex, got {}.".format(
type(url).__name__
)
)

self._url = url

url = property(get_url, set_url)
Expand Down
17 changes: 17 additions & 0 deletions respx/transports.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
DefaultType,
Headers,
HeaderTypes,
QueryParamTypes,
Request,
RequestPattern,
Response,
Expand Down Expand Up @@ -91,6 +92,7 @@ def add(
method: Union[str, Callable, RequestPattern],
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -111,6 +113,7 @@ def add(
pattern = RequestPattern(
method,
url,
params=params,
response,
pass_through=pass_through,
alias=alias,
Expand All @@ -127,6 +130,7 @@ def get(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -137,6 +141,7 @@ def get(
return self.add(
"GET",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -149,6 +154,7 @@ def post(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -159,6 +165,7 @@ def post(
return self.add(
"POST",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -171,6 +178,7 @@ def put(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -181,6 +189,7 @@ def put(
return self.add(
"PUT",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -193,6 +202,7 @@ def patch(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -203,6 +213,7 @@ def patch(
return self.add(
"PATCH",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -215,6 +226,7 @@ def delete(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -225,6 +237,7 @@ def delete(
return self.add(
"DELETE",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -237,6 +250,7 @@ def head(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -247,6 +261,7 @@ def head(
return self.add(
"HEAD",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand All @@ -259,6 +274,7 @@ def options(
self,
url: Optional[Union[str, Pattern]] = None,
*,
params: Optional[QueryParamTypes] = None,
status_code: Optional[int] = None,
content: Optional[ContentDataTypes] = None,
content_type: Optional[str] = None,
Expand All @@ -269,6 +285,7 @@ def options(
return self.add(
"OPTIONS",
url=url,
params=params,
status_code=status_code,
content=content,
content_type=content_type,
Expand Down
18 changes: 18 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,3 +446,21 @@ def test_pop():
respx.get("https://foo.bar/", alias="foobar")
request_pattern = respx.pop("foobar")
assert request_pattern.url == "https://foo.bar/"


@respx.mock
@pytest.mark.asyncio
@pytest.mark.parametrize(
"url,params,call_url",
[
("https://foo/", "foo=bar&foo=foo", "https://foo/"),
("https://foo/", b"foo=bar&foo=foo", "https://foo/"),
("https://foo/", [("foo", "bar"), ("foo", "foo")], "https://foo/"),
("https://foo/", {"foo": "bar"}, "https://foo/"),
(re.compile(r"https://foo/(?P<page>\w+)/"), {"foo": "bar"}, "https://foo/baz/"),
],
)
async def test_params(client, url, params, call_url):
respx.get(url, params=params, content="spam spam")
response = await client.get(call_url, params=params)
assert response.text == "spam spam"

0 comments on commit dfc9027

Please sign in to comment.