pyruvate


Namepyruvate JSON
Version 1.2.2 PyPI version JSON
download
home_pagehttps://gitlab.com/tschorr/pyruvate
SummaryWSGI server implemented in Rust.
upload_time2023-07-02 17:57:13
maintainer
docs_urlNone
authortschorr
requires_python
license
keywords wsgi
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            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.7-3.11).

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.7) `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.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

            

Raw data

            {
    "_id": null,
    "home_page": "https://gitlab.com/tschorr/pyruvate",
    "name": "pyruvate",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "WSGI",
    "author": "tschorr",
    "author_email": "t_schorr@gmx.de",
    "download_url": "https://files.pythonhosted.org/packages/36/7b/1f61bbb94ce211f9b914d4edf2ad3149eac1af5ca1fe4c0a0be6c95439a7/pyruvate-1.2.2.tar.gz",
    "platform": null,
    "description": "Pyruvate WSGI server\n====================\n\n.. image:: https://gitlab.com/tschorr/pyruvate/badges/main/pipeline.svg\n   :target: https://gitlab.com/tschorr/pyruvate\n\n.. image:: https://codecov.io/gl/tschorr/pyruvate/branch/main/graph/badge.svg\n   :target: https://codecov.io/gl/tschorr/pyruvate\n\n.. image:: http://img.shields.io/pypi/v/pyruvate.svg\n   :target: https://pypi.org/project/pyruvate\n\nPyruvate is a fast, multithreaded `WSGI <https://www.python.org/dev/peps/pep-3333>`_ server implemented in `Rust <https://www.rust-lang.org/>`_.\n\nFeatures\n--------\n\n* Non-blocking read/write using `mio <https://github.com/tokio-rs/mio>`_\n* Request parsing using `httparse <https://github.com/seanmonstar/httparse>`_\n* `rust-cpython <https://github.com/dgrunwald/rust-cpython>`_ based Python interface\n* Worker pool based on `threadpool <https://github.com/rust-threadpool/rust-threadpool>`_\n* `PasteDeploy <https://pastedeploy.readthedocs.io/en/latest/>`_ entry point\n\nInstallation\n------------\n\nIf you are on Linux and use a recent Python version,\n\n.. code-block::\n\n    $ pip install pyruvate\n\nis probably all you need to do.\n\nBinary Packages\n+++++++++++++++\n\n`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.7-3.11).\n\nSource Installation\n+++++++++++++++++++\n\nOn 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.\n\nDevelopment Installation\n++++++++++++++++++++++++\n\n* Install `Rust <https://doc.rust-lang.org/book/ch01-01-installation.html>`__\n* Install and activate a Python 3 (>= 3.7) `virtualenv <https://docs.python.org/3/tutorial/venv.html>`_\n* Install `setuptools_rust <https://github.com/PyO3/setuptools-rust>`_ using pip::\n\n    $ pip install setuptools_rust\n\n* Install Pyruvate, e.g. using pip::\n\n    $ pip install -e git+https://gitlab.com/tschorr/pyruvate.git#egg=pyruvate[test]\n\nUsing Pyruvate in your WSGI application\n---------------------------------------\n\nFrom Python using a TCP port\n++++++++++++++++++++++++++++\n\nA hello world WSGI application using Pyruvate listening on 127.0.0.1:7878 and using 2 worker threads looks like this:\n\n.. code-block:: python\n\n    import pyruvate\n\n    def application(environ, start_response):\n        \"\"\"Simplest possible application object\"\"\"\n        status = '200 OK'\n        response_headers = [('Content-type', 'text/plain')]\n        start_response(status, response_headers, None)\n        return [b\"Hello world!\\n\"]\n\n    pyruvate.serve(application, \"127.0.0.1:7878\", 2)\n\nFrom Python using a Unix socket\n+++++++++++++++++++++++++++++++\n\nA hello world WSGI application using Pyruvate listening on unix:/tmp/pyruvate.socket and using 2 worker threads looks like this:\n\n.. code-block:: python\n\n    import pyruvate\n\n    def application(environ, start_response):\n        \"\"\"Simplest possible application object\"\"\"\n        status = '200 OK'\n        response_headers = [('Content-type', 'text/plain')]\n        start_response(status, response_headers, None)\n        return [b\"Hello world!\\n\"]\n\n    pyruvate.serve(application, \"/tmp/pyruvate.socket\", 2)\n\nUsing PasteDeploy\n+++++++++++++++++\n\nAgain listening on 127.0.0.1:7878 and using 2 worker threads::\n\n    [server:main]\n    use = egg:pyruvate#main\n    socket = 127.0.0.1:7878\n    workers = 2\n\nConfiguration Options\n+++++++++++++++++++++\n\nsocket\n    Required: The TCP socket Pyruvate should bind to.\n    `Pyruvate` also supports `systemd socket activation <https://www.freedesktop.org/software/systemd/man/systemd.socket.html>`_\n    If you specify `None` as the socket value, `Pyruvate` will try to acquire a socket bound by `systemd`.\n\nworkers\n    Required: Number of worker threads to use.\n\nasync_logging\n    Optional: Log asynchronously using a dedicated thread.\n    Defaults to `True`.\n\nchunked_transfer\n    Optional: Whether to use chunked transfer encoding if no Content-Length header is present.\n    Defaults to `False`.\n\nkeepalive_timeout\n    Optional: Specify a timeout in integer seconds for keepalive connection.\n    The persistent connection will be closed after the timeout expires.\n    Defaults to 60 seconds.\n\nmax_number_headers\n    Optional: Maximum number of request headers that will be parsed.\n    If a request contains more headers than configured, request processing will stop with an error indicating an incomplete request.\n    The default is 32 headers\n\nmax_reuse_count\n    Optional: Specify how often to reuse an existing connection.\n    Setting this parameter to 0 will effectively disable keep-alive connections.\n    This is the default.\n\nqmon_warn_threshold\n    Optional: Warning threshold for the number of requests in the request queue.\n    A warning will be logged if the number of queued requests reaches this value.\n    The value must be a positive integer.\n    The default is `None` which disables the queue monitor.\n\nsend_timeout\n    Optional: Time to wait for a client connection to become available for\n    writing after EAGAIN, in seconds. Connections that do not receive data\n    within this time are closed.\n    The value must be a positive integer.\n    The default is 60 seconds.\n\nLogging\n+++++++\n\nPyruvate uses the standard `Python logging facility <https://docs.python.org/3/library/logging.html>`_.\nThe logger name is `pyruvate`.\nSee 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.\n\nExample Configurations\n----------------------\n\nDjango\n++++++\n\nAfter installing Pyruvate in your Django virtualenv, create or modify your `wsgi.py` file (one worker listening on 127.0.0.1:8000):\n\n.. code-block:: python\n\n    import os\n    import pyruvate\n\n    from django.core.wsgi import get_wsgi_application\n\n    os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"your_django_application.settings\")\n\n    application = get_wsgi_application()\n\n    pyruvate.serve(application, \"127.0.0.1:8000\", 1)\n\nYou can now start Django + Pyruvate with::\n\n    $ python wsgi.py\n\nOverride settings by using the `DJANGO_SETTINGS_MODULE` environment variable when appropriate.\nTested with `Django 4.1.x, 3.2.x, 2.2.x <https://www.djangoproject.com/>`_.\n\nMapProxy\n++++++++\n\nFirst create a basic WSGI configuration following the `MapProxy deployment documentation <https://mapproxy.org/docs/latest/deployment.html#server-script>`_.\nThen modify `config.py` so it is using Pyruvate (2 workers listening on 127.0.0.1:8005):\n\n.. code-block:: python\n\n    import os.path\n    import pyruvate\n\n    from mapproxy.wsgiapp import make_wsgi_app\n    application = make_wsgi_app(r'/path/to/mapproxy/mapproxy.yaml')\n\n    pyruvate.serve(application, \"127.0.0.1:8005\", 2)\n\nStart from your virtualenv::\n\n    $ python config.py\n\nTested with `Mapproxy 1.15.x, 1.13.x, 1.12.x <https://mapproxy.org/>`_.\n\nPlone\n+++++\n\nUsing `pip`\n~~~~~~~~~~~\n\nAfter 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)::\n\n    [server:main]\n    use = egg:pyruvate#main\n    socket = localhost:7878\n    workers = 2\n\nUsing `zc.buildout`\n~~~~~~~~~~~~~~~~~~~\n\nUsing `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::\n\n    [instance]\n    recipe = plone.recipe.zope2instance\n    http-address = 127.0.0.1:8080\n    eggs =\n        Plone\n        pyruvate\n    wsgi-ini-template = ${buildout:directory}/templates/pyruvate.ini.in\n\nThe `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)::\n\n    [server:main]\n    use = egg:pyruvate#main\n    socket = %(http_address)s\n    workers = 3\n\nThere 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.\n\nTested with `Plone 6.0.x, 5.2.x <https://plone.org/>`_.\n\nPyramid\n+++++++\n\nInstall Pyruvate in your Pyramid virtualenv using pip::\n\n    $ pip install pyruvate\n\nModify 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)::\n\n    [server:main]\n    use = egg:pyruvate#main\n    socket = 127.0.0.1:7878\n    workers = 5\n\nStart your application as usual using `pserve`::\n\n    $ pserve path/to/your/configfile.ini\n\nTested with `Pyramid 2.0, 1.10.x <https://trypyramid.com/>`_.\n\nRadicale\n++++++++\n\nYou 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.\nTested with `Radicale 3.1.8 <https://radicale.org>`_.\n\nNginx settings\n++++++++++++++\n\nLike other WSGI servers Pyruvate should be used behind a reverse proxy, e.g. Nginx::\n\n    ....\n    location / {\n        proxy_pass http://localhost:7878;\n        ...\n    }\n    ...\n\nNginx 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.\n\n\nChangelog\n=========\n\n1.2.2 (2023-07-02)\n------------------\n\n* Document Unix Domain Socket usage (`#27 <https://gitlab.com/tschorr/pyruvate/-/issues/27>`_)\n* Provide legacy manylinux wheel names (`#26 <https://gitlab.com/tschorr/pyruvate/-/issues/26>`_) \n\n1.2.1 (2022-12-22)\n------------------\n\n* Track and remove unfinished responses that did not otherwise error (`#23 <https://gitlab.com/tschorr/pyruvate/-/issues/23>`_)\n* Build musllinux_1_1 wheels (`#24 <https://gitlab.com/tschorr/pyruvate/-/issues/24>`_)\n\n1.2.0 (2022-10-26)\n------------------\n\n* Support Python 3.11 and discontinue Python 3.6, switch to manylinux2014 for building wheels (`#19 <https://gitlab.com/tschorr/pyruvate/-/issues/19>`_)\n* Add a request queue monitor (`#17 <https://gitlab.com/tschorr/pyruvate/-/issues/17>`_)\n* Remove blocking worker (`#18 <https://gitlab.com/tschorr/pyruvate/-/issues/18>`_)\n* Improve parsing of Content-Length header (`#20 <https://gitlab.com/tschorr/pyruvate/-/issues/20>`_)\n\n1.1.4 (2022-04-19)\n------------------\n\n* Fix handling of empty list responses (`#14 <https://gitlab.com/tschorr/pyruvate/-/issues/14>`_)\n* Support hostnames in socket addresses (`#15 <https://gitlab.com/tschorr/pyruvate/-/issues/15>`_)\n\n1.1.3 (2022-04-11)\n------------------\n\n* Simplify response writing and improve performance (`#12 <https://gitlab.com/tschorr/pyruvate/-/issues/12>`_)\n* Improve signal handling (`#13 <https://gitlab.com/tschorr/pyruvate/-/issues/13>`_)\n\n1.1.2 (2022-01-10)\n------------------\n\n* Migrate to Rust 2021\n* Use codecov binary uploader\n* Add CONTRIBUTING.rst\n* Fixed: The wrk benchmarking tool could make pyruvate hang when there is no Content-Length header (`#11 <https://gitlab.com/tschorr/pyruvate/-/issues/11>`_)\n\n1.1.1 (2021-10-12)\n------------------\n\n* Support Python 3.10\n\n1.1.0 (2021-09-14)\n------------------\n\n* Refactor FileWrapper and improve its performance\n* Increase the default maximum number of headers\n* Add `Radicale <https://radicale.org>`_ example configuration\n* Update development status \n\n1.0.3 (2021-06-05)\n------------------\n\n* HEAD request: Do not complain about content length mismatch (`#4 <https://gitlab.com/tschorr/pyruvate/-/issues/4>`_) \n* More appropriate log level for client side connection termination (`#5 <https://gitlab.com/tschorr/pyruvate/-/issues/5>`_)\n* Simplify request parsing\n\n1.0.2 (2021-05-02)\n------------------\n\n* Close connection and log an error in the case where the actual content length is\n  less than the Content-Length header provided by the application\n* Fix readme\n\n1.0.1 (2021-04-28)\n------------------\n\n* Fix decoding of URLs that contain non-ascii characters\n* Raise Python exception when response contains objects other than bytestrings\n  instead of simply logging the error.\n\n1.0.0 (2021-03-24)\n------------------\n\n* Improve query string handling\n\n0.9.2 (2021-01-30)\n------------------\n\n* Better support for HTTP 1.1 Expect/Continue\n* Improve documentation\n\n0.9.1 (2021-01-13)\n------------------\n\n* Improve GIL handling\n* Propagate worker thread name to Python logging\n* Do not report broken pipe as error\n* PasteDeploy entry point: fix option handling\n\n0.9.0 (2021-01-06)\n------------------\n\n* Reusable connections\n* Chunked transfer-encoding\n* Support macOS\n\n0.8.4 (2020-12-12)\n------------------\n\n* Lower CPU usage\n\n0.8.3 (2020-11-26)\n------------------\n\n* Clean wheel build directories\n* Fix some test isolation problems\n* Remove a println\n\n0.8.2 (2020-11-17)\n------------------\n\n* Fix blocksize handling for sendfile case\n* Format unix stream peer address\n* Use latest mio\n\n0.8.1 (2020-11-10)\n------------------\n\n* Receiver in non-blocking worker must not block when channel is empty\n\n0.8.0 (2020-11-07)\n------------------\n\n* Logging overhaul\n* New async_logging option\n* Some performance improvements\n* Support Python 3.9\n* Switch to manylinux2010 platform tag\n\n0.7.1 (2020-09-16)\n------------------\n\n* Raise Python exception when socket is unavailable\n* Add Pyramid configuration example in readme\n\n0.7.0 (2020-08-30)\n------------------\n\n* Use Python logging\n* Display server info on startup\n* Fix socket activation for unix domain sockets\n\n0.6.2 (2020-08-12)\n------------------\n\n* Improved logging\n* PasteDeploy entry point now also uses at most 24 headers by default\n\n0.6.1 (2020-08-10)\n------------------\n\n* Improve request parsing\n* Increase default maximum number of headers to 24\n\n0.6.0 (2020-07-29)\n------------------\n\n* Support unix domain sockets\n* Improve sendfile usage\n\n0.5.3 (2020-07-15)\n------------------\n\n* Fix testing for completed sendfile call in case of EAGAIN\n\n0.5.2 (2020-07-15)\n------------------\n\n* Fix testing for completed response in case of EAGAIN\n* Cargo update\n\n0.5.1 (2020-07-07)\n------------------\n\n* Fix handling of read events\n* Fix changelog\n* Cargo update\n* 'Interrupted' error is not a todo\n* Remove unused code\n\n0.5.0 (2020-06-07)\n------------------\n\n* Add support for systemd socket activation\n\n0.4.0 (2020-06-29)\n------------------\n\n* Add a new worker that does nonblocking write\n* Add default arguments\n* Add option to configure maximum number of request headers\n* Add Via header\n\n0.3.0 (2020-06-16)\n------------------\n\n* Switch to rust-cpython\n* Fix passing of tcp connections to worker threads\n\n0.2.0 (2020-03-10)\n------------------\n\n* Added some Python tests (using py.test and tox)\n* Improve handling of HTTP headers\n* Respect content length header when using sendfile\n\n0.1.0 (2020-02-10)\n------------------\n\n* Initial release\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "WSGI server implemented in Rust.",
    "version": "1.2.2",
    "project_urls": {
        "Homepage": "https://gitlab.com/tschorr/pyruvate"
    },
    "split_keywords": [
        "wsgi"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ad4cd3f5db26906f343b07a82de3f06a77a0469b21d5dbf85a355dcac21db0ce",
                "md5": "517009002bb968d2bcf249fbbe35b0ea",
                "sha256": "aa0892a6ac51680036ed5cfff0ef0bc29a1460dcdc4be76e8270e72f7c686b61"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "517009002bb968d2bcf249fbbe35b0ea",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": null,
            "size": 1322309,
            "upload_time": "2023-07-02T17:56:20",
            "upload_time_iso_8601": "2023-07-02T17:56:20.570666Z",
            "url": "https://files.pythonhosted.org/packages/ad/4c/d3f5db26906f343b07a82de3f06a77a0469b21d5dbf85a355dcac21db0ce/pyruvate-1.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1f5cc33cfd2b0a64bc9dec542e96c271fb83883bcccf73f7b4824eb3141865e9",
                "md5": "7e8ebb02cd44609942ee65215f5e4778",
                "sha256": "e17e5e947981385088730605ebb27dc46413b057312e34f6fb2a5a99bab37c96"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl",
            "has_sig": false,
            "md5_digest": "7e8ebb02cd44609942ee65215f5e4778",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": null,
            "size": 1314895,
            "upload_time": "2023-07-02T17:56:25",
            "upload_time_iso_8601": "2023-07-02T17:56:25.920304Z",
            "url": "https://files.pythonhosted.org/packages/1f/5c/c33cfd2b0a64bc9dec542e96c271fb83883bcccf73f7b4824eb3141865e9/pyruvate-1.2.2-cp310-cp310-musllinux_1_1_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "86cdf6bfd0039b52ccf486e2d5d7b814d29d234cfa327cd5618c35c86463a116",
                "md5": "15e08f68073688fb7c8ec8f97b2f0515",
                "sha256": "2644333fc8fc9eaddbaefcd4eaca3c12d866c64d77be9c1617b0859a0ea68aa6"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "15e08f68073688fb7c8ec8f97b2f0515",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": null,
            "size": 1322309,
            "upload_time": "2023-07-02T17:56:32",
            "upload_time_iso_8601": "2023-07-02T17:56:32.940866Z",
            "url": "https://files.pythonhosted.org/packages/86/cd/f6bfd0039b52ccf486e2d5d7b814d29d234cfa327cd5618c35c86463a116/pyruvate-1.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "72855dae28e98ff48ef41e44c8a09c5450e06aaf91d18ff05994ddaed2e5e4b4",
                "md5": "69d7bc1f70e802da5eded9196201c8d8",
                "sha256": "8af2eb19c851d7484814e6eab2f6d6d98a9256a236208c43c1da9bddb3036ba6"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl",
            "has_sig": false,
            "md5_digest": "69d7bc1f70e802da5eded9196201c8d8",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": null,
            "size": 1314897,
            "upload_time": "2023-07-02T17:56:37",
            "upload_time_iso_8601": "2023-07-02T17:56:37.525783Z",
            "url": "https://files.pythonhosted.org/packages/72/85/5dae28e98ff48ef41e44c8a09c5450e06aaf91d18ff05994ddaed2e5e4b4/pyruvate-1.2.2-cp311-cp311-musllinux_1_1_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "527314ca181dbd4b40886bae7b8bb357f12aba900480710c18965fd97b95f5db",
                "md5": "642e941bd93e20da8c395465c3b5243e",
                "sha256": "e1c42de49156bc2608ab6f8ccab01cd2188891f02be031af14d81732e409fbbe"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "642e941bd93e20da8c395465c3b5243e",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": null,
            "size": 1322207,
            "upload_time": "2023-07-02T17:56:44",
            "upload_time_iso_8601": "2023-07-02T17:56:44.300707Z",
            "url": "https://files.pythonhosted.org/packages/52/73/14ca181dbd4b40886bae7b8bb357f12aba900480710c18965fd97b95f5db/pyruvate-1.2.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "90d935b51c8232b9be59e5bb33e8e49d93813a25a025e72edfb0c22ea97eb78e",
                "md5": "4831a2950138a7e3362c81f70649317d",
                "sha256": "bde8bde487b5206210d265d7e82e153615aeb1ed2e2672dc349121b40198c5f1"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl",
            "has_sig": false,
            "md5_digest": "4831a2950138a7e3362c81f70649317d",
            "packagetype": "bdist_wheel",
            "python_version": "cp37",
            "requires_python": null,
            "size": 1315282,
            "upload_time": "2023-07-02T17:56:49",
            "upload_time_iso_8601": "2023-07-02T17:56:49.451002Z",
            "url": "https://files.pythonhosted.org/packages/90/d9/35b51c8232b9be59e5bb33e8e49d93813a25a025e72edfb0c22ea97eb78e/pyruvate-1.2.2-cp37-cp37m-musllinux_1_1_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "cb61c6dea9a950f7f4414d4a8d0b4a12ed3e876e25eed9d1331f7db05ec488fa",
                "md5": "6663a5c000bad922bff6806b93dfb43e",
                "sha256": "721438a9a45bd2cb3d90b00132154f87229a2287e8b3ac35928aa5b425e0e767"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "6663a5c000bad922bff6806b93dfb43e",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": null,
            "size": 1322119,
            "upload_time": "2023-07-02T17:56:54",
            "upload_time_iso_8601": "2023-07-02T17:56:54.075021Z",
            "url": "https://files.pythonhosted.org/packages/cb/61/c6dea9a950f7f4414d4a8d0b4a12ed3e876e25eed9d1331f7db05ec488fa/pyruvate-1.2.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "62f94162bbaaed2625abaf86dea7a790510e1335d05a7e7b9fe5760d99e4a63c",
                "md5": "e3b04c509bfbfd620bc3508ed9e244de",
                "sha256": "b8d2832e75ce29174608cd8fedeacdfdefaa216e3dc3f77f1e8b791145ff1f37"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp38-cp38-musllinux_1_1_x86_64.whl",
            "has_sig": false,
            "md5_digest": "e3b04c509bfbfd620bc3508ed9e244de",
            "packagetype": "bdist_wheel",
            "python_version": "cp38",
            "requires_python": null,
            "size": 1314935,
            "upload_time": "2023-07-02T17:56:59",
            "upload_time_iso_8601": "2023-07-02T17:56:59.332660Z",
            "url": "https://files.pythonhosted.org/packages/62/f9/4162bbaaed2625abaf86dea7a790510e1335d05a7e7b9fe5760d99e4a63c/pyruvate-1.2.2-cp38-cp38-musllinux_1_1_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2c2f39392db440898e5906b1ab3b1717f64ab8743d6898480d0d36135ced9a9d",
                "md5": "aaed6aea28aee1233422e9259d1adf36",
                "sha256": "fd10f1718989063cadce40e91d1a721dc49a2bb5fa84e4a9f60bea895dc043cd"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "has_sig": false,
            "md5_digest": "aaed6aea28aee1233422e9259d1adf36",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": null,
            "size": 1322229,
            "upload_time": "2023-07-02T17:57:06",
            "upload_time_iso_8601": "2023-07-02T17:57:06.215049Z",
            "url": "https://files.pythonhosted.org/packages/2c/2f/39392db440898e5906b1ab3b1717f64ab8743d6898480d0d36135ced9a9d/pyruvate-1.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2abc12ce329d9c431bdb902bcb43cafd7e19757217c3be580099febb8f1371ee",
                "md5": "1f7fcf38e995d0fbf6f1fb71314b0767",
                "sha256": "a2c8bd7bf14765f3a3f37c5da7a17983340a2315376a12564f2826dfa07f8f8c"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2-cp39-cp39-musllinux_1_1_x86_64.whl",
            "has_sig": false,
            "md5_digest": "1f7fcf38e995d0fbf6f1fb71314b0767",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": null,
            "size": 1314930,
            "upload_time": "2023-07-02T17:57:11",
            "upload_time_iso_8601": "2023-07-02T17:57:11.526202Z",
            "url": "https://files.pythonhosted.org/packages/2a/bc/12ce329d9c431bdb902bcb43cafd7e19757217c3be580099febb8f1371ee/pyruvate-1.2.2-cp39-cp39-musllinux_1_1_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "367b1f61bbb94ce211f9b914d4edf2ad3149eac1af5ca1fe4c0a0be6c95439a7",
                "md5": "b7f33ee7a08f26de649147dae39a2468",
                "sha256": "2740901764fe9f3aaa252c4fcc8efc591a8196929d1a91a39b0ad48d75e56bcd"
            },
            "downloads": -1,
            "filename": "pyruvate-1.2.2.tar.gz",
            "has_sig": false,
            "md5_digest": "b7f33ee7a08f26de649147dae39a2468",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 60614,
            "upload_time": "2023-07-02T17:57:13",
            "upload_time_iso_8601": "2023-07-02T17:57:13.740974Z",
            "url": "https://files.pythonhosted.org/packages/36/7b/1f61bbb94ce211f9b914d4edf2ad3149eac1af5ca1fe4c0a0be6c95439a7/pyruvate-1.2.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-07-02 17:57:13",
    "github": false,
    "gitlab": true,
    "bitbucket": false,
    "codeberg": false,
    "gitlab_user": "tschorr",
    "gitlab_project": "pyruvate",
    "lcname": "pyruvate"
}
        
Elapsed time: 0.17122s