pyruvate


Namepyruvate JSON
Version 1.5.0 PyPI version JSON
download
home_pageNone
SummaryWSGI server implemented in Rust.
upload_time2025-07-24 11:25:25
maintainerNone
docs_urlNone
authortschorr <t_schorr@gmx.de>
requires_python>=3.9
licenseNone
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/>`_.
It is implementing a pre-fork worker model, making it a good choice for applications that are not completely thread safe or maintain per thread objects that are expensive to create (e.g. pooled database connections).

Features
--------

* Non-blocking read/write using `mio <https://github.com/tokio-rs/mio>`_
* Request parsing using `httparse <https://github.com/seanmonstar/httparse>`_
* `pyo3-ffi <https://github.com/pyo3/pyo3>`_ 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_28 <https://peps.python.org/pep-0600/>`_ and `musllinux_1_2 <https://peps.python.org/pep-0656/>`_ wheels are available for the `x86_64` architecture and active Python 3 versions (currently 3.9-3.13).

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.
Then you will need to switch to Rust Nightly::

    $ rustup install nightly
    $ rustup default nightly

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

* Install `Rust <https://doc.rust-lang.org/book/ch01-01-installation.html>`__
* Install Rust Nightly Toolchain and make it the default::

    $ rustup install nightly
    $ rustup default nightly

* Install and activate a Python 3 (>= 3.9) `virtualenv <https://docs.python.org/3/tutorial/venv.html>`_
* Install `maturin <https://www.maturin.rs/>`_ using pip::

    $ pip install maturin

* Clone Pyruvate with git and cd into your copy::

    $ git clone https://gitlab.com/tschorr/pyruvate.git
    $ cd pyruvate

* Install Pyruvate as editable::

    $ maturin develop

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.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.5.0 <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.


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pyruvate",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "WSGI",
    "author": "tschorr <t_schorr@gmx.de>",
    "author_email": "Thomas Schorr <t_schorr@gmx.de>",
    "download_url": "https://files.pythonhosted.org/packages/70/b7/41ac98a5f7cad76bd9cb90c5ce975a75ba3fa0348c4436db2a5ba4f26c03/pyruvate-1.5.0.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/>`_.\nIt is implementing a pre-fork worker model, making it a good choice for applications that are not completely thread safe or maintain per thread objects that are expensive to create (e.g. pooled database connections).\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* `pyo3-ffi <https://github.com/pyo3/pyo3>`_ 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_28 <https://peps.python.org/pep-0600/>`_ and `musllinux_1_2 <https://peps.python.org/pep-0656/>`_ wheels are available for the `x86_64` architecture and active Python 3 versions (currently 3.9-3.13).\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.\nThen you will need to switch to Rust Nightly::\n\n    $ rustup install nightly\n    $ rustup default nightly\n\nDevelopment Installation\n++++++++++++++++++++++++\n\n* Install `Rust <https://doc.rust-lang.org/book/ch01-01-installation.html>`__\n* Install Rust Nightly Toolchain and make it the default::\n\n    $ rustup install nightly\n    $ rustup default nightly\n\n* Install and activate a Python 3 (>= 3.9) `virtualenv <https://docs.python.org/3/tutorial/venv.html>`_\n* Install `maturin <https://www.maturin.rs/>`_ using pip::\n\n    $ pip install maturin\n\n* Clone Pyruvate with git and cd into your copy::\n\n    $ git clone https://gitlab.com/tschorr/pyruvate.git\n    $ cd pyruvate\n\n* Install Pyruvate as editable::\n\n    $ maturin develop\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.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.5.0 <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",
    "bugtrack_url": null,
    "license": null,
    "summary": "WSGI server implemented in Rust.",
    "version": "1.5.0",
    "project_urls": {
        "Changelog": "https://gitlab.com/tschorr/pyruvate/-/blob/main/CHANGES.rst?ref_type=heads",
        "Issues": "https://gitlab.com/tschorr/pyruvate/-/issues",
        "Repository": "https://gitlab.com/tschorr/pyruvate"
    },
    "split_keywords": [
        "wsgi"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1a23218f4272abdb8730474b2c38dcef6dd841975f27e4bc6084b7e50aa9b22e",
                "md5": "e8bf3cf8d28b6d718ce92fbb178c987f",
                "sha256": "b73beda05a1646ed3845db4aaacebc19a98a24b0fed2194a7578de61fd023193"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp310-cp310-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "e8bf3cf8d28b6d718ce92fbb178c987f",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.9",
            "size": 554865,
            "upload_time": "2025-07-24T11:24:55",
            "upload_time_iso_8601": "2025-07-24T11:24:55.897590Z",
            "url": "https://files.pythonhosted.org/packages/1a/23/218f4272abdb8730474b2c38dcef6dd841975f27e4bc6084b7e50aa9b22e/pyruvate-1.5.0-cp310-cp310-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2509d0cdca6be0b3a0857a08183b671fc312e908b8ba2d058c954934bd7daab4",
                "md5": "c6f260a75813ea145443fb3a2e282738",
                "sha256": "ab537615f9a80198121a5702d5fb40aa09f3c9f9fa91c4fed5e43d2b1e5b7e61"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl",
            "has_sig": false,
            "md5_digest": "c6f260a75813ea145443fb3a2e282738",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.9",
            "size": 5590925,
            "upload_time": "2025-07-24T11:24:58",
            "upload_time_iso_8601": "2025-07-24T11:24:58.868252Z",
            "url": "https://files.pythonhosted.org/packages/25/09/d0cdca6be0b3a0857a08183b671fc312e908b8ba2d058c954934bd7daab4/pyruvate-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5bab5d40bdf2f84fe16a0cd24f64597979e3a1992ce9a47ee230fe45d851e8b4",
                "md5": "f69edbe27d6f8042fba348843394773a",
                "sha256": "24b755008779c0cde80fe323cdbf99ecfdd85a6a99f21da54c9bf09b1b370502"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp311-cp311-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "f69edbe27d6f8042fba348843394773a",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.9",
            "size": 554238,
            "upload_time": "2025-07-24T11:25:01",
            "upload_time_iso_8601": "2025-07-24T11:25:01.081175Z",
            "url": "https://files.pythonhosted.org/packages/5b/ab/5d40bdf2f84fe16a0cd24f64597979e3a1992ce9a47ee230fe45d851e8b4/pyruvate-1.5.0-cp311-cp311-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "715fcc248bde62ff89d4714643d74b40bac7b1637fd2957b30ba0641f0237655",
                "md5": "a2566d15f449ca9f23bf3236468b41d2",
                "sha256": "f978b44a86d2df3cf47fc82686f75942bb40c096c07ad15095d24de6f0103db9"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl",
            "has_sig": false,
            "md5_digest": "a2566d15f449ca9f23bf3236468b41d2",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.9",
            "size": 5589783,
            "upload_time": "2025-07-24T11:25:03",
            "upload_time_iso_8601": "2025-07-24T11:25:03.922874Z",
            "url": "https://files.pythonhosted.org/packages/71/5f/cc248bde62ff89d4714643d74b40bac7b1637fd2957b30ba0641f0237655/pyruvate-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fc7d879279d4a07e3ad76a401b12014c855b78359bb6082c4fc583e18ab58576",
                "md5": "da8f29c821a629010e7b9a695137f6ce",
                "sha256": "490fcd5084ce3340f9ae63e25064fff6fe45622fc958f87111b0e9f404fd9ecc"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp312-cp312-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "da8f29c821a629010e7b9a695137f6ce",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.9",
            "size": 557047,
            "upload_time": "2025-07-24T11:25:05",
            "upload_time_iso_8601": "2025-07-24T11:25:05.869782Z",
            "url": "https://files.pythonhosted.org/packages/fc/7d/879279d4a07e3ad76a401b12014c855b78359bb6082c4fc583e18ab58576/pyruvate-1.5.0-cp312-cp312-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "173f12b0d2b7825bbdf2daf16fa84ab2f4d90427244e14ebf69d5e01ab13ed1d",
                "md5": "82bcc9259f1dc5b2d0415982df9095f5",
                "sha256": "71b8b6368923c88f807a2af4fee09e2f99abc36e217afd169af32c7a9c885518"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl",
            "has_sig": false,
            "md5_digest": "82bcc9259f1dc5b2d0415982df9095f5",
            "packagetype": "bdist_wheel",
            "python_version": "cp312",
            "requires_python": ">=3.9",
            "size": 5579883,
            "upload_time": "2025-07-24T11:25:08",
            "upload_time_iso_8601": "2025-07-24T11:25:08.248370Z",
            "url": "https://files.pythonhosted.org/packages/17/3f/12b0d2b7825bbdf2daf16fa84ab2f4d90427244e14ebf69d5e01ab13ed1d/pyruvate-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "25884cec3d118db4711265e16152aa6c668a67d4f584364dac090eeebeb7e707",
                "md5": "8cdc27d50ebf5b4e1b36b102e71c24d9",
                "sha256": "2d9cdca0c99599fd8a9548906c16e2b5725dd660f94a779c808040ed106c3e66"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp313-cp313-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "8cdc27d50ebf5b4e1b36b102e71c24d9",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": ">=3.9",
            "size": 556506,
            "upload_time": "2025-07-24T11:25:10",
            "upload_time_iso_8601": "2025-07-24T11:25:10.225820Z",
            "url": "https://files.pythonhosted.org/packages/25/88/4cec3d118db4711265e16152aa6c668a67d4f584364dac090eeebeb7e707/pyruvate-1.5.0-cp313-cp313-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "607890f65a3b54553012bf4aecf5dbb80f1d2b311aa1dab0103bfd948c94722c",
                "md5": "edc265384bd73522dcfde693cdcf5743",
                "sha256": "6b369b28e0b5753155494e9d44034f604da507b445ab705c1b8a38bf7c944cb2"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl",
            "has_sig": false,
            "md5_digest": "edc265384bd73522dcfde693cdcf5743",
            "packagetype": "bdist_wheel",
            "python_version": "cp313",
            "requires_python": ">=3.9",
            "size": 5577646,
            "upload_time": "2025-07-24T11:25:12",
            "upload_time_iso_8601": "2025-07-24T11:25:12.582181Z",
            "url": "https://files.pythonhosted.org/packages/60/78/90f65a3b54553012bf4aecf5dbb80f1d2b311aa1dab0103bfd948c94722c/pyruvate-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "370e05e59cc97bb22e3481cca045d3905de9795b865d3d1527a071321db33d1b",
                "md5": "1f8a640f08add0d854901e59602c669b",
                "sha256": "591fc3d045a31ea122283e0f9345aa93869eda6cedc117dd30126e9a8cbbd469"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp39-cp39-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "1f8a640f08add0d854901e59602c669b",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.9",
            "size": 556046,
            "upload_time": "2025-07-24T11:25:14",
            "upload_time_iso_8601": "2025-07-24T11:25:14.064300Z",
            "url": "https://files.pythonhosted.org/packages/37/0e/05e59cc97bb22e3481cca045d3905de9795b865d3d1527a071321db33d1b/pyruvate-1.5.0-cp39-cp39-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "82f7c08c0935e0c7e9f41994dab874d36bb5a31213dd45f96d6e5e677be740ba",
                "md5": "785d5b37183a131bd1b5a23f7b1f40c5",
                "sha256": "ed05e6f25c40d1534e1b6559dd3f11fc9e297f77f464a3048bbbce92e1bcc3c3"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl",
            "has_sig": false,
            "md5_digest": "785d5b37183a131bd1b5a23f7b1f40c5",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.9",
            "size": 5593495,
            "upload_time": "2025-07-24T11:25:16",
            "upload_time_iso_8601": "2025-07-24T11:25:16.423512Z",
            "url": "https://files.pythonhosted.org/packages/82/f7/c08c0935e0c7e9f41994dab874d36bb5a31213dd45f96d6e5e677be740ba/pyruvate-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "70b741ac98a5f7cad76bd9cb90c5ce975a75ba3fa0348c4436db2a5ba4f26c03",
                "md5": "aa29c0e08544752c26b0b16f4e2ea306",
                "sha256": "35c0c05f01a478f2626f9b98ba9b67e63e26d2949a7f0e7906f8ea09e58e2f75"
            },
            "downloads": -1,
            "filename": "pyruvate-1.5.0.tar.gz",
            "has_sig": false,
            "md5_digest": "aa29c0e08544752c26b0b16f4e2ea306",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 38325840,
            "upload_time": "2025-07-24T11:25:25",
            "upload_time_iso_8601": "2025-07-24T11:25:25.563517Z",
            "url": "https://files.pythonhosted.org/packages/70/b7/41ac98a5f7cad76bd9cb90c5ce975a75ba3fa0348c4436db2a5ba4f26c03/pyruvate-1.5.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-24 11:25:25",
    "github": false,
    "gitlab": true,
    "bitbucket": false,
    "codeberg": false,
    "gitlab_user": "tschorr",
    "gitlab_project": "pyruvate",
    "lcname": "pyruvate"
}
        
Elapsed time: 0.53457s