Skip to content

Commit 5e2c45d

Browse files
committed
Add aiohttp.ClientSession with methods.
- `base_url` parameter: to simplify reusing the session with different methods. - `json` parameter.
1 parent 53e8608 commit 5e2c45d

File tree

3 files changed

+103
-16
lines changed

3 files changed

+103
-16
lines changed

micropython/uaiohttpclient/clientsession_example.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ async def fetch(client):
1111
async def main():
1212
async with aiohttp.ClientSession() as client:
1313
html = await fetch(client)
14-
print(html)
14+
print(html.decode())
1515

1616

17-
asyncio.run(main())
17+
if __name__ == "__main__":
18+
asyncio.run(main())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import uaiohttpclient as aiohttp
2+
import asyncio
3+
4+
5+
async def main():
6+
async with aiohttp.ClientSession("http://httpbin.org") as session:
7+
async with session.get("/get") as resp:
8+
assert resp.status == 200
9+
rget = await resp.text()
10+
print(f"GET: {rget.decode()}")
11+
async with session.post("/post", json={"foo": "bar"}) as resp:
12+
assert resp.status == 200
13+
rpost = await resp.text()
14+
print(f"POST: {rpost.decode()}")
15+
async with session.put("/put", data=b"data") as resp:
16+
assert resp.status == 200
17+
rput = await resp.json()
18+
print("PUT: ", rput)
19+
20+
21+
if __name__ == "__main__":
22+
asyncio.run(main())

micropython/uaiohttpclient/uaiohttpclient.py

+78-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import uasyncio as asyncio
2+
import json as _json
23

34

45
class ClientResponse:
@@ -11,6 +12,9 @@ def read(self, sz=-1):
1112
def text(self, sz=-1):
1213
return self.read(sz=sz)
1314

15+
async def json(self):
16+
return _json.loads(await self.read())
17+
1418
def __repr__(self):
1519
return "<ClientResponse %d %s>" % (self.status, self.headers)
1620

@@ -57,23 +61,27 @@ async def __aexit__(self, *args):
5761

5862

5963
class ClientSession:
60-
def __init__(self):
64+
def __init__(self, base_url=""):
6165
self._reader = None
66+
self._base_url = base_url
6267

6368
async def __aenter__(self):
6469
return self
6570

6671
async def __aexit__(self, *args):
6772
return await asyncio.sleep(0)
6873

69-
def request(self, method, url, ssl=None):
70-
return _RequestContextManager(self, self._request(method, url, ssl=ssl))
74+
def request(self, method, url, data=None, json=None, ssl=None):
75+
return _RequestContextManager(
76+
self,
77+
self._request(method, self._base_url + url, data=data, json=json, ssl=ssl),
78+
)
7179

72-
async def _request(self, method, url, ssl=None):
80+
async def _request(self, method, url, data=None, json=None, ssl=None):
7381
redir_cnt = 0
7482
redir_url = None
7583
while redir_cnt < 2:
76-
reader = yield from self.request_raw(method, url, ssl)
84+
reader = yield from self.request_raw(method, url, data, json, ssl)
7785
headers = []
7886
sline = yield from reader.readline()
7987
sline = sline.split(None, 2)
@@ -105,7 +113,11 @@ async def _request(self, method, url, ssl=None):
105113
self._reader = reader
106114
return resp
107115

108-
async def request_raw(self, method, url, ssl=None):
116+
async def request_raw(self, method, url, data=None, json=None, ssl=None):
117+
if json and isinstance(json, dict):
118+
data = _json.dumps(json)
119+
if data is not None and method == "GET":
120+
method = "POST"
109121
try:
110122
proto, dummy, host, path = url.split("/", 3)
111123
except ValueError:
@@ -129,20 +141,72 @@ async def request_raw(self, method, url, ssl=None):
129141
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
130142
# But explicitly set Connection: close, even though this should be default for 1.0,
131143
# because some servers misbehave w/o it.
132-
query = (
133-
"%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n"
134-
% (
135-
method,
136-
path,
137-
host,
144+
if not data:
145+
query = (
146+
"%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n"
147+
% (
148+
method,
149+
path,
150+
host,
151+
)
138152
)
139-
)
153+
else:
154+
query = (
155+
"""%s /%s HTTP/1.0\r\nHost: %s\r\n%sContent-Length: %s\r\n\r\n%s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n"""
156+
% (
157+
method,
158+
path,
159+
host,
160+
"Content-Type: application/json\r\n" if json else "",
161+
str(len(str(data))),
162+
data,
163+
)
164+
)
165+
140166
yield from writer.awrite(query.encode("latin-1"))
141167
# yield from writer.aclose()
142168
return reader
143169

144170
def get(self, url, ssl=None):
145-
return _RequestContextManager(self, self._request("GET", url, ssl=ssl))
171+
return _RequestContextManager(
172+
self, self._request("GET", self._base_url + url, ssl=ssl)
173+
)
174+
175+
def post(self, url, data=None, json=None, ssl=None):
176+
return _RequestContextManager(
177+
self,
178+
self._request("POST", self._base_url + url, data=data, json=json, ssl=ssl),
179+
)
180+
181+
def put(self, url, data=None, json=None, ssl=None):
182+
return _RequestContextManager(
183+
self,
184+
self._request("PUT", self._base_url + url, data=data, json=json, ssl=ssl),
185+
)
186+
187+
def patch(self, url, data=None, json=None, ssl=None):
188+
return _RequestContextManager(
189+
self,
190+
self._request("PATCH", self._base_url + url, data=data, json=json, ssl=ssl),
191+
)
192+
193+
def delete(self, url, ssl=None):
194+
return _RequestContextManager(
195+
self,
196+
self._request("DELETE", self._base_url + url, ssl=ssl),
197+
)
198+
199+
def head(self, url, ssl=None):
200+
return _RequestContextManager(
201+
self,
202+
self._request("HEAD", self._base_url + url, ssl=ssl),
203+
)
204+
205+
def options(self, url, ssl=None):
206+
return _RequestContextManager(
207+
self,
208+
self._request("OPTIONS", self._base_url + url, ssl=ssl),
209+
)
146210

147211

148212
def request_raw(method, url):

0 commit comments

Comments
 (0)