Skip to content

Commit e723252

Browse files
authored
Multiple HTTP writes (#125)
* Fix for #111. * Bump version.
1 parent ef2d1d5 commit e723252

File tree

8 files changed

+79
-20
lines changed

8 files changed

+79
-20
lines changed

.isort.cfg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
[settings]
2-
known_third_party = aiohttp,async_timeout,decorator,gevent,mock,pook,pytest,redis,requests,setuptools,six,sure,urllib3
2+
multi_line_output=3
3+
include_trailing_comma=True
4+
force_grid_wrap=0
5+
use_parentheses=True
6+
line_length=88

.pre-commit-config.yaml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v3.1.0
3+
rev: v3.2.0
44
hooks:
55
- id: check-yaml
6+
args: ['--unsafe']
67
- id: check-json
78
- id: end-of-file-fixer
89
- id: trailing-whitespace
9-
# - id: no-commit-to-branch
10+
- id: no-commit-to-branch
1011
- id: pretty-format-json
1112
args: ['--autofix']
1213

@@ -16,13 +17,8 @@ repos:
1617
- id: autoflake
1718
args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variable']
1819

19-
- repo: https://github.com/asottile/seed-isort-config
20-
rev: v2.2.0
21-
hooks:
22-
- id: seed-isort-config
23-
2420
- repo: https://github.com/timothycrosley/isort
25-
rev: 4.3.21
21+
rev: 5.5.2
2622
hooks:
2723
- id: isort
2824

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ A socket mock framework
2020
-------------------------
2121
for all kinds of socket *animals*, web-clients included - with gevent/asyncio/SSL support
2222

23+
...and then MicroPython's *urequest* (*mocket >= 3.9.1*)
24+
25+
2326
Versioning
2427
==========
2528
Starting from *3.7.0*, Mocket major version will follow the same numbering pattern as Python's and therefore indicate the most recent Python version that is supported.

mocket/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
try:
22
# Py2
3-
from mocket import mocketize, Mocket, MocketEntry, Mocketizer
3+
from mocket import Mocket, MocketEntry, Mocketizer, mocketize
44
except ImportError:
55
# Py3
6-
from mocket.mocket import mocketize, Mocket, MocketEntry, Mocketizer
6+
from mocket.mocket import Mocket, MocketEntry, Mocketizer, mocketize
77

88
__all__ = ("mocketize", "Mocket", "MocketEntry", "Mocketizer")
99

10-
__version__ = "3.9.0"
10+
__version__ = "3.9.1"

mocket/mocket.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
hasher = xxh32 or hashlib.md5
3939

4040
try: # pragma: no cover
41-
from urllib3.contrib.pyopenssl import inject_into_urllib3, extract_from_urllib3
41+
from urllib3.contrib.pyopenssl import extract_from_urllib3, inject_into_urllib3
4242

4343
pyopenssl_override = True
4444
except ImportError:
@@ -386,7 +386,7 @@ def send(self, data, *args, **kwargs): # pragma: no cover
386386
else:
387387
req = Mocket.last_request()
388388
if hasattr(req, "add_data"):
389-
req.add_data(decode_from_bytes(data))
389+
req.add_data(data)
390390
self._entry = entry
391391
return len(data)
392392

mocket/mockhttp.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
class Request:
3333
parser = None
34+
_body = None
3435

3536
def __init__(self, data):
3637
self.parser = HttpParser()
@@ -39,15 +40,20 @@ def __init__(self, data):
3940
self.method = self.parser.get_method()
4041
self.path = self.parser.get_path()
4142
self.headers = self.parser.get_headers()
42-
self.body = decode_from_bytes(self.parser.recv_body())
4343
self.querystring = parse_qs(
4444
unquote_utf8(self.parser.get_query_string()), keep_blank_values=True
4545
)
4646
if self.querystring:
4747
self.path += "?{}".format(self.parser.get_query_string())
4848

4949
def add_data(self, data):
50-
self.body += data
50+
self.parser.execute(data, len(data))
51+
52+
@property
53+
def body(self):
54+
if self._body is None:
55+
self._body = decode_from_bytes(self.parser.recv_body())
56+
return self._body
5157

5258
def __str__(self):
5359
return "{} - {} - {}".format(self.method, self.path, self.headers)
@@ -82,7 +88,10 @@ def get_protocol_data(self, str_format_fun_name="capitalize"):
8288
status_code=self.status, status=STATUS[self.status]
8389
)
8490
header_lines = CRLF.join(
85-
("{0}: {1}".format(getattr(k, str_format_fun_name)(), v) for k, v in self.headers.items())
91+
(
92+
"{0}: {1}".format(getattr(k, str_format_fun_name)(), v)
93+
for k, v in self.headers.items()
94+
)
8695
)
8796
return "{0}\r\n{1}\r\n\r\n".format(status_line, header_lines).encode("utf-8")
8897

mocket/plugins/httpretty/__init__.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
from sys import version_info
22

33
from mocket import Mocket, mocketize
4-
from mocket.compat import byte_type, encode_to_bytes, text_type
4+
from mocket.compat import byte_type, text_type
55
from mocket.mockhttp import Entry as MocketHttpEntry
6+
from mocket.mockhttp import Request as MocketHttpRequest
67
from mocket.mockhttp import Response as MocketHttpResponse
78

89

910
def httprettifier_headers(headers):
1011
return {k.lower().replace("_", "-"): v for k, v in headers.items()}
1112

1213

14+
class Request(MocketHttpRequest):
15+
@property
16+
def body(self):
17+
if self._body is None:
18+
self._body = self.parser.recv_body()
19+
return self._body
20+
21+
1322
class Response(MocketHttpResponse):
1423
def get_protocol_data(self, str_format_fun_name="lower"):
1524
if "server" in self.headers and self.headers["server"] == "Python/Mocket":
1625
self.headers["server"] = "Python/HTTPretty"
17-
return super(Response, self).get_protocol_data(str_format_fun_name=str_format_fun_name)
26+
return super(Response, self).get_protocol_data(
27+
str_format_fun_name=str_format_fun_name
28+
)
1829

1930
def set_base_headers(self):
2031
super(Response, self).set_base_headers()
@@ -27,6 +38,7 @@ def set_extra_headers(self, headers):
2738

2839

2940
class Entry(MocketHttpEntry):
41+
request_cls = Request
3042
response_cls = Response
3143

3244

@@ -102,7 +114,6 @@ def __init__(self):
102114
def __getattr__(self, name):
103115
if name == "last_request":
104116
last_request = getattr(Mocket, "last_request")()
105-
last_request.body = encode_to_bytes(last_request.body)
106117
return last_request
107118
elif name == "latest_requests":
108119
return getattr(Mocket, "_requests")

tests/main/test_http.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io
55
import json
66
import os
7+
import socket
78
import tempfile
89
import time
910
from unittest import TestCase
@@ -321,3 +322,38 @@ def test_post_file_object(self):
321322
files = {"content": file_obj}
322323
r = requests.post(url, files=files, data={}, verify=False)
323324
self.assertEqual(r.status_code, 201)
325+
326+
@mocketize
327+
def test_sockets(self):
328+
"""
329+
https://github.com/mindflayer/python-mocket/issues/111
330+
https://gist.github.com/amotl/015ef6b336db55128798d7f1a9a67dea
331+
"""
332+
333+
# Define HTTP conversation.
334+
url = "http://127.0.0.1/api/data"
335+
Entry.single_register(Entry.POST, url)
336+
337+
# Define HTTP url segments and data.
338+
host = "127.0.0.1"
339+
port = 80
340+
method = "POST"
341+
path = "/api/data"
342+
data = json.dumps({"hello": "world"})
343+
344+
# Invoke HTTP request.
345+
address = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0]
346+
sock = socket.socket(address[0], address[1], address[2])
347+
348+
sock.connect(address[-1])
349+
sock.write("%s %s HTTP/1.0\r\n" % (method, path))
350+
sock.write("Host: %s\r\n" % host)
351+
sock.write("Content-Type: application/json\r\n")
352+
sock.write("Content-Length: %d\r\n" % len(data))
353+
sock.write("Connection: close\r\n\r\n")
354+
sock.write(data)
355+
sock.close()
356+
357+
# Proof that worked.
358+
print(Mocket.last_request().__dict__)
359+
assert Mocket.last_request().body == '{"hello": "world"}'

0 commit comments

Comments
 (0)