Skip to main content
Negotiator
==========

Proper Content Negotiation for Python

Introduction
------------

Negotiator offers a framework for making content negotiation decisions based on the HTTP accept headers.

NOTE it currently only formally supports Accept and Accept-Language, but it is a short haul to support for Accept-Charset and Accept-Encoding (TODO)


Basic Usage
-----------

Import all the objects from the negotiator module

>>> from negotiator import ContentNegotiator, AcceptParameters, ContentType, Language

Specify the default parameters. These are the parameters which will be used in place of any HTTP Accept headers which are not present in the negotiation request. For example, if the Accept-Language header is not passed to the negotiator it will assume that the client request is for "en"

>>> default_params = AcceptParameters(ContentType("text/html"), Language("en"))

Specify the list of acceptable formats that the server supports

>>> acceptable = [AcceptParameters(ContentType("text/html"), Language("en"))]
>>> acceptable.append(AcceptParameters(ContentType("text/json"), Language("en")))

Create an instance of the negotiator, ready to accept negotiation requests

>>> cn = ContentNegotiator(default_params, acceptable)

A simple negotiate on the HTTP Accept header "text/json;q=1.0, text/html;q=0.9", asking for json, and if not json then html

>>> acceptable = cn.negotiate(accept="text/json;q=1.0, text/html;q=0.9")

The negotiator indicates that the best match the server can give to the client's request is text/json in english

>>> acceptable
AcceptParameters:: Content Type: text/json;Language: en;


Advanced Usage
--------------

Import all the objects from the negotiator module

>>> from negotiator import ContentNegotiator, AcceptParameters, ContentType, Language

Specify the default parameters. These are the parameters which will be used in place of any HTTP Accept headers which are not present in the negotiation request. For example, if the Accept-Language header is not passed to the negotiator it will assume that the client request is for "en"

>>> default_params = AcceptParameters(ContentType("text/html"), Language("en"))

Specify the list of acceptable formats that the server supports. For this advanced example we specify html, json and pdf in a variety of languages

>>> acceptable = [AcceptParameters(ContentType("text/html"), Language("en"))]
>>> acceptable.append(AcceptParameters(ContentType("text/html"), Language("fr")))
>>> acceptable.append(AcceptParameters(ContentType("text/html"), Language("de")))
>>> acceptable.append(AcceptParameters(ContentType("text/json"), Language("en")))
>>> acceptable.append(AcceptParameters(ContentType("text/json"), Language("cz")))
>>> acceptable.append(AcceptParameters(ContentType("application/pdf"), Language("de")))

specify the weighting that the negotiator should apply to the different Accept headers. A higher weighting towards content type will prefer content type variations over language variations (e.g. if there are two formats which are equally acceptable to the client, in different languages, a content_type weight higher than a language weight will return the parameters according to the server's preferred content type.

>>> weights = {"content_type" : 1.0, "language" : 0.5}

Create an instance of the negotiator, ready to accept negotiation requests

>>> cn = ContentNegotiator(default_params, acceptable, weights)

set up some more complex accept headers (you can try modifying the order of the elements without q values, and the q values themselves, to see different results).

>>> accept = "text/html, text/json;q=1.0, application/pdf;q=0.5"
>>> accept_language = "en;q=0.5, de, cz, fr"

negotiate over both headers, looking for an optimal solution to the client request

>>> acceptable = cn.negotiate(accept, accept_language)

The negotiator indicates the best fit to the client request is text/html in German

>>> acceptable
AcceptParameters:: Content Type: text/html;Language: de;


Preference Ordering Rules
-------------------------

The Negotiator organises the preferences in each accept header into a sequence,
from highest q value to lowest, grouping together equal q values.

For example, the HTTP Accept header:

"text/html, text/json;q=1.0, application/pdf;q=0.5"

Would result in the following preference sequence (as a python dictionary):

{
1.0 : ["text/json", "text/html"],
0.5 : ["application/pdf"]
}

While the HTTP Accept-Language header:

"en;q=0.5, de, cz, fr"

Would result in the following preference sequence (as a python dictionary):

{
1.0 : ["de"],
0.8 : ["cz"],
0.6 : ["fr"],
0.5 : ["en"]
}

(In reality, the q values for de, cz and fr would be evenly spaced between 1.0 and 0.5, using floating point numbers as the keys)


Combined Preference Ordering Rules
----------------------------------

The negotiator will compute all the possible allowed combinations and their weighted overall q values.

Given that the server supports the following combinations (from the code example above):

text/html, en
text/html, fr
text/html, de
text/json, en
text/json, cz
application/pdf, de

And given the weights:

w = {"content_type" : 1.0, "language" : 0.5}

We can calculate the combined q value of each allowed (by both server and client) option, using the equation:

overall_q = w["content_type"] * content_type_q + w["language"] * language_q

So, for the above options and q values from the previous section, we can generate the preference list (as a python dictionary):

{
1.5 : ["text/html, de"],
1.4 : ["text/json, cz"],
1.3 : ["text/html, fr"],
1.25 : ["text/html, en", "text/json, en"]
1.0 : ["application/pdf, de"]
}

It is clear, then, why the negotiator in the Advanced Usage section selected "text/html, de" as its preferred format.

Metadata

Release files for negotiator-3k 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for negotiator-3k 1.0.0
File Interpreter ABI Platform
negotiator-3k-1.0.0.tar.gz Details

Release files / negotiator-3k-1.0.0.tar.gz

Download URL negotiator-3k-1.0.0.tar.gz
Size 11.4 kB
Tags Source
SHA-256 checksum
How to use checksums
911c9699ee5911de38a255c91870fdf6a66175558686a9e348f5d9f9bf994621
BLAKE2b-256 checksum
How to use checksums
6cec20b4553cf6652877ad5a4452c2567fb3320c58d31254c2ee39ec2c34438c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Security for negotiator-3k 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

1.0.0 This release

1 release file No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page