Httpx: Should query parameter ordering matter when comparing URL equality?

Created on 25 Nov 2020  Â·  10Comments  Â·  Source: encode/httpx

Checklist

  • [x] The bug is reproducible against the latest release and/or master.
  • [x] There are no similar issues or pull requests to fix it yet.

Describe the bug

Unable to compare two httpx.URL() objects, which have the same query params but with different order

To reproduce

url1 = httpx.URL('http://test?a=1&b=2')
url2 = httpx.URL('http://test?b=2&a=1')

assert url1 == url2

Expected behavior

The URLs considered as equal

Actual behavior

Obviously same URLs considered as different

Traceback (most recent call last):
  File "/Users/user/.virtualenvs/some/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3417, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-11-9666aec6e8b1>", line 4, in <module>
    assert url1 == url2
AssertionError

Environment

  • OS: doesn't matter
  • Python version: 3.8.2, but looks like it doesn't matter as well
  • HTTPX version: 0.16.1
  • Async environment: doesn't matter

Additional context

Given issue makes writing test quite annoying. It forces saving same order in the query string. It also hard to mock such calls.

user-experience

All 10 comments

Got the same issue, the things will go much easier if it's fixed. Hope it will be done soon.
Thanks for reporting @devova.

So, this isn't as obvious a behaviour as you might think.

Query string ordering generally won't be important, but it can be, and we can't really treat those URLs as being unambiguously equivalent.

I took a look through a few other libraries here too...

>>> from hyperlink import URL
>>> URL.from_text('http://test?a=1&b=2') == URL.from_text('http://test?b=2&a=1') 
False
>>> import urllib3
>>> urllib3.util.parse_url('http://test?a=1&b=2') == urllib3.util.parse_url('http://test?b=2&a=1')
False
>>> from furl import furl
>>> furl('http://test?a=1&b=2') == furl('http://test?b=2&a=1')
False

The best you can do for your use case at the moment is check for equivalence of parsed query parameter datastructures...

httpx.QueryParams(url1.query) == httpx.QueryParams(url2.query)

That's not to say that we couldn't consider changing our equality behaviour. It might be more practical, although it's a bit fuzzy.

Also useful might be having a .params property on the class, to easily access the parsed query params datastructure, so eg...

url1.params == url2.params

Also, if folks could not do the "let's get a bunch of tictrac folks to upvote this" thing, that'd be grand. 🤣

There are more productive ways to push things forward... https://github.com/sponsors/encode 💚

Tweaked the issue title on this one.

Similar issue here would be should URL escaping be relevant when comparing URLs...

# What behaviour would we most expect here...
httpx.URL("http://example.com/path/to%20somewhere") == httpx.URL("http://example.com/path/to somewhere")

As with the query ordering, these two URLs are not strictly equal, but to most application frameworks they probably are equivalent.

@tomchristie thank you for given examples, it there need to explicitly compare URLs these options might work. As I sad it also hard to mock the requests. I'm using pytest-httpx where I can do

httpx_mock.add_response(url=...)

And here I have to really care about query string order since under the hood it compares httpx.URL objects

Hello @devova feel free to enter the issue in pytest-httpx, I will take a look at it as order of parameters should indeed not matter if the names are different

@devova pytest-httpx 0.10.1 is now available on pypi.org and should fix this issue.

Should you encounter new issues in the future, don't hesitate to ask for help on the GitHub page for pytest-httpx.

@Colin-b very appreciate it

Super — so should we consider this resolved? I'm personally not too fond of making this too smart — although it could be that url.params could help. But the other case about escaping is messy too... And I think we should treat it as we do now: different URLs. It's easier for people to pre-process then feed into HTTPX than to get around some automatic processing we would do if you _really_ want ordering or escaping to matter.

Yeah, the solution works for me. I also agree that it was a usability problem in testing rather than implicit URL equality in main httpx library.
Thank you all for your contribution.

Was this page helpful?
0 / 5 - 0 ratings