Skip to content

Commit

Permalink
Add aiohttp.ClientSession with methods.
Browse files Browse the repository at this point in the history
- `base_url` parameter: to simplify reusing the session with
   different methods.

- `json` parameter.
  • Loading branch information
Carglglz committed Oct 31, 2023
1 parent 13c89fc commit c1d7c31
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 26 deletions.
5 changes: 3 additions & 2 deletions micropython/uaiohttpclient/clientsession_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ async def fetch(client):
async def main():
async with aiohttp.ClientSession() as client:
html = await fetch(client)
print(html)
print(html.decode())


asyncio.run(main())
if __name__ == "__main__":
asyncio.run(main())
22 changes: 22 additions & 0 deletions micropython/uaiohttpclient/clientsession_methods_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import uaiohttpclient as aiohttp
import asyncio


async def main():
async with aiohttp.ClientSession("http://httpbin.org") as session:
async with session.get("/get") as resp:
assert resp.status == 200
rget = await resp.text()
print(f"GET: {rget.decode()}")
async with session.post("/post", json={"foo": "bar"}) as resp:
assert resp.status == 200
rpost = await resp.text()
print(f"POST: {rpost.decode()}")
async with session.put("/put", data=b"data") as resp:
assert resp.status == 200
rput = await resp.json()
print("PUT: ", rput)


if __name__ == "__main__":
asyncio.run(main())
105 changes: 81 additions & 24 deletions micropython/uaiohttpclient/uaiohttpclient.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import uasyncio as asyncio
import json as _json


class ClientResponse:
Expand All @@ -11,6 +12,9 @@ def read(self, sz=-1):
def text(self, sz=-1):
return self.read(sz=sz)

async def json(self):
return _json.loads(await self.read())

def __repr__(self):
return "<ClientResponse %d %s>" % (self.status, self.headers)

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


class ClientSession:
def __init__(self):
def __init__(self, base_url=""):
self._reader = None
self._base_url = base_url

async def __aenter__(self):
return self

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

def request(self, method, url, ssl=None):
return _RequestContextManager(self, self._request(method, url, ssl=ssl))
def request(self, method, url, data=None, json=None, ssl=None):
return _RequestContextManager(
self,
self._request(method, self._base_url + url, data=data, json=json, ssl=ssl),
)

async def _request(self, method, url, ssl=None):
async def _request(self, method, url, data=None, json=None, ssl=None):
redir_cnt = 0
redir_url = None
while redir_cnt < 2:
reader = yield from self.request_raw(method, url, ssl)
reader = yield from self.request_raw(method, url, data, json, ssl)

Check failure on line 84 in micropython/uaiohttpclient/uaiohttpclient.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (PLE1700)

micropython/uaiohttpclient/uaiohttpclient.py:84:22: PLE1700 `yield from` statement in async function; use `async for` instead
headers = []
sline = yield from reader.readline()

Check failure on line 86 in micropython/uaiohttpclient/uaiohttpclient.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (PLE1700)

micropython/uaiohttpclient/uaiohttpclient.py:86:21: PLE1700 `yield from` statement in async function; use `async for` instead
sline = sline.split(None, 2)
Expand Down Expand Up @@ -105,7 +113,11 @@ async def _request(self, method, url, ssl=None):
self._reader = reader
return resp

async def request_raw(self, method, url, ssl=None):
async def request_raw(self, method, url, data=None, json=None, ssl=None):
if json and isinstance(json, dict):
data = _json.dumps(json)
if data is not None and method == "GET":
method = "POST"
try:
proto, dummy, host, path = url.split("/", 3)
except ValueError:
Expand All @@ -129,20 +141,70 @@ async def request_raw(self, method, url, ssl=None):
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
# But explicitly set Connection: close, even though this should be default for 1.0,
# because some servers misbehave w/o it.
query = (
"%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n"
% (
method,
path,
host,
if not data:
query = (
"%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n"
% (
method,
path,
host,
)
)
)
else:
query = (
"""%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"""
% (
method,
path,
host,
"Content-Type: application/json\r\n" if json else "",
str(len(str(data))),
data,
)
)

yield from writer.awrite(query.encode("latin-1"))

Check failure on line 166 in micropython/uaiohttpclient/uaiohttpclient.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (PLE1700)

micropython/uaiohttpclient/uaiohttpclient.py:166:9: PLE1700 `yield from` statement in async function; use `async for` instead
# yield from writer.aclose()
return reader

def get(self, url, ssl=None):
return _RequestContextManager(self, self._request("GET", url, ssl=ssl))
return _RequestContextManager(self, self._request("GET", self._base_url + url, ssl=ssl))

def post(self, url, data=None, json=None, ssl=None):
return _RequestContextManager(
self,
self._request("POST", self._base_url + url, data=data, json=json, ssl=ssl),
)

def put(self, url, data=None, json=None, ssl=None):
return _RequestContextManager(
self,
self._request("PUT", self._base_url + url, data=data, json=json, ssl=ssl),
)

def patch(self, url, data=None, json=None, ssl=None):
return _RequestContextManager(
self,
self._request("PATCH", self._base_url + url, data=data, json=json, ssl=ssl),
)

def delete(self, url, ssl=None):
return _RequestContextManager(
self,
self._request("DELETE", self._base_url + url, ssl=ssl),
)

def head(self, url, ssl=None):
return _RequestContextManager(
self,
self._request("HEAD", self._base_url + url, ssl=ssl),
)

def options(self, url, ssl=None):
return _RequestContextManager(
self,
self._request("OPTIONS", self._base_url + url, ssl=ssl),
)


def request_raw(method, url):
Expand All @@ -163,19 +225,14 @@ def request_raw(method, url):
host, port = host.split(":", 1)
port = int(port)

reader, writer = yield from asyncio.open_connection(
host, port, ssl=proto == "https:"
)
reader, writer = yield from asyncio.open_connection(host, port, ssl=proto == "https:")
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
# But explicitly set Connection: close, even though this should be default for 1.0,
# because some servers misbehave w/o it.
query = (
"%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n"
% (
method,
path,
host,
)
query = "%s /%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\nUser-Agent: compat\r\n\r\n" % (
method,
path,
host,
)
yield from writer.awrite(query.encode("latin-1"))
# yield from writer.aclose()
Expand Down

0 comments on commit c1d7c31

Please sign in to comment.