Repository: Pylons/pyramid

Issue:
pyramid.request.route_url docs incorrect, request query not passed if _query omitted
RE: documentation on `Request.route_url` for handling query string
https://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request.route_url

Discussed with @raydeo who confirmed issue in #pyramid IRC on (Tues Feb 6, 2018 around 12p Central US).

`route_url` docs state, "If no `_query` keyword argument is provided, the request query string will be returned in the URL."

That is not correct. If `_query` is omitted, no query is added to generated URL.

Need to check and see if it was ever correct and this functionality is broken, or if this was just never correct (or possibly intended but never implemented).

Background is that I was running through the v1.9.1 [Quick Tutorial for Pyramid, 10: Handling Web Requests and Responses](https://docs.pylonsproject.org/projects/pyramid/en/latest/quick_tutorial/request_response.html)

It has you do a redirect using exception handling via `HTTPFound`, but the query string is stripped in the redirect.

I wanted to learn more about how to redirect but in a more useful sense where the query and anchor are maintained, so more like what a user would expect in a true 302.

At the bottom of the tutorial it has the Extra Credit section and lists some links to further documentation, including [Request and Response Objects](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/webob.html#webob-chapter).

I followed and then took it one step deeper to the `pyramid.request` API documentation linked from [that page](https://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#request-module).

Further recommendations are to update the documentation for `query_string` parameter of [pyramid.request](https://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request.query_string) that tells us what kind of data structure is returned (quoted string, determined by empirically).

I would also recommend updating the documentation for the `route_url` to include a recommended approach for passing the `request` query string. It seems the best way would be via something like @raydeo suggested:
`request.route_url(..., _query=request.GET.items())`

I had found that `_query=self.request.query_string` worked, but @raydo pointed out that this could present issues because as mentioned previously `query_string` is just a quoted string and not properly urlencoded.


Discussion:
It's related to #1081 and #1040, which indicate it was never actually intended for `Request.route_url` to retain query string (see discussion in #1040 and tests in #1081, they're all intended for `Request.current_route_url`). 

It's been "broken" in a54d7d6. Instead of reverting the mistake from #1081, @mmerickel just did a quick dirty fix, so the misleading documentation is still there.
It's correct that this was broken by me. I think that at this point we just need to fix the documentation to match the current behavior.

Resolving patch:
diff --git a/pyramid/url.py b/pyramid/url.py
--- a/pyramid/url.py
+++ b/pyramid/url.py
@@ -161,15 +161,14 @@ def route_url(self, route_name, *elements, **kw):
         ``*remainder`` replacement value, it is tacked on to the URL
         after being URL-quoted-except-for-embedded-slashes.
 
-        If no ``_query`` keyword argument is provided, the request query string
-        will be returned in the URL. If it is present, it will be used to
-        compose a query string that will be tacked on to the end of the URL,
-        replacing any request query string.  The value of ``_query`` may be a
-        sequence of two-tuples *or* a data structure with an ``.items()``
-        method that returns a sequence of two-tuples (presumably a dictionary).
-        This data structure will be turned into a query string per the
-        documentation of :func:`pyramid.url.urlencode` function.  This will
-        produce a query string in the ``x-www-form-urlencoded`` format.  A
+        If ``_query`` is provided, it will be used to compose a query string
+        that will be tacked on to the end of the URL.  The value of ``_query``
+        may be a sequence of two-tuples *or* a data structure with an
+        ``.items()`` method that returns a sequence of two-tuples
+        (presumably a dictionary). This data structure will be turned into
+        a query string per the documentation of the
+        :func:`pyramid.url.urlencode` function.  This will produce a query
+        string in the ``x-www-form-urlencoded`` format.  A
         non-``x-www-form-urlencoded`` query string may be used by passing a
         *string* value as ``_query`` in which case it will be URL-quoted
         (e.g. query="foo bar" will become "foo%20bar").  However, the result
@@ -353,20 +352,21 @@ def resource_url(self, resource, *elements, **kw):
                      ``elements`` are used, the generated URL will *not*
                      end in a trailing slash.
 
-        If a keyword argument ``query`` is present, it will be used to compose
-        a query string that will be tacked on to the end of the URL.  The value
-        of ``query`` may be a sequence of two-tuples *or* a data structure with
-        an ``.items()`` method that returns a sequence of two-tuples
-        (presumably a dictionary).  This data structure will be turned into a
-        query string per the documentation of :func:`pyramid.url.urlencode`
-        function.  This will produce a query string in the
-        ``x-www-form-urlencoded`` encoding.  A non-``x-www-form-urlencoded``
-        query string may be used by passing a *string* value as ``query`` in
-        which case it will be URL-quoted (e.g. query="foo bar" will become
-        "foo%20bar").  However, the result will not need to be in ``k=v`` form
-        as required by ``x-www-form-urlencoded``.  After the query data is
-        turned into a query string, a leading ``?`` is prepended, and the
-        resulting string is appended to the generated URL.
+        If ``query`` is provided, it will be used to compose a query string
+        that will be tacked on to the end of the URL.  The value of ``query``
+        may be a sequence of two-tuples *or* a data structure with an
+        ``.items()`` method that returns a sequence of two-tuples
+        (presumably a dictionary). This data structure will be turned into
+        a query string per the documentation of the
+        :func:`pyramid.url.urlencode` function.  This will produce a query
+        string in the ``x-www-form-urlencoded`` format.  A
+        non-``x-www-form-urlencoded`` query string may be used by passing a
+        *string* value as ``query`` in which case it will be URL-quoted
+        (e.g. query="foo bar" will become "foo%20bar").  However, the result
+        will not need to be in ``k=v`` form as required by
+        ``x-www-form-urlencoded``.  After the query data is turned into a query
+        string, a leading ``?`` is prepended, and the resulting string is
+        appended to the generated URL.
 
         .. note::
 


Test patch: