5
5
from contextlib import ExitStack , contextmanager
6
6
from enum import StrEnum
7
7
from http import HTTPMethod , HTTPStatus
8
- from typing import TypedDict , Unpack
8
+ from typing import Any , TypedDict , Unpack
9
9
10
10
import js
11
11
21
21
Headers = dict [str , str ] | list [tuple [str , str ]]
22
22
23
23
24
+ # https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties
25
+ class RequestInitCfProperties (TypedDict , total = False ):
26
+ apps : bool | None
27
+ cacheEverything : bool | None
28
+ cacheKey : str | None
29
+ cacheTags : list [str ] | None
30
+ cacheTtl : int
31
+ cacheTtlByStatus : dict [str , int ]
32
+ image : (
33
+ Any | None
34
+ ) # TODO: https://developers.cloudflare.com/images/transform-images/transform-via-workers/
35
+ mirage : bool | None
36
+ polish : str | None
37
+ resolveOverride : str | None
38
+ scrapeShield : bool | None
39
+ webp : bool | None
40
+
41
+
42
+ # This matches the Request options:
43
+ # https://developers.cloudflare.com/workers/runtime-apis/request/#options
24
44
class FetchKwargs (TypedDict , total = False ):
25
45
headers : Headers | None
26
46
body : "Body | None"
27
47
method : HTTPMethod = HTTPMethod .GET
48
+ redirect : str | None
49
+ cf : RequestInitCfProperties | None
28
50
29
51
30
52
# TODO: Pyodide's FetchResponse.headers returns a dict[str, str] which means
@@ -65,6 +87,15 @@ async def formData(self) -> "FormData":
65
87
except JsException as exc :
66
88
raise _to_python_exception (exc ) from exc
67
89
90
+ def replace_body (self , body : Body ) -> "FetchResponse" :
91
+ """
92
+ Returns a new Response object with the same options (status, headers, etc) as
93
+ the original but with an updated body.
94
+ """
95
+ b = body .js_object if isinstance (body , FormData ) else body
96
+ js_resp = js .Response .new (b , self .js_response )
97
+ return FetchResponse (js_resp .url , js_resp )
98
+
68
99
69
100
async def fetch (
70
101
resource : str ,
@@ -99,7 +130,7 @@ def __init__(
99
130
self ,
100
131
body : Body ,
101
132
status : HTTPStatus | int = HTTPStatus .OK ,
102
- statusText = "" ,
133
+ status_text = "" ,
103
134
headers : Headers = None ,
104
135
):
105
136
"""
@@ -108,7 +139,7 @@ def __init__(
108
139
Based on the JS API of the same name:
109
140
https://developer.mozilla.org/en-US/docs/Web/API/Response/Response.
110
141
"""
111
- options = self ._create_options (status , statusText , headers )
142
+ options = self ._create_options (status , status_text , headers )
112
143
113
144
# Initialise via the FetchResponse super-class which gives us access to
114
145
# methods that we would ordinarily have to redeclare.
@@ -119,13 +150,15 @@ def __init__(
119
150
120
151
@staticmethod
121
152
def _create_options (
122
- status : HTTPStatus | int = HTTPStatus .OK , statusText = "" , headers : Headers = None
153
+ status : HTTPStatus | int = HTTPStatus .OK ,
154
+ status_text = "" ,
155
+ headers : Headers = None ,
123
156
):
124
157
options = {
125
158
"status" : status .value if isinstance (status , HTTPStatus ) else status ,
126
159
}
127
- if len ( statusText ) > 0 :
128
- options ["statusText" ] = statusText
160
+ if status_text :
161
+ options ["statusText" ] = status_text
129
162
if headers :
130
163
if isinstance (headers , list ):
131
164
# We should have a list[tuple[str, str]]
@@ -154,10 +187,10 @@ def redirect(url: str, status: HTTPStatus | int = HTTPStatus.FOUND):
154
187
def json (
155
188
data : str | dict [str , str ],
156
189
status : HTTPStatus | int = HTTPStatus .OK ,
157
- statusText = "" ,
190
+ status_text = "" ,
158
191
headers : Headers = None ,
159
192
):
160
- options = Response ._create_options (status , statusText , headers )
193
+ options = Response ._create_options (status , status_text , headers )
161
194
with _manage_pyproxies () as pyproxies :
162
195
try :
163
196
return js .Response .json (
0 commit comments