Skip to content

Commit a69d07e

Browse files
committed
refactor: rework Entry, Request and Response classes
1 parent 9cfad4c commit a69d07e

40 files changed

+1543
-867
lines changed

Diff for: mocket/__init__.py

+42-11
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,51 @@
1-
from mocket.async_mocket import async_mocketize
2-
from mocket.entry import MocketEntry
3-
from mocket.mocket import Mocket
4-
from mocket.mocketizer import Mocketizer, mocketize
5-
from mocket.ssl.context import MocketSSLContext
6-
7-
# NOTE this is here for backwards-compat to keep old import-paths working
8-
from mocket.ssl.context import MocketSSLContext as FakeSSLContext
1+
from mocket.bytes import (
2+
MocketBytesEntry,
3+
MocketBytesRequest,
4+
MocketBytesResponse,
5+
)
6+
from mocket.compat import FakeSSLContext, MocketEntry
7+
from mocket.core.async_mocket import async_mocketize
8+
from mocket.core.exceptions import MocketException, StrictMocketException
9+
from mocket.core.mocket import Mocket
10+
from mocket.core.mocketizer import Mocketizer, mocketize
11+
from mocket.core.socket import MocketSocket
12+
from mocket.core.ssl.context import MocketSSLContext
13+
from mocket.core.ssl.socket import MocketSSLSocket
14+
from mocket.http import (
15+
MocketHttpEntry,
16+
MocketHttpMethod,
17+
MocketHttpRequest,
18+
MocketHttpResponse,
19+
)
20+
from mocket.redis import (
21+
MocketRedisEntry,
22+
MocketRedisRequest,
23+
MocketRedisResponse,
24+
)
925

10-
__all__ = (
26+
__all__ = [
1127
"async_mocketize",
1228
"mocketize",
1329
"Mocket",
14-
"MocketEntry",
1530
"Mocketizer",
31+
"MocketBytesEntry",
32+
"MocketBytesRequest",
33+
"MocketBytesResponse",
34+
"MocketHttpEntry",
35+
"MocketHttpMethod",
36+
"MocketHttpRequest",
37+
"MocketHttpResponse",
38+
"MocketRedisEntry",
39+
"MocketRedisRequest",
40+
"MocketRedisResponse",
41+
"MocketSocket",
42+
"MocketSSLSocket",
1643
"MocketSSLContext",
44+
"MocketException",
45+
"StrictMocketException",
46+
# NOTE this is here for backwards-compat to keep old import-paths working
1747
"FakeSSLContext",
18-
)
48+
"MocketEntry",
49+
]
1950

2051
__version__ = "3.13.2"

Diff for: mocket/async_mocket.py

+5-21
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,6 @@
1-
from mocket.mocketizer import Mocketizer
2-
from mocket.utils import get_mocketize
1+
from mocket.core.async_mocket import async_mocketize
32

4-
5-
async def wrapper(
6-
test,
7-
truesocket_recording_dir=None,
8-
strict_mode=False,
9-
strict_mode_allowed=None,
10-
*args,
11-
**kwargs,
12-
):
13-
async with Mocketizer.factory(
14-
test, truesocket_recording_dir, strict_mode, strict_mode_allowed, args
15-
):
16-
return await test(*args, **kwargs)
17-
18-
19-
async_mocketize = get_mocketize(wrapper_=wrapper)
20-
21-
22-
__all__ = ("async_mocketize",)
3+
# NOTE this is here for backwards-compat to keep old import-paths working
4+
__all__ = [
5+
"async_mocketize",
6+
]

Diff for: mocket/bytes.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from __future__ import annotations
2+
3+
from typing_extensions import Self
4+
5+
from mocket.core.entry import MocketBaseEntry, MocketBaseRequest, MocketBaseResponse
6+
from mocket.core.types import Address
7+
8+
9+
class MocketBytesRequest(MocketBaseRequest):
10+
def __init__(self) -> None:
11+
self._data = b""
12+
13+
@property
14+
def data(self) -> bytes:
15+
return self._data
16+
17+
@classmethod
18+
def from_data(cls: type[Self], data: bytes) -> Self:
19+
request = cls()
20+
request._data = data
21+
return request
22+
23+
24+
class MocketBytesResponse(MocketBaseResponse):
25+
def __init__(self, data: bytes | str | bool) -> None:
26+
if isinstance(data, str):
27+
data = data.encode()
28+
elif isinstance(data, bool):
29+
data = bytes(data)
30+
self._data = data
31+
32+
@property
33+
def data(self) -> bytes:
34+
return self._data
35+
36+
37+
class MocketBytesEntry(MocketBaseEntry):
38+
request_cls = MocketBytesRequest
39+
response_cls = MocketBytesResponse
40+
41+
def __init__(
42+
self,
43+
address: Address,
44+
responses: list[MocketBytesResponse | Exception | bytes | str | bool]
45+
| MocketBytesResponse
46+
| Exception
47+
| bytes
48+
| str
49+
| bool,
50+
) -> None:
51+
if not isinstance(responses, list):
52+
responses = [responses]
53+
54+
if not responses:
55+
responses = [MocketBytesResponse(data=b"")]
56+
57+
_responses = []
58+
for response in responses:
59+
if not isinstance(response, (MocketBytesResponse, Exception)):
60+
response = MocketBytesResponse(response)
61+
_responses.append(response)
62+
63+
super().__init__(address=address, responses=_responses)

Diff for: mocket/compat/__init__.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import mocket.compat.mockhttp as mockhttp
2+
import mocket.compat.mockredis as mockredis
3+
from mocket.bytes import MocketBytesEntry as MocketEntry
4+
from mocket.core.ssl.context import MocketSSLContext as FakeSSLContext
5+
6+
__all__ = [
7+
"FakeSSLContext",
8+
"MocketEntry",
9+
"mockhttp",
10+
"mockredis",
11+
]
File renamed without changes.

Diff for: mocket/compat/mockhttp.py

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
from __future__ import annotations
2+
3+
from io import BufferedReader
4+
from typing import Any
5+
6+
from mocket.http import (
7+
MocketHttpEntry,
8+
MocketHttpMethod,
9+
MocketHttpRequest,
10+
MocketHttpResponse,
11+
)
12+
from mocket.mocket import Mocket
13+
14+
15+
class Response(MocketHttpResponse):
16+
def __init__(
17+
self,
18+
body: str | bytes | BufferedReader = b"",
19+
status: int = 200,
20+
headers: dict[str, str] | None = None,
21+
) -> None:
22+
super().__init__(
23+
status_code=status,
24+
headers=headers,
25+
body=body,
26+
)
27+
28+
@property
29+
def status(self) -> int:
30+
return self.status_code
31+
32+
33+
class Request(MocketHttpRequest):
34+
@property
35+
def body(self) -> str | None: # type: ignore
36+
body = super().body
37+
if body is None:
38+
return None
39+
return body.decode()
40+
41+
42+
class Entry(MocketHttpEntry):
43+
request_cls = Request
44+
response_cls = Response # type: ignore[assignment]
45+
46+
CONNECT = MocketHttpMethod.CONNECT
47+
DELETE = MocketHttpMethod.DELETE
48+
GET = MocketHttpMethod.GET
49+
HEAD = MocketHttpMethod.HEAD
50+
OPTIONS = MocketHttpMethod.OPTIONS
51+
PATCH = MocketHttpMethod.PATCH
52+
POST = MocketHttpMethod.POST
53+
PUT = MocketHttpMethod.PUT
54+
TRACE = MocketHttpMethod.TRACE
55+
56+
METHODS = list(MocketHttpMethod)
57+
58+
def __init__(
59+
self,
60+
uri: str,
61+
method: MocketHttpMethod,
62+
responses: list[Exception | Response],
63+
match_querystring: bool = True,
64+
add_trailing_slash: bool = True,
65+
) -> None:
66+
super().__init__(
67+
method=method,
68+
uri=uri,
69+
responses=responses,
70+
match_querystring=match_querystring,
71+
add_trailing_slash=add_trailing_slash,
72+
)
73+
74+
def __repr__(self) -> str:
75+
return (
76+
f"{self.__class__.__name__}("
77+
f"method='{self.method.name}', "
78+
f"schema='{self.schema}', "
79+
f"location={self.address}, "
80+
f"path='{self.path}', "
81+
f"query='{self.query}'"
82+
")"
83+
)
84+
85+
@property
86+
def schema(self) -> str:
87+
return self.scheme
88+
89+
@classmethod
90+
def register(
91+
cls,
92+
method: MocketHttpMethod,
93+
uri: str,
94+
*responses: Exception | Response,
95+
**config: Any,
96+
) -> None:
97+
if "body" in config or "status" in config:
98+
raise AttributeError("Did you mean `Entry.single_register(...)`?")
99+
100+
if isinstance(config, dict):
101+
match_querystring = config.get("match_querystring", True)
102+
add_trailing_slash = config.get("add_trailing_slash", True)
103+
104+
entry = cls(
105+
method=method,
106+
uri=uri,
107+
responses=list(responses),
108+
match_querystring=match_querystring,
109+
add_trailing_slash=add_trailing_slash,
110+
)
111+
Mocket.register(entry)
112+
113+
@classmethod
114+
def single_register(
115+
cls,
116+
method: MocketHttpMethod,
117+
uri: str,
118+
body: str | bytes | BufferedReader = b"",
119+
status: int = 200,
120+
headers: dict[str, str] | None = None,
121+
match_querystring: bool = True,
122+
exception: Exception | None = None,
123+
) -> None:
124+
response: Response | Exception
125+
if exception is not None:
126+
response = exception
127+
else:
128+
response = Response(
129+
body=body,
130+
status=status,
131+
headers=headers,
132+
)
133+
134+
cls.register(
135+
method,
136+
uri,
137+
response,
138+
match_querystring=match_querystring,
139+
)

0 commit comments

Comments
 (0)