Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

pyruvate

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pyruvate

WSGI server implemented in Rust.

  • 1.3.0
  • PyPI
  • Socket score

Maintainers
1

Pyruvate WSGI server

.. image:: https://gitlab.com/tschorr/pyruvate/badges/main/pipeline.svg :target: https://gitlab.com/tschorr/pyruvate

.. image:: https://codecov.io/gl/tschorr/pyruvate/branch/main/graph/badge.svg :target: https://codecov.io/gl/tschorr/pyruvate

.. image:: http://img.shields.io/pypi/v/pyruvate.svg :target: https://pypi.org/project/pyruvate

Pyruvate is a fast, multithreaded WSGI <https://www.python.org/dev/peps/pep-3333>_ server implemented in Rust <https://www.rust-lang.org/>_.

Features

  • Non-blocking read/write using mio <https://github.com/tokio-rs/mio>_
  • Request parsing using httparse <https://github.com/seanmonstar/httparse>_
  • rust-cpython <https://github.com/dgrunwald/rust-cpython>_ based Python interface
  • Worker pool based on threadpool <https://github.com/rust-threadpool/rust-threadpool>_
  • PasteDeploy <https://pastedeploy.readthedocs.io/en/latest/>_ entry point

Installation

If you are on Linux and use a recent Python version,

.. code-block::

$ pip install pyruvate

is probably all you need to do.

Binary Packages +++++++++++++++

manylinux_2_17 <https://peps.python.org/pep-0600/>_ and musllinux_1_1 <https://peps.python.org/pep-0656/>_ wheels are available for the x86_64 architecture and active Python 3 versions (currently 3.8-3.12).

Source Installation +++++++++++++++++++

On macOS or if for any other reason you want to install the source tarball (e.g. using pip install --no-binary) you will need to install Rust <https://doc.rust-lang.org/book/ch01-01-installation.html>_ first.

Development Installation ++++++++++++++++++++++++

  • Install Rust <https://doc.rust-lang.org/book/ch01-01-installation.html>__

  • Install and activate a Python 3 (>= 3.8) virtualenv <https://docs.python.org/3/tutorial/venv.html>_

  • Install setuptools_rust <https://github.com/PyO3/setuptools-rust>_ using pip::

    $ pip install setuptools_rust

  • Install Pyruvate, e.g. using pip::

    $ pip install -e git+https://gitlab.com/tschorr/pyruvate.git#egg=pyruvate[test]

Using Pyruvate in your WSGI application

From Python using a TCP port ++++++++++++++++++++++++++++

A hello world WSGI application using Pyruvate listening on 127.0.0.1:7878 and using 2 worker threads looks like this:

.. code-block:: python

import pyruvate

def application(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers, None)
    return [b"Hello world!\n"]

pyruvate.serve(application, "127.0.0.1:7878", 2)

From Python using a Unix socket +++++++++++++++++++++++++++++++

A hello world WSGI application using Pyruvate listening on unix:/tmp/pyruvate.socket and using 2 worker threads looks like this:

.. code-block:: python

import pyruvate

def application(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers, None)
    return [b"Hello world!\n"]

pyruvate.serve(application, "/tmp/pyruvate.socket", 2)

Using PasteDeploy +++++++++++++++++

Again listening on 127.0.0.1:7878 and using 2 worker threads::

[server:main]
use = egg:pyruvate#main
socket = 127.0.0.1:7878
workers = 2

Configuration Options +++++++++++++++++++++

socket Required: The TCP socket Pyruvate should bind to. Pyruvate also supports systemd socket activation <https://www.freedesktop.org/software/systemd/man/systemd.socket.html>_ If you specify None as the socket value, Pyruvate will try to acquire a socket bound by systemd.

workers Required: Number of worker threads to use.

async_logging Optional: Log asynchronously using a dedicated thread. Defaults to True.

chunked_transfer Optional: Whether to use chunked transfer encoding if no Content-Length header is present. Defaults to False.

keepalive_timeout Optional: Specify a timeout in integer seconds for keepalive connection. The persistent connection will be closed after the timeout expires. Defaults to 60 seconds.

max_number_headers Optional: Maximum number of request headers that will be parsed. If a request contains more headers than configured, request processing will stop with an error indicating an incomplete request. The default is 32 headers

max_reuse_count Optional: Specify how often to reuse an existing connection. Setting this parameter to 0 will effectively disable keep-alive connections. This is the default.

qmon_warn_threshold Optional: Warning threshold for the number of requests in the request queue. A warning will be logged if the number of queued requests reaches this value. The value must be a positive integer. The default is None which disables the queue monitor.

send_timeout Optional: Time to wait for a client connection to become available for writing after EAGAIN, in seconds. Connections that do not receive data within this time are closed. The value must be a positive integer. The default is 60 seconds.

Logging +++++++

Pyruvate uses the standard Python logging facility <https://docs.python.org/3/library/logging.html>. The logger name is pyruvate. See the Python documentation (logging <https://docs.python.org/3/library/logging.html>, logging.config <https://docs.python.org/3/library/logging.config.html>_) for configuration options.

Example Configurations

Django ++++++

After installing Pyruvate in your Django virtualenv, create or modify your wsgi.py file (one worker listening on 127.0.0.1:8000):

.. code-block:: python

import os
import pyruvate

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_django_application.settings")

application = get_wsgi_application()

pyruvate.serve(application, "127.0.0.1:8000", 1)

You can now start Django + Pyruvate with::

$ python wsgi.py

Override settings by using the DJANGO_SETTINGS_MODULE environment variable when appropriate. Tested with Django 4.1.x, 3.2.x, 2.2.x <https://www.djangoproject.com/>_.

MapProxy ++++++++

First create a basic WSGI configuration following the MapProxy deployment documentation <https://mapproxy.org/docs/latest/deployment.html#server-script>_. Then modify config.py so it is using Pyruvate (2 workers listening on 127.0.0.1:8005):

.. code-block:: python

import os.path
import pyruvate

from mapproxy.wsgiapp import make_wsgi_app
application = make_wsgi_app(r'/path/to/mapproxy/mapproxy.yaml')

pyruvate.serve(application, "127.0.0.1:8005", 2)

Start from your virtualenv::

$ python config.py

Tested with Mapproxy 1.15.x, 1.13.x, 1.12.x <https://mapproxy.org/>_.

Plone +++++

Using pip


After installing Pyruvate in your Plone virtualenv, change the `server` section in your `zope.ini` file (located in `instance/etc` if you are using `mkwsgiinstance` to create the instance)::

    [server:main]
    use = egg:pyruvate#main
    socket = localhost:7878
    workers = 2

Using `zc.buildout`

Using zc.buildout <https://pypi.org/project/zc.buildout/>_ and plone.recipe.zope2instance <https://pypi.org/project/plone.recipe.zope2instance>_ you can define an instance part using Pyruvate's PasteDeploy <https://pastedeploy.readthedocs.io/en/latest/>_ entry point::

[instance]
recipe = plone.recipe.zope2instance
http-address = 127.0.0.1:8080
eggs =
    Plone
    pyruvate
wsgi-ini-template = ${buildout:directory}/templates/pyruvate.ini.in

The server section of the template provided with the wsgi-ini-template <https://pypi.org/project/plone.recipe.zope2instance/#advanced-options>_ option should look like this (3 workers listening on http-address as specified in the buildout [instance] part)::

[server:main]
use = egg:pyruvate#main
socket = %(http_address)s
workers = 3

There is a minimal buildout example configuration for Plone 5.2 in the examples directory <https://gitlab.com/tschorr/pyruvate/-/tree/main/examples/plone52>_ of the package.

Tested with Plone 6.0.x, 5.2.x <https://plone.org/>_.

Pyramid +++++++

Install Pyruvate in your Pyramid virtualenv using pip::

$ pip install pyruvate

Modify the server section in your .ini file to use Pyruvate's PasteDeploy <https://pastedeploy.readthedocs.io/en/latest/>_ entry point (listening on 127.0.0.1:7878 and using 5 workers)::

[server:main]
use = egg:pyruvate#main
socket = 127.0.0.1:7878
workers = 5

Start your application as usual using pserve::

$ pserve path/to/your/configfile.ini

Tested with Pyramid 2.0, 1.10.x <https://trypyramid.com/>_.

Radicale ++++++++

You can find an example configuration for Radicale <https://radicale.org>_ in the examples directory <https://gitlab.com/tschorr/pyruvate/-/tree/main/examples/plone52>_ of the package. Tested with Radicale 3.1.8 <https://radicale.org>_.

Nginx settings ++++++++++++++

Like other WSGI servers Pyruvate should be used behind a reverse proxy, e.g. Nginx::

....
location / {
    proxy_pass http://localhost:7878;
    ...
}
...

Nginx doesn't use keepalive connections by default so you will need to modify your configuration <https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive>_ if you want persistent connections.

Changelog

1.3.0 (2024-07-04)

  • Switch back to rust-cpython (#29 <https://gitlab.com/tschorr/pyruvate/-/issues/29>_)

1.3.0-rc1 (2023-12-28)

  • Replace rust-cpython with PyO3 (#28 <https://gitlab.com/tschorr/pyruvate/-/issues/28>_)
  • Add support for Python 3.12
  • Drop support for Python 3.7

1.2.2 (2023-07-02)

  • Document Unix Domain Socket usage (#27 <https://gitlab.com/tschorr/pyruvate/-/issues/27>_)
  • Provide legacy manylinux wheel names (#26 <https://gitlab.com/tschorr/pyruvate/-/issues/26>_)

1.2.1 (2022-12-22)

  • Track and remove unfinished responses that did not otherwise error (#23 <https://gitlab.com/tschorr/pyruvate/-/issues/23>_)
  • Build musllinux_1_1 wheels (#24 <https://gitlab.com/tschorr/pyruvate/-/issues/24>_)

1.2.0 (2022-10-26)

  • Support Python 3.11 and discontinue Python 3.6, switch to manylinux2014 for building wheels (#19 <https://gitlab.com/tschorr/pyruvate/-/issues/19>_)
  • Add a request queue monitor (#17 <https://gitlab.com/tschorr/pyruvate/-/issues/17>_)
  • Remove blocking worker (#18 <https://gitlab.com/tschorr/pyruvate/-/issues/18>_)
  • Improve parsing of Content-Length header (#20 <https://gitlab.com/tschorr/pyruvate/-/issues/20>_)

1.1.4 (2022-04-19)

  • Fix handling of empty list responses (#14 <https://gitlab.com/tschorr/pyruvate/-/issues/14>_)
  • Support hostnames in socket addresses (#15 <https://gitlab.com/tschorr/pyruvate/-/issues/15>_)

1.1.3 (2022-04-11)

  • Simplify response writing and improve performance (#12 <https://gitlab.com/tschorr/pyruvate/-/issues/12>_)
  • Improve signal handling (#13 <https://gitlab.com/tschorr/pyruvate/-/issues/13>_)

1.1.2 (2022-01-10)

  • Migrate to Rust 2021
  • Use codecov binary uploader
  • Add CONTRIBUTING.rst
  • Fixed: The wrk benchmarking tool could make pyruvate hang when there is no Content-Length header (#11 <https://gitlab.com/tschorr/pyruvate/-/issues/11>_)

1.1.1 (2021-10-12)

  • Support Python 3.10

1.1.0 (2021-09-14)

  • Refactor FileWrapper and improve its performance
  • Increase the default maximum number of headers
  • Add Radicale <https://radicale.org>_ example configuration
  • Update development status

1.0.3 (2021-06-05)

  • HEAD request: Do not complain about content length mismatch (#4 <https://gitlab.com/tschorr/pyruvate/-/issues/4>_)
  • More appropriate log level for client side connection termination (#5 <https://gitlab.com/tschorr/pyruvate/-/issues/5>_)
  • Simplify request parsing

1.0.2 (2021-05-02)

  • Close connection and log an error in the case where the actual content length is less than the Content-Length header provided by the application
  • Fix readme

1.0.1 (2021-04-28)

  • Fix decoding of URLs that contain non-ascii characters
  • Raise Python exception when response contains objects other than bytestrings instead of simply logging the error.

1.0.0 (2021-03-24)

  • Improve query string handling

0.9.2 (2021-01-30)

  • Better support for HTTP 1.1 Expect/Continue
  • Improve documentation

0.9.1 (2021-01-13)

  • Improve GIL handling
  • Propagate worker thread name to Python logging
  • Do not report broken pipe as error
  • PasteDeploy entry point: fix option handling

0.9.0 (2021-01-06)

  • Reusable connections
  • Chunked transfer-encoding
  • Support macOS

0.8.4 (2020-12-12)

  • Lower CPU usage

0.8.3 (2020-11-26)

  • Clean wheel build directories
  • Fix some test isolation problems
  • Remove a println

0.8.2 (2020-11-17)

  • Fix blocksize handling for sendfile case
  • Format unix stream peer address
  • Use latest mio

0.8.1 (2020-11-10)

  • Receiver in non-blocking worker must not block when channel is empty

0.8.0 (2020-11-07)

  • Logging overhaul
  • New async_logging option
  • Some performance improvements
  • Support Python 3.9
  • Switch to manylinux2010 platform tag

0.7.1 (2020-09-16)

  • Raise Python exception when socket is unavailable
  • Add Pyramid configuration example in readme

0.7.0 (2020-08-30)

  • Use Python logging
  • Display server info on startup
  • Fix socket activation for unix domain sockets

0.6.2 (2020-08-12)

  • Improved logging
  • PasteDeploy entry point now also uses at most 24 headers by default

0.6.1 (2020-08-10)

  • Improve request parsing
  • Increase default maximum number of headers to 24

0.6.0 (2020-07-29)

  • Support unix domain sockets
  • Improve sendfile usage

0.5.3 (2020-07-15)

  • Fix testing for completed sendfile call in case of EAGAIN

0.5.2 (2020-07-15)

  • Fix testing for completed response in case of EAGAIN
  • Cargo update

0.5.1 (2020-07-07)

  • Fix handling of read events
  • Fix changelog
  • Cargo update
  • 'Interrupted' error is not a todo
  • Remove unused code

0.5.0 (2020-06-07)

  • Add support for systemd socket activation

0.4.0 (2020-06-29)

  • Add a new worker that does nonblocking write
  • Add default arguments
  • Add option to configure maximum number of request headers
  • Add Via header

0.3.0 (2020-06-16)

  • Switch to rust-cpython
  • Fix passing of tcp connections to worker threads

0.2.0 (2020-03-10)

  • Added some Python tests (using py.test and tox)
  • Improve handling of HTTP headers
  • Respect content length header when using sendfile

0.1.0 (2020-02-10)

  • Initial release

Keywords

FAQs


Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc