python urllib: build urls including parameters with and without keyword

Viewed 735

I am building grafana links in python with urllib like the following:

from urllib.parse import urlencode, urlunsplit

parameters = {
    "parameter1":"value1",
    "parameter2":"value2"
}

query = urlencode(
    query = parameters,
    doseq = True
)

link = urlunsplit((
    "https",
    "my_grafana.com",
    "/graph",
    query,
    ""
))

link will be in this case 'https://my_grafana.com/graph?parameter1=value1&parameter2=value2'. I now want to add parameters with no keyword for example "kiosk". The link should look like 'https://my_grafana.com/graph?parameter1=value1&parameter2=value2&kiosk&other_parameter'

As urlencode returns a string with the parameters I could manipulate the string like in the following example before I give it to urlunsplit:

no_keyword_parameters = ["kiosk","other_parameter"]
query = "&".join([query, *no_keyword_parameters])

I wonder if you can put parameters with and without keyword directly with urlencode together. I tried giving "kiosk" as a dictionary entry with None as content ({"kiosk": None}) but it includes the None in the url. Approaches, where I give a list of tuples instead of a dictionary for the parameters, were also unsuccessful.

Thank you for any help.

2 Answers

As mentioned by Ondrej, urlencode builds the query using k + '=' + v.
You could add non value parameters manually:

from urllib.parse import urlencode, urlunsplit, quote_plus

parameters = {"parameter1": "value1", "parameter2": "value2"}
no_value_parameters = ["kiosk", "other_parameter"]
no_value_parameters_quoted = [quote_plus(p) for p in no_value_parameters]

query = urlencode(query=parameters, doseq=True)
link = urlunsplit(("https", "my_grafana.com", "/graph", query, ""))
link = f"{link}&{'&'.join(no_value_parameters_quoted)}"
print(link)

Out:

https://my_grafana.com/graph?parameter1=value1&parameter2=value2&kiosk&other_parameter

What you've done seems sound and you could either do it like that or formalize it a bit more in your own encoding function, but urllib.parse.urlencode does not seem to understand the notion of parameters without value. If you look at the implementation (with doseq you get a variation of the same for the part relevant to your question):

        for k, v in query:
...
           l.append(k + '=' + v)

I.e. you have to have a key, value pair (to unpack two values) and whatever they are quoted to (that happens in the ellipses) will be a str joined over =. So even using custom qoute_via you cannot really change its function.

That linked implementation is the one provided with CPython, but also the documentation expects: key/value pairs, so that behavior really is as specified / documented:

The resulting string is a series of key=value pairs separated by '&' characters...

Related