internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: pallets/werkzeug

Issue:
werkzeug double-encodes redirects when processing merge_slashes
```python
from werkzeug.routing import Rule, Map

routes = Map([
    Rule("/merge/<some>/path"),
])

def get_redirect_location(path):
    try:
        routes.bind("test.host").match(path)
    except Exception as e:
        return e.get_response({}).headers['location']
    else:
        raise ValueError("no redirect")

def test_merge_slashes():
    assert get_redirect_location("/merge/%//path") == 'http://test.host/merge/%25/path'
```

It looks like `Rule.match` uses `Rule.build` to generate the new path [here](https://github.com/pallets/werkzeug/blob/2.0.1/src/werkzeug/routing.py#L943), which is already urlencoded. But then `MapAdapter.match` encodes the resulting path again [here](https://github.com/pallets/werkzeug/blob/2.0.1/src/werkzeug/routing.py#L1963-L1969).

Environment:

- Python version: 3.9.5
- Werkzeug version: 2.0.1


Discussion:

Resolving patch:
diff --git a/src/werkzeug/routing.py b/src/werkzeug/routing.py
--- a/src/werkzeug/routing.py
+++ b/src/werkzeug/routing.py
@@ -134,6 +134,7 @@
 from .urls import url_encode
 from .urls import url_join
 from .urls import url_quote
+from .urls import url_unquote
 from .utils import cached_property
 from .utils import redirect
 from .wsgi import get_host
@@ -944,7 +945,10 @@ def match(
                     if path.endswith("/") and not new_path.endswith("/"):
                         new_path += "/"
                     if new_path.count("/") < path.count("/"):
-                        path = new_path
+                        # The URL will be encoded when MapAdapter.match
+                        # handles the RequestPath raised below. Decode
+                        # the URL here to avoid a double encoding.
+                        path = url_unquote(new_path)
                         require_redirect = True
 
                 if require_redirect:


Test patch:
diff --git a/tests/test_routing.py b/tests/test_routing.py
--- a/tests/test_routing.py
+++ b/tests/test_routing.py
@@ -122,6 +122,26 @@ def test_merge_slashes_match():
     assert adapter.match("/no//merge")[0] == "no_merge"
 
 
+@pytest.mark.parametrize(
+    ("path", "expected"),
+    [("/merge/%//path", "/merge/%25/path"), ("/merge//st/path", "/merge/st/path")],
+)
+def test_merge_slash_encoding(path, expected):
+    """This test is to make sure URLs are not double-encoded
+    when a redirect is thrown with `merge_slash = True`"""
+    url_map = r.Map(
+        [
+            r.Rule("/merge/<some>/path"),
+        ]
+    )
+    adapter = url_map.bind("localhost", "/")
+
+    with pytest.raises(r.RequestRedirect) as excinfo:
+        adapter.match(path)
+
+    assert excinfo.value.new_url.endswith(expected)
+
+
 def test_merge_slashes_build():
     url_map = r.Map(
         [
Repository: pallets/werkzeug

Issue:
to_dict method on CombinedMultiDict doesn't give combined result for overlapping keys
Whenever I call `to_dict(flat=False)` on a `CombinedMultiDict`, obtained from combining two MultiDicts with overlapping keys, only the values of the last MultiDict are returned. 

```python
# altered from documentation to make keys overlapping.
from werkzeug.datastructures import CombinedMultiDict, MultiDict
post = MultiDict([('foo', 'bar'),('foo', 'bar2')])
get = MultiDict([('foo', 'bar3')])
combined = CombinedMultiDict([get, post])
combined.getlist('foo')
>> ['bar3', 'bar', 'bar2']
combined.to_dict(flat=False)
>> {'foo': ['bar3']}
```

From a class that intends to combine two MultiDicts, I expect the result from one of its methods to be a combined result.
Environment:
- Python version: 3.6.8
- Werkzeug version: 1.0.1



Discussion:

Resolving patch:
diff --git a/src/werkzeug/datastructures.py b/src/werkzeug/datastructures.py
--- a/src/werkzeug/datastructures.py
+++ b/src/werkzeug/datastructures.py
@@ -1526,10 +1526,10 @@ def to_dict(self, flat=True):
                      contain the first item for each key.
         :return: a :class:`dict`
         """
-        rv = {}
-        for d in reversed(self.dicts):
-            rv.update(d.to_dict(flat))
-        return rv
+        if flat:
+            return dict(self.items())
+
+        return dict(self.lists())
 
     def __len__(self):
         return len(self._keys_impl())


Test patch:
diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py
--- a/tests/test_datastructures.py
+++ b/tests/test_datastructures.py
@@ -595,10 +595,14 @@ def test_basic_interface(self):
         d["foo"] = "blub"
 
         # make sure lists merges
-        md1 = ds.MultiDict((("foo", "bar"),))
+        md1 = ds.MultiDict((("foo", "bar"), ("foo", "baz")))
         md2 = ds.MultiDict((("foo", "blafasel"),))
         x = self.storage_class((md1, md2))
-        assert list(x.lists()) == [("foo", ["bar", "blafasel"])]
+        assert list(x.lists()) == [("foo", ["bar", "baz", "blafasel"])]
+
+        # make sure dicts are created properly
+        assert x.to_dict() == {"foo": "bar"}
+        assert x.to_dict(flat=False) == {"foo": ["bar", "baz", "blafasel"]}
 
     def test_length(self):
         d1 = ds.MultiDict([("foo", "1")])
Repository: pallets/werkzeug

Issue:
Debugger cookie must not use SameSite=None
The debugger sets a cookie to store the pin. #1913 added `SameSite=None`. However, browsers are now warning that that is invalid without the `Secure` flag, which is only valid for HTTPS.

1. Trigger the debugger.
2. Open the browser dev tools.
3. Click the console icon in the debugger and enter the pin.
4. Observe the warning in the browser dev tools console.

The browser should not show the warning that the debugger's cookie will be rejected in a future version. The cookie should either use `Lax` or `Strict`. I think `Strict` makes more sense in this case. The original issue #1912 referenced using the debugger in an iframe, which I think would require `Lax`, but I'm not sure that's a behavior worth keeping.

Environment:

- Python version: 3.9
- Werkzeug version: 2.0.2



Discussion:
Both `Lax` and `Strict` are not allowed from iframes with different domains. However, they do work for the same domain (port can be different).

I could set `None` only if `request.is_secure` otherwise `Strict`. However, I don't feel very comfortable with that, it makes the debugger less secure in a scenario that sounds more secure (for whatever that's worth, don't use the debugger in production). For now I'm going to always use `Strict`.

If users want to use the interactive debugger within an iframe, they'll need to serve from the same domain (perhaps using a proxy server or hosts file). Alternatively, they can always use PyCharm, VSCode, pdb, etc. to debug outside the browser.

`nest.html`:

```html
<iframe src="http://a.localhost:5000/"></iframe>
```

```
$ python -m http.server -b 127.0.0.1 8000
```

`example.py`:

```python
from werkzeug import Request, run_simple


@Request.application
def app(request):
    raise Exception


run_simple("localhost", 5000, app, use_debugger=True)
```

```
$ python example.py
```

My machine is configured to treat every `*.localhost` domain as `127.0.0.1`. Mine uses systemd, the same can be done by editing `/etc/hosts`. Navigate to `http://b.localhost:8000/nest.html`, which will request `http://a.localhost:5000` in an iframe. You can enter a pin, but the resulting cookie won't be stored or sent. Navigate to `http://a.localhost:8000/nest.html` (same domain now), and the cookie will work.

Resolving patch:
diff --git a/src/werkzeug/debug/__init__.py b/src/werkzeug/debug/__init__.py
--- a/src/werkzeug/debug/__init__.py
+++ b/src/werkzeug/debug/__init__.py
@@ -449,7 +449,7 @@ def pin_auth(self, request: Request) -> Response:
                 self.pin_cookie_name,
                 f"{int(time.time())}|{hash_pin(pin)}",
                 httponly=True,
-                samesite="None",
+                samesite="Strict",
                 secure=request.is_secure,
             )
         elif bad_cookie:


Test patch:
Repository: pallets/werkzeug

Issue:
Shortly example cannot redirect to the expected link
**Bug**

In Shortly example, if I want to follow a short link with  `http://127.0.0.1:5000/1`, the following error occurs:

```
Traceback (most recent call last):
  File "/werkzeug/src/werkzeug/serving.py", line 319, in run_wsgi
    execute(self.server.app)
  File "/werkzeug/src/werkzeug/serving.py", line 308, in execute
    application_iter = app(environ, start_response)
  File "/werkzeug/examples/shortly/shortly.py", line 121, in __call__
    return self.wsgi_app(environ, start_response)
  File "/werkzeug/src/werkzeug/middleware/shared_data.py", line 287, in __call__
    return self.app(environ, start_response)
  File "/werkzeug/examples/shortly/shortly.py", line 117, in wsgi_app
    response = self.dispatch_request(request)
  File "/werkzeug/examples/shortly/shortly.py", line 109, in dispatch_request
    return getattr(self, f"on_{endpoint}")(request, **values)
  File "/werkzeug/examples/shortly/shortly.py", line 72, in on_follow_short_link
    return redirect(link_target)
  File "/werkzeug/src/werkzeug/utils.py", line 554, in redirect
    display_location = html.escape(location)
  File "/.pyenv/versions/3.8.10/lib/python3.8/html/__init__.py", line 19, in escape
    s = s.replace("&", "&amp;") # Must be done first!
TypeError: a bytes-like object is required, not 'str'
```

**Expected Behavior**

The browser should redirect to the link based on the short id.

**Reason**

redis-py package saves value as string but returns bytes by default. The `link_target` is bytes at the moment, but str is needed for `redirect` function

**Environment:**

- Python version: 3.8.10
- Werkzeug version: 2.0.1
- Redis-py version: 3.5.3


Discussion:

Resolving patch:
diff --git a/examples/shortly/shortly.py b/examples/shortly/shortly.py
--- a/examples/shortly/shortly.py
+++ b/examples/shortly/shortly.py
@@ -37,7 +37,9 @@ def get_hostname(url):
 
 class Shortly:
     def __init__(self, config):
-        self.redis = redis.Redis(config["redis_host"], config["redis_port"])
+        self.redis = redis.Redis(
+            config["redis_host"], config["redis_port"], decode_responses=True
+        )
         template_path = os.path.join(os.path.dirname(__file__), "templates")
         self.jinja_env = Environment(
             loader=FileSystemLoader(template_path), autoescape=True


Test patch:
Repository: pallets/werkzeug

Issue:
mypy deduced type on Request.user_agent_class is Type[_UserAgent]
I ran into this after updating to v2.0.2 of flask and werkzeug.

Since `UserAgent` is going away, I replaced it with `ua_parser` (example will follow).
However, setting `user_agent_class = MyUserAgent` triggers a typing error as the type of `Request.user_agent_class` refers to the internal (deprecated) `_UserAgent`.

Absolutely minimal reproduction:
```python
# minimal.py
from flask import Request
from werkzeug.user_agent import UserAgent

class MyUserAgent(UserAgent): pass

class MyRequest(Request):
    user_agent_class = MyUserAgent
```
produces
```shell
$ mypy minimal.py
minimal.py:7: error: Incompatible types in assignment (expression has type "Type[MyUserAgent]", base class "Request" defined the type as "Type[_UserAgent]")
Found 1 error in 1 file (checked 1 source file)
```

I've also created [a simple reproduction of the failing mypy run in a repo](https://github.com/sirosen/repro/tree/main/flask/ua_typesig), which includes both the above minimal example, and my usage with `ua_parser`.

I know that `_UserAgent` is going away, so maybe this doesn't matter. But I could submit a patch to change [this line](https://github.com/pallets/werkzeug/blob/f7b53ee8a81f015c6c85659959004328237a3c8c/src/werkzeug/sansio/request.py#L98) to read
```python
    user_agent_class: t.Type[UserAgent] = t.cast(t.Type[UserAgent], _DeprecatedUserAgent)
```

I think that would solve this, since the type would be known to `mypy` (and other type checkers) as `Type[UserAgent]`, and inheriting subclasses would be accepted.

Would that fix be welcome?

Also, I haven't seen any python projects establish a testing process for type annotations. Do the pallets projects have an approach if I wanted to add a test case for this?


Discussion:
This was more straightforward than the suggested fix, only need `Type[UserAgent]`. It was because I had missed adding any annotation at all, so it was falling back to the assigned type.

Resolving patch:
diff --git a/src/werkzeug/sansio/request.py b/src/werkzeug/sansio/request.py
--- a/src/werkzeug/sansio/request.py
+++ b/src/werkzeug/sansio/request.py
@@ -95,7 +95,7 @@ class Request:
     #: .. versionadded:: 0.6
     list_storage_class: t.Type[t.List] = ImmutableList
 
-    user_agent_class = _DeprecatedUserAgent
+    user_agent_class: t.Type[UserAgent] = _DeprecatedUserAgent
     """The class used and returned by the :attr:`user_agent` property to
     parse the header. Defaults to
     :class:`~werkzeug.user_agent.UserAgent`, which does no parsing. An


Test patch:
Repository: pallets/werkzeug

Issue:
_set_cache_value doesn't check for None type and crashes if no_cache is set to False
Setting `response.cache_control.no_cache = False` used to work up until version 2.0.x thanks to this code in datastructures.py, where the type value received is None:

```
    def _set_cache_value(self, key, value, type):
        """Used internally by the accessor properties."""
        if type is bool:
(...)
        else:
            if value is None:
                self.pop(key, None)
            elif value is True:
                self[key] = None
            else:
                self[key] = value

```

Now it crashes because type is not checked for None in 2.1.x:

```
    def _set_cache_value(self, key, value, type):
        """Used internally by the accessor properties."""
        if type is bool:
(...)
       else:
            if value is None:
                self.pop(key, None)
            elif value is True:
                self[key] = None
            else:
                self[key] = type(value) # <-- crashes if type is None
```

It type is None, this will crash:
`TypeError: 'NoneType' object is not callable`

I think the correct code should be:
```
    def _set_cache_value(self, key, value, type):
        """Used internally by the accessor properties."""
        if type is bool:
(...)
       else:
            if value is None:
                self.pop(key, None)
            elif value is True:
                self[key] = None
            elif type is None:
                # do something, e.g. self[key] = value
            else:
                self[key] = type(value) 
```

To reproduce:
```
def send_static(path):
    response = send_from_directory('assets', path)
    response.cache_control.no_cache = False
```

Expected behavior:
At least check for type being None before trying to call it and throw an appropriate exception if needed (not sure why it should be an error, the code worked fine in 2.0.3)


Environment:

- Python version: 3.10.x
- Werkzeug version: 2.1.1



Discussion:

Resolving patch:
diff --git a/src/werkzeug/datastructures.py b/src/werkzeug/datastructures.py
--- a/src/werkzeug/datastructures.py
+++ b/src/werkzeug/datastructures.py
@@ -2036,7 +2036,10 @@ def _set_cache_value(self, key, value, type):
             elif value is True:
                 self[key] = None
             else:
-                self[key] = type(value)
+                if type is not None:
+                    self[key] = type(value)
+                else:
+                    self[key] = value
 
     def _del_cache_value(self, key):
         """Used internally by the accessor properties."""


Test patch:
diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py
--- a/tests/test_datastructures.py
+++ b/tests/test_datastructures.py
@@ -973,6 +973,8 @@ def test_set_none(self):
         assert cc.no_cache is None
         cc.no_cache = None
         assert cc.no_cache is None
+        cc.no_cache = False
+        assert cc.no_cache is False
 
 
 class TestContentSecurityPolicy:
Repository: pallets/werkzeug

Issue:
Don't use keep-alive connections in HTTP/1.1 mode
Python's built-in `http.server`, which Werkzeug's dev server extends, does not drain the request body stream before the next request begins. If the view function didn't read the request body, then it would result in the body appearing prepended to the next request method, like `{}GET`. Not reading the body is apparently common, perhaps when first developing a view. When we enabled HTTP/1.1 by default, many more users began seeing this issue.

Disable keep-alive connections. The original request for HTTP/1.1 mode was for chunked responses, which will continue to work.

While they technically should report it to Python, they instead reported it repeatedly to Werkzeug and Flask since that's what they were using. If someone wants to report this to Python, and they fix it, please open a PR here to re-enable keep-alive connections.

Remember, the development server should never be used outside development. It is not designed to be particularly secure, stable, or efficient.


Discussion:

Resolving patch:
diff --git a/src/werkzeug/serving.py b/src/werkzeug/serving.py
--- a/src/werkzeug/serving.py
+++ b/src/werkzeug/serving.py
@@ -271,18 +271,23 @@ def write(data: bytes) -> None:
                 # is the more conservative behavior and matches other
                 # parts of the code.
                 # https://httpwg.org/specs/rfc7230.html#rfc.section.3.3.1
-                if not (
-                    "content-length" in header_keys
-                    or environ["REQUEST_METHOD"] == "HEAD"
-                    or (100 <= code < 200)
-                    or code in {204, 304}
+                if (
+                    not (
+                        "content-length" in header_keys
+                        or environ["REQUEST_METHOD"] == "HEAD"
+                        or (100 <= code < 200)
+                        or code in {204, 304}
+                    )
+                    and self.protocol_version >= "HTTP/1.1"
                 ):
-                    if self.protocol_version >= "HTTP/1.1":
-                        chunk_response = True
-                        self.send_header("Transfer-Encoding", "chunked")
-                    else:
-                        self.send_header("Connection", "close")
-
+                    chunk_response = True
+                    self.send_header("Transfer-Encoding", "chunked")
+
+                # Always close the connection. This disables HTTP/1.1
+                # keep-alive connections. They aren't handled well by
+                # Python's http.server because it doesn't know how to
+                # drain the stream before the next request line.
+                self.send_header("Connection", "close")
                 self.end_headers()
 
             assert isinstance(data, bytes), "applications must write bytes"


Test patch:
Repository: pallets/werkzeug

Issue:
show Python 3.11 traceback information in debugger
Python 3.11 adds fine grained location information to tracebacks, and uses it to print an arrow under the code line. Figure out how to get this information from the `traceback` objects and use it to draw the same output in the interactive debugger.


Discussion:
I'm at PyCon and I'll take this on
Also verify that `ExceptionGroup` errors render correctly, they have some additional output as well but I think that might already be handled by the existing formatting.

Resolving patch:
diff --git a/src/werkzeug/debug/tbtools.py b/src/werkzeug/debug/tbtools.py
--- a/src/werkzeug/debug/tbtools.py
+++ b/src/werkzeug/debug/tbtools.py
@@ -175,15 +175,19 @@ def _process_traceback(
             elif hide_value or hidden:
                 continue
 
-        new_stack.append(
-            DebugFrameSummary(
-                filename=fs.filename,
-                lineno=fs.lineno,
-                name=fs.name,
-                locals=f.f_locals,
-                globals=f.f_globals,
-            )
-        )
+        frame_args: t.Dict[str, t.Any] = {
+            "filename": fs.filename,
+            "lineno": fs.lineno,
+            "name": fs.name,
+            "locals": f.f_locals,
+            "globals": f.f_globals,
+        }
+
+        if hasattr(fs, "colno"):
+            frame_args["colno"] = fs.colno  # type: ignore[attr-defined]
+            frame_args["end_colno"] = fs.end_colno  # type: ignore[attr-defined]
+
+        new_stack.append(DebugFrameSummary(**frame_args))
 
     # The codeop module is used to compile code from the interactive
     # debugger. Hide any codeop frames from the bottom of the traceback.
@@ -385,9 +389,21 @@ def render_line(line: str, cls: str) -> None:
             line = line.expandtabs().rstrip()
             stripped_line = line.strip()
             prefix = len(line) - len(stripped_line)
+            colno = getattr(self, "colno", 0)
+            end_colno = getattr(self, "end_colno", 0)
+
+            if cls == "current" and colno and end_colno:
+                arrow = (
+                    f'\n<span class="ws">{" " * prefix}</span>'
+                    f'{" " * (colno - prefix)}{"^" * (end_colno - colno)}'
+                )
+            else:
+                arrow = ""
+
             rendered_lines.append(
                 f'<pre class="line {cls}"><span class="ws">{" " * prefix}</span>'
-                f"{escape(stripped_line) if stripped_line else ' '}</pre>"
+                f"{escape(stripped_line) if stripped_line else ' '}"
+                f"{arrow if arrow else ''}</pre>"
             )
 
         if lines:


Test patch: