[Python-Dev] Should urlencode() sort the query parameters (if they come from a dict)?

MRAB python at mrabarnett.plus.com
Sat Aug 18 20:47:57 CEST 2012


On 18/08/2012 18:34, Guido van Rossum wrote:
> On Sat, Aug 18, 2012 at 6:28 AM, Christian Heimes <lists at cheimes.de> wrote:
>> Am 17.08.2012 21:27, schrieb Guido van Rossum:
>>> I wonder if it wouldn't make sense to change urlencode() to generate
>>> URLs that don't depend on the hash order, for all versions of Python
>>> that support PYTHONHASHSEED? It seems a one-line fix:
>>>
>>>         query = query.items()
>>>
>>> with this:
>>>
>>>         query = sorted(query.items())
>>>
>>> This would not prevent breakage of unit tests, but it would make a
>>> much simpler fix possible: simply sort the parameters in the URL.
>>
>> I vote -0. The issue can also be addressed with a small and simple
>> helper function that wraps urlparse and compares the query parameter. Or
>> you cann urlencode() with `sorted(qs.items)` instead of `qs` in the
>> application.
>
> Hm. That's actually a good point.
>
>> The order of query string parameter is actually important for some
>> applications, for example Zope, colander+deform and other form
>> frameworks use the parameter order to group parameters.
>>
>> Therefore I propose that the query string is only sorted when the query
>> is exactly a dict and not some subclass or class that has an items() method.
>>
>>     if type(query) is dict:
>>         query = sorted(query.items())
>>     else:
>>         query = query.items()
>
> That's already in the bug I filed. :-) I also added that the sort may
> fail if the keys mix e.g. bytes and str (or int and str, for that
> matter).
>
One possible way around that is to add the class names, perhaps only if
sorting raises an exception:

def make_key(pair):
     return type(pair[0]).__name__, type(pair[1]).__name__, pair

if type(query) is dict:
     try:
         query = sorted(query.items())
     except TypeError:
         query = sorted(query.items(), key=make_key)
else:
     query = query.items()



More information about the Python-Dev mailing list