Package: tremolo
TremoloTremolo is astream-oriented, asynchronous, programmable HTTP server written in pure Python. It can also serve as anASGI server.Tremolo provides a common routing functionality to some unique features such as download/upload speed limiters, etc. While maintaining its simplicity and performance.Being built with a stream in mind, Tremolo tends to useyieldinstead ofreturnin route handlers.@app.route('/hello')asyncdefhello_world(**server):yieldb'Hello 'yieldb'world!'You can take advantage of this to serve big files efficiently:@app.route('/my/url/big.data')asyncdefmy_big_data(content_type='application/octet-stream',**server):# buffer_size = 16384buffer_size=server['context'].options['buffer_size']withopen('/my/folder/big.data','rb')asf:chunk=Truewhilechunk:chunk=f.read(buffer_size)yieldchunkAnd other use cases…FeaturesTremolo is only suitable for those who valueminimalismand stability over features.With only3klines of code, withno dependenciesother than thePython Standard Library, it gives you:HTTP/1.x withWebSocket supportKeep-Alive connections withconfigurable limitStream chunked uploadsStream multipart uploadsDownload/upload speed throttlingResumable downloadsFramework features; routing, middleware, etc.ASGI serverPyPy compatibleExampleHere is a completehello worldexample in case you missed the usualreturn.fromtremoloimportTremoloapp=Tremolo()@app.route('/hello')asyncdefhello_world(**server):return'Hello world!','latin-1'if__name__=='__main__':app.run('0.0.0.0',8000,debug=True)Well,latin-1on the right side is not required. The default isutf-8.You can save it ashello.pyand just run it withpython3 hello.py.Your firsthello worldpage with Tremolo will be athttp://localhost:8000/hello.ASGI ServerTremolo is an HTTP Server framework. You can build abstractions on top of it, say an ASGI server.In fact, Tremolo already has ASGI server (plus WebSocket) implementation.So you can immediately use existingASGI applications / frameworks, behind Tremolo (ASGI server).For example, If a minimal ASGI application with the nameexample.py:asyncdefapp(scope,receive,send):assertscope['type']=='http'awaitsend({'type':'http.response.start','status':200,'headers':[(b'content-type',b'text/plain')]})awaitsend({'type':'http.response.body','body':b'Hello world!'})Then you can run as follows:python3 -m tremolo --debug --bind 127.0.0.1:8000 example:appTo see more available options:python3 -m tremolo --helpIt's also possible to run the ASGI server programmatically (example with uvloop):python3 example_uvloop.pyBenchmarkingThe first thing to note is that Tremolo is a pure Python server framework.As a pure Python server framework, it is hard to find a comparison.
Because most servers/frameworks today are full of steroids likehttptools,uvloop, Rust, etc.You can try comparing withUvicornwith the following option (disabling steroids to be fair):uvicorn --loop asyncio --http h11 --log-level error example:appvspython3 -m tremolo --log-level ERROR example:appYou will find that Tremolo is reasonably fast.However, it should be noted that bottlenecks often occur on the application side.
Which means that in real-world usage, throughput reflects more on the application than the server.Misc.Tremolo utilizesSO_REUSEPORT(Linux 3.9+) to load balance worker processes.app.run('0.0.0.0',8000,worker_num=2)Tremolo can also listen to multiple ports in case you are using an external load balancer like Nginx / HAProxy.app.listen(8001)app.listen(8002)app.run('0.0.0.0',8000)You can even get higher concurrency withPyPyoruvloop:importasyncioimportuvloopasyncio.set_event_loop_policy(uvloop.EventLoopPolicy())Installingpython3 -m pip install --upgrade tremoloTestingJust runpython3 alltests.pyfor all tests. Or individualtest_*.pyin thetests/folder, for examplepython3 tests/test_cli.py.If you also want measurements withcoverage:coverage run alltests.py
coverage combine
coverage report
coverage html # to generate html reportsLicenseMIT