Skip to content

Commit 6d7a44a

Browse files
committed
Lint, test and fix bug with form data
1 parent e372574 commit 6d7a44a

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed

adafruit_requests.py

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@
5050
5151
"""
5252

53-
import gc
54-
5553
__version__ = "0.0.0-auto.0"
5654
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Requests.git"
5755

@@ -61,16 +59,23 @@ def __init__(self, response):
6159
self._response = response
6260

6361
def read(self, size=-1):
62+
"""Read as much as available or up to size and return it in a byte string.
63+
64+
Do NOT use this unless you really need to. Reusing memory with `readinto` is much better.
65+
"""
6466
if size == -1:
6567
return self._response.content
6668
return self._response.socket.recv(size)
6769

6870
def readinto(self, buf):
69-
return self._response._readinto(buf)
71+
"""Read as much as available into buf or until it is full. Returns the number of bytes read
72+
into buf."""
73+
return self._response._readinto(buf) # pylint: disable=protected-access
7074

7175

7276
class Response:
7377
"""The response from a request, contains all the headers/content"""
78+
# pylint: disable=too-many-instance-attributes
7479

7580
encoding = None
7681

@@ -98,7 +103,6 @@ def __init__(self, sock, session=None):
98103
self.reason = self._readto(b"\r\n")
99104
self._parse_headers()
100105
self._raw = None
101-
self._content_read = 0
102106
self._session = session
103107

104108
def __enter__(self):
@@ -114,8 +118,7 @@ def _recv_into(self, buf, size=0):
114118
read_size = len(b)
115119
buf[:read_size] = b
116120
return read_size
117-
else:
118-
return self.socket.recv_into(buf, size)
121+
return self.socket.recv_into(buf, size)
119122

120123
def _readto(self, first, second=b""):
121124
buf = self._receive_buffer
@@ -216,7 +219,7 @@ def _throw_away(self, nbytes):
216219
nbytes -= self._read_from_buffer(nbytes=nbytes)
217220

218221
buf = self._receive_buffer
219-
for i in range(nbytes // len(buf)):
222+
for _ in range(nbytes // len(buf)):
220223
self._recv_into(buf)
221224
remaining = nbytes % len(buf)
222225
if remaining:
@@ -239,7 +242,7 @@ def close(self):
239242
self._throw_away(chunk_size + 2)
240243
self._parse_headers()
241244
if self._session:
242-
self._session.free_socket(self.socket)
245+
self._session._free_socket(self.socket) # pylint: disable=protected-access
243246
else:
244247
self.socket.close()
245248
self.socket = None
@@ -340,6 +343,7 @@ def iter_content(self, chunk_size=1, decode_unicode=False):
340343

341344

342345
class Session:
346+
"""HTTP session that shares sockets and ssl context."""
343347
def __init__(self, socket_pool, ssl_context=None):
344348
self._socket_pool = socket_pool
345349
self._ssl_context = ssl_context
@@ -348,11 +352,28 @@ def __init__(self, socket_pool, ssl_context=None):
348352
self._socket_free = {}
349353
self._last_response = None
350354

351-
def free_socket(self, socket):
355+
def _free_socket(self, socket):
356+
352357
if socket not in self._open_sockets.values():
353358
raise RuntimeError("Socket not from session")
354359
self._socket_free[socket] = True
355360

361+
def _free_sockets(self):
362+
free_sockets = []
363+
for sock in self._socket_free:
364+
if self._socket_free[sock]:
365+
sock.close()
366+
free_sockets.append(sock)
367+
for sock in free_sockets:
368+
del self._socket_free[sock]
369+
key = None
370+
for k in self._open_sockets:
371+
if self._open_sockets[k] == sock:
372+
key = k
373+
break
374+
if key:
375+
del self._open_sockets[key]
376+
356377
def _get_socket(self, host, port, proto, *, timeout=1):
357378
key = (host, port, proto)
358379
if key in self._open_sockets:
@@ -381,20 +402,7 @@ def _get_socket(self, host, port, proto, *, timeout=1):
381402

382403
# We couldn't connect due to memory so clean up the open sockets.
383404
if not ok:
384-
free_sockets = []
385-
for s in self._socket_free:
386-
if self._socket_free[s]:
387-
s.close()
388-
free_sockets.append(s)
389-
for s in free_sockets:
390-
del self._socket_free[s]
391-
key = None
392-
for k in self._open_sockets:
393-
if self._open_sockets[k] == s:
394-
key = k
395-
break
396-
if key:
397-
del self._open_sockets[key]
405+
self._free_sockets()
398406
# Recreate the socket because the ESP-IDF won't retry the connection if it failed once.
399407
sock = None # Clear first so the first socket can be cleaned up.
400408
sock = self._socket_pool.socket(addr_info[0], addr_info[1], addr_info[2])
@@ -466,7 +474,7 @@ def request(
466474
socket.send(b"Content-Type: application/json\r\n")
467475
if data:
468476
if isinstance(data, dict):
469-
sock.send(b"Content-Type: application/x-www-form-urlencoded\r\n")
477+
socket.send(b"Content-Type: application/x-www-form-urlencoded\r\n")
470478
_post_data = ""
471479
for k in data:
472480
_post_data = "{}&{}={}".format(_post_data, k, data[k])
@@ -513,22 +521,28 @@ def delete(self, url, **kw):
513521

514522
# Backwards compatible API:
515523

516-
_default_session = None
524+
_default_session = None # pylint: disable=invalid-name
517525

518526

519-
class FakeSSLContext:
520-
def wrap_socket(self, socket, server_hostname=None):
527+
class _FakeSSLContext:
528+
@staticmethod
529+
def wrap_socket(socket, server_hostname=None):
530+
"""Return the same socket"""
531+
# pylint: disable=unused-argument
521532
return socket
522533

523534

524535
def set_socket(sock, iface=None):
525-
global _default_session
526-
_default_session = Session(sock, FakeSSLContext())
536+
"""Legacy API for setting the socket and network interface. Use a `Session` instead."""
537+
global _default_session # pylint: disable=global-statement,invalid-name
538+
_default_session = Session(sock, _FakeSSLContext())
527539
if iface:
528540
sock.set_interface(iface)
529541

530542

531543
def request(method, url, data=None, json=None, headers=None, stream=False, timeout=1):
544+
"""Send HTTP request"""
545+
# pylint: disable=too-many-arguments
532546
_default_session.request(
533547
method,
534548
url,

tests/post_test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ def test_string():
3939
sock.send.assert_called_with(b"31F")
4040

4141

42+
def test_form():
43+
pool = mocket.MocketPool()
44+
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)
45+
sock = mocket.Mocket(headers + encoded)
46+
pool.socket.return_value = sock
47+
48+
s = adafruit_requests.Session(pool)
49+
data = {"Date": "July 25, 2019"}
50+
r = s.post("http://" + host + "/post", data=data)
51+
sock.connect.assert_called_once_with((host, 80))
52+
sock.send.assert_called_with(b"Date=July 25, 2019")
53+
54+
4255
def test_json():
4356
pool = mocket.MocketPool()
4457
pool.getaddrinfo.return_value = ((None, None, None, None, (ip, 80)),)

0 commit comments

Comments
 (0)