Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/fix lint errors #30

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist
max-complexity = 10
max-line-length = 127
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
flake8 . --count --statistics

mypy-checks:
strategy:
Expand Down
4 changes: 0 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Connects to an echo server, sends a message and disconnect upon reply.
.. code-block:: python

import asyncio
import uvloop
from picows import ws_connect, WSFrame, WSTransport, WSListener, WSMsgType, WSCloseCode

class ClientListener(WSListener):
Expand All @@ -97,7 +96,6 @@ Connects to an echo server, sends a message and disconnect upon reply.


if __name__ == '__main__':
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
asyncio.run(main("ws://127.0.0.1:9001"))

This prints:
Expand All @@ -112,7 +110,6 @@ Echo server
.. code-block:: python

import asyncio
import uvloop
from picows import ws_create_server, WSFrame, WSTransport, WSListener, WSMsgType, WSUpgradeRequest

class ServerClientListener(WSListener):
Expand All @@ -138,7 +135,6 @@ Echo server
await server.serve_forever()

if __name__ == '__main__':
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
asyncio.run(main())


Expand Down
187 changes: 113 additions & 74 deletions examples/echo_client_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@
from picows import WSFrame, WSTransport, WSListener, ws_connect, WSMsgType
from time import time

_logger = getLogger(__name__)

try:
from examples.echo_client_cython import picows_main_cython
except ImportError:
picows_main_cython = None


RPS: Dict[str, List[float]] = {"ssl": [], "plain": []}
NAMES: List[str] = []
_logger = getLogger(__name__)


def create_client_ssl_context():
Expand Down Expand Up @@ -116,7 +121,101 @@ async def aiohttp_main(url: str, data: bytes, duration: int, ssl_context):
break


if __name__ == '__main__':
def run_for_websockets_library(plain_url, ssl_url, ssl_context, msg, duration):
global NAMES, RPS
_, rps = asyncio.run(websockets_main(plain_url, msg, duration, None))
RPS["plain"].append(rps)
name, rps = asyncio.run(websockets_main(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)
NAMES.append(name)


def run_for_aiohttp_library(plain_url, ssl_url, ssl_context, msg, duration):
global NAMES, RPS
_, rps = asyncio.run(aiohttp_main(plain_url, msg, duration, None))
RPS["plain"].append(rps)
name, rps = asyncio.run(aiohttp_main(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)
NAMES.append(name)


def run_picows_client(plain_url, ssl_url, ssl_context, msg, duration):
global NAMES, RPS
_, rps = asyncio.run(picows_main(plain_url, msg, duration, None))
RPS["plain"].append(rps)
name, rps = asyncio.run(picows_main(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)
NAMES.append(name)


def run_picows_cython_plain_client(plain_url, ssl_url, ssl_context, msg, duration):
global NAMES, RPS
print("Run picows cython plain client")
rps = asyncio.run(picows_main_cython(plain_url, msg, duration, None))
RPS["plain"].append(rps)


def run_picows_cython_ssl_client(plain_url, ssl_url, ssl_context, msg, duration):
global NAMES, RPS
print("Run picows cython ssl client")
rps = asyncio.run(picows_main_cython(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)


def run_boost_beast_client(args):
global NAMES, RPS

print("Run boost.beast plain client")
pr = subprocess.run([args.boost_client, b"0",
args.host.encode(),
args.plain_port.encode(),
args.msg_size, args.duration],
shell=False, check=True, capture_output=True)
_, rps = pr.stdout.split(b":", 2)
RPS["plain"].append(int(rps.decode()))

print("Run boost.beast ssl client")
pr = subprocess.run([args.boost_client, b"1",
args.host.encode(),
args.ssl_port.encode(),
args.msg_size, args.duration],
shell=False, check=True, capture_output=True)
name, rps = pr.stdout.split(b":", 2)
RPS["ssl"].append(int(rps.decode()))
NAMES.append("c++ boost.beast")


def print_result_and_plot(loop_name, msg_size):
for k, v in RPS.items():
print(k.replace("\n", " "), v)

print("names:", " | ".join(n.replace("\n", " ") for n in NAMES))

try:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(layout='constrained')

x = np.arange(len(NAMES))
width = 0.25 # the width of the bars
multiplier = 0

for cl_type, measurement in RPS.items():
offset = width * multiplier
ax.bar(x + offset, measurement, width, label=cl_type)
multiplier += 1

ax.set_ylabel('request/second')
ax.set_title(f'Echo round-trip performance \n({loop_name}, msg_size={msg_size})')
ax.set_xticks(x + width, NAMES)
ax.legend(loc='upper left', ncols=3)

plt.show()
except ImportError:
pass


def main():
parser = argparse.ArgumentParser(description="Benchmark for the various websocket clients",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--host", default="127.0.0.1", help="Server host")
Expand Down Expand Up @@ -146,87 +245,27 @@ async def aiohttp_main(url: str, data: bytes, duration: int, ssl_context):
ssl_url = f"wss://{args.host}:{args.ssl_port}/"

if not args.picows_plain_only and not args.picows_ssl_only:
_, rps = asyncio.run(websockets_main(plain_url, msg, duration, None))
RPS["plain"].append(rps)
name, rps = asyncio.run(websockets_main(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)
NAMES.append(name)

_, rps = asyncio.run(aiohttp_main(plain_url, msg, duration, None))
RPS["plain"].append(rps)
name, rps = asyncio.run(aiohttp_main(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)
NAMES.append(name)

_, rps = asyncio.run(picows_main(plain_url, msg, duration, None))
RPS["plain"].append(rps)
name, rps = asyncio.run(picows_main(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)
NAMES.append(name)
run_for_websockets_library(plain_url, ssl_url, ssl_context, msg, duration)
run_for_aiohttp_library(plain_url, ssl_url, ssl_context, msg, duration)
run_picows_client(plain_url, ssl_url, ssl_context, msg, duration)

if picows_main_cython is not None:
NAMES.append("picows\ncython client")

try:
from examples.echo_client_cython import picows_main_cython
if not args.picows_ssl_only:
print("Run picows cython plain client")
rps = asyncio.run(picows_main_cython(plain_url, msg, duration, None))
RPS["plain"].append(rps)
run_picows_cython_plain_client(plain_url, ssl_url, ssl_context, msg, duration)

if not args.picows_plain_only:
print("Run picows cython ssl client")
rps = asyncio.run(picows_main_cython(ssl_url, msg, duration, ssl_context))
RPS["ssl"].append(rps)

NAMES.append("picows\ncython client")
except ImportError:
pass
run_picows_cython_ssl_client(plain_url, ssl_url, ssl_context, msg, duration)

if not args.picows_plain_only and not args.picows_ssl_only and args.boost_client is not None:
print("Run boost.beast plain client")
pr = subprocess.run([args.boost_client, b"0",
args.host.encode(),
args.plain_port.encode(),
args.msg_size, args.duration],
shell=False, check=True, capture_output=True)
_, rps = pr.stdout.split(b":", 2)
RPS["plain"].append(int(rps.decode()))

print("Run boost.beast ssl client")
pr = subprocess.run([args.boost_client, b"1",
args.host.encode(),
args.ssl_port.encode(),
args.msg_size, args.duration],
shell=False, check=True, capture_output=True)
name, rps = pr.stdout.split(b":", 2)
RPS["ssl"].append(int(rps.decode()))
NAMES.append("c++ boost.beast")
run_boost_beast_client(args)

if args.picows_plain_only or args.picows_ssl_only:
exit()

for k, v in RPS.items():
print(k.replace("\n", " "), v)

print("names:", " | ".join(n.replace("\n", " ") for n in NAMES))
print_result_and_plot(loop_name, msg_size)

try:
import matplotlib.pyplot as plt

fig, ax = plt.subplots(layout='constrained')

x = np.arange(len(NAMES))
width = 0.25 # the width of the bars
multiplier = 0

for cl_type, measurement in RPS.items():
offset = width * multiplier
rects = ax.bar(x + offset, measurement, width, label=cl_type)
multiplier += 1

ax.set_ylabel('request/second')
ax.set_title(f'Echo round-trip performance \n({loop_name}, msg_size={msg_size})')
ax.set_xticks(x + width, NAMES)
ax.legend(loc='upper left', ncols=3)

plt.show()
except ImportError:
pass
if __name__ == '__main__':
main()
3 changes: 2 additions & 1 deletion examples/okx_roundtrip_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import logging

import picows
from picows import ws_connect, WSFrame, WSTransport, WSListener, WSMsgType, WSCloseCode
from picows import ws_connect, WSTransport, WSListener

EXPECTED_OKX_ROUNDTRIP_TIME = 0.1


class ClientListener(WSListener):
async def check_okx_roundtrip_time(self, transport: picows.WSTransport):
rtts = await transport.measure_roundtrip_time(5)
Expand Down
2 changes: 0 additions & 2 deletions examples/readme_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import uvloop
from picows import ws_connect, WSFrame, WSTransport, WSListener, WSMsgType, WSCloseCode


Expand All @@ -19,5 +18,4 @@ async def main(url):


if __name__ == '__main__':
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
asyncio.run(main("ws://127.0.0.1:9001"))
2 changes: 0 additions & 2 deletions examples/readme_server.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import uvloop
from picows import ws_create_server, WSFrame, WSTransport, WSListener, \
WSMsgType, WSUpgradeRequest

Expand Down Expand Up @@ -30,5 +29,4 @@ def listener_factory(r: WSUpgradeRequest):


if __name__ == '__main__':
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
asyncio.run(main())
18 changes: 15 additions & 3 deletions examples/subprotocol_negotiation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
ws_create_server, WSUpgradeResponse, WSUpgradeResponseWithListener, \
WSUpgradeRequest


class OCPPServerClientListener(WSListener):
def on_ws_connected(self, transport: WSTransport):
print("New client connected, negotiated protocol: ", transport.response.headers["Sec-WebSocket-Protocol"])
Expand All @@ -19,15 +20,26 @@ def on_ws_connected(self, transport: WSTransport):
async def main():
def server_client_factory(request: WSUpgradeRequest):
if "ocpp2.1" in request.headers["Sec-WebSocket-Protocol"]:
return WSUpgradeResponseWithListener(WSUpgradeResponse.create_101_response(extra_headers={"Sec-WebSocket-Protocol": "ocpp2.1"}), OCPPServerClientListener())
return WSUpgradeResponseWithListener(
WSUpgradeResponse.create_101_response(extra_headers={"Sec-WebSocket-Protocol": "ocpp2.1"}),
OCPPServerClientListener())
else:
return WSUpgradeResponseWithListener(WSUpgradeResponse.create_error_response(HTTPStatus.BAD_REQUEST, b"requested websocket subprotocol is not supported"), None)
return WSUpgradeResponseWithListener(
WSUpgradeResponse.create_error_response(
HTTPStatus.BAD_REQUEST,
b"requested websocket subprotocol is not supported"
),
None)

server = await ws_create_server(server_client_factory, "127.0.0.1", 27001)
asyncio.create_task(server.serve_forever())

# Client request support for either ocpp1.6 or ocpp2.1 protocol
(transport, client) = await ws_connect(OCPPClientListener, "ws://127.0.0.1:27001/", extra_headers={"Sec-WebSocket-Protocol": "ocpp1.6,ocpp2.1"})
(transport, client) = await ws_connect(
OCPPClientListener,
"ws://127.0.0.1:27001/",
extra_headers={"Sec-WebSocket-Protocol": "ocpp1.6,ocpp2.1"}
)

transport.disconnect()
await transport.wait_disconnected()
Expand Down
Loading
Loading