nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: django/channels
Pull request #1954 (2022-11-16 11:25:25)

Fixed URLRouter root_path handling.
As discussed in https://github.com/django/daphne/issues/125, this adds handing of `scope["root_path"]` to `channels.routing.URLRouter`.

tevariou: any news on when this could be merged ?
carltongibson: @tevariou It's on my list to review now. 

Patch:
diff --git a/channels/routing.py b/channels/routing.py
index 07b5bab..d09d5ff 100644
--- a/channels/routing.py
+++ b/channels/routing.py
@@ -107,6 +107,15 @@ class URLRouter:
         path = scope.get("path_remaining", scope.get("path", None))
         if path is None:
             raise ValueError("No 'path' key in connection scope, cannot route URLs")
+
+        if "path_remaining" not in scope:
+            # We are the outermost URLRouter, so handle root_path if present.
+            root_path = scope.get("root_path", "")
+            if root_path and not path.startswith(root_path):
+                # If root_path is present, path must start with it.
+                raise ValueError("No route found for path %r." % path)
+            path = path[len(root_path) :]
+
         # Remove leading / to match Django's handling
         path = path.lstrip("/")
         # Run through the routes we have until one matches


Test patch:
diff --git a/tests/test_routing.py b/tests/test_routing.py
index b41f652..99c7679 100644
--- a/tests/test_routing.py
+++ b/tests/test_routing.py
@@ -107,6 +107,23 @@ async def test_url_router():
         "args": tuple(),
         "kwargs": {"default": 42},
     }
+    # Valid root_path in scope
+    assert (
+        await router(
+            {"type": "http", "path": "/root/", "root_path": "/root"}, None, None
+        )
+        == 1
+    )
+    assert (
+        await router(
+            {"type": "http", "path": "/root/foo/", "root_path": "/root"}, None, None
+        )
+        == 2
+    )
+
+    # Unmatched root_path in scope
+    with pytest.raises(ValueError):
+        await router({"type": "http", "path": "/", "root_path": "/root"}, None, None)
 
     # Invalid matches
     with pytest.raises(ValueError):
@@ -261,6 +278,29 @@ async def test_path_remaining():
         == 2
     )
 
+    assert (
+        await outermost_router(
+            {"type": "http", "path": "/root/prefix/stuff/", "root_path": "/root"},
+            None,
+            None,
+        )
+        == 2
+    )
+
+    with pytest.raises(ValueError):
+        await outermost_router(
+            {"type": "http", "path": "/root/root/prefix/stuff/", "root_path": "/root"},
+            None,
+            None,
+        )
+
+    with pytest.raises(ValueError):
+        await outermost_router(
+            {"type": "http", "path": "/root/prefix/root/stuff/", "root_path": "/root"},
+            None,
+            None,
+        )
+
 
 def test_invalid_routes():
     """
Repository: django/channels
Pull request #1983 (2023-03-08 19:39:35)

Remove leading whitespace in cookie middleware
Looks like the same issue as this PR https://github.com/django/channels/pull/1130 fixed.

h11 does not allow header values with leading or trailing whitespace.


Patch:
diff --git a/channels/sessions.py b/channels/sessions.py
index d54b432..fa16ec9 100644
--- a/channels/sessions.py
+++ b/channels/sessions.py
@@ -111,7 +111,7 @@ class CookieMiddleware:
         # Write out the cookies to the response
         for c in cookies.values():
             message.setdefault("headers", []).append(
-                (b"Set-Cookie", bytes(c.output(header=""), encoding="utf-8"))
+                (b"Set-Cookie", bytes(c.output(header="").strip(), encoding="utf-8"))
             )
 
     @classmethod


Test patch:
diff --git a/tests/test_http.py b/tests/test_http.py
index dd4a003..aa1fbe5 100644
--- a/tests/test_http.py
+++ b/tests/test_http.py
@@ -4,7 +4,7 @@ import pytest
 
 from channels.consumer import AsyncConsumer
 from channels.db import database_sync_to_async
-from channels.sessions import SessionMiddlewareStack
+from channels.sessions import CookieMiddleware, SessionMiddlewareStack
 from channels.testing import HttpCommunicator
 
 
@@ -21,6 +21,15 @@ class SimpleHttpApp(AsyncConsumer):
         await self.send({"type": "http.response.body", "body": b"test response"})
 
 
+@pytest.mark.asyncio
+async def test_set_cookie():
+    message = {}
+    CookieMiddleware.set_cookie(message, "Testing-Key", "testing-value")
+    assert message == {
+        "headers": [(b"Set-Cookie", b"Testing-Key=testing-value; Path=/; SameSite=lax")]
+    }
+
+
 @pytest.mark.django_db(transaction=True)
 @pytest.mark.asyncio
 async def test_sessions():
Repository: django/asgiref
Pull request #8 (2016-12-13 11:41:55)

validation method for multiple  channel names
added validation method that accepts list of channel names.


Patch:
diff --git a/asgiref/base_layer.py b/asgiref/base_layer.py
index 7cce614..99b22dd 100755
--- a/asgiref/base_layer.py
+++ b/asgiref/base_layer.py
@@ -112,3 +112,11 @@ class BaseChannelLayer(object):
             if bool(self.group_name_regex.match(name)):
                 return True
         raise TypeError("Group name must be a valid unicode string containing only alphanumerics, hyphens, or periods.")
+
+    def valid_channel_names(self, names):
+        _non_empty_list = True if names else False
+        _names_type = isinstance(names, list)
+        assert _non_empty_list and _names_type, "names must be a non-empty list"
+
+        assert all(self.valid_channel_name(channel) for channel in names)
+        return True


Test patch:
diff --git a/asgiref/tests/test_base_layer.py b/asgiref/tests/test_base_layer.py
index f6c5bc0..d39ed85 100755
--- a/asgiref/tests/test_base_layer.py
+++ b/asgiref/tests/test_base_layer.py
@@ -47,6 +47,32 @@ class BaseLayerTests(unittest.TestCase):
         with self.assertRaises(TypeError):
             layer.valid_channel_name("some+other!thing")
 
+    def test_valid_channel_names(self):
+        """
+        Tests the channel names validator
+        """
+        layer = BaseChannelLayer()
+
+        # valid channel names
+        valid_names = ["http.request", "http.response!ab0def",
+                       "http.request.body?ab0def", "0.a_b-c?d_e-f.1"]
+        self.assertTrue(layer.valid_channel_names(valid_names))
+
+        # invalid channel names
+        invalid_names = ["http.request\u00a3", "way.too.long" * 10,
+                         "one?two?three", "four!five!six", "some+other!thing"]
+        with self.assertRaises(TypeError):
+            layer.valid_channel_names(invalid_names)
+
+        # empty names
+        with self.assertRaises(AssertionError):
+            layer.valid_channel_names([])
+
+        # list type check
+        with self.assertRaises(AssertionError):
+            layer.valid_channel_names("")
+
+
     def test_valid_group_name(self):
         """
         Tests the group name validator
Repository: django/asgiref
Pull request #176 (2020-06-18 09:05:21)

Fix a crash in Local.__del__ due to buggy WeakSet impl

adamchainz: Is a test possible? Is there a Python bug to link to in a comment as it might get fixed in a future version?
untitaker: I couldn't find a python bug report. I can file one later.

Our options for tests are constrained to mocking weakset to always raise a TypeError, not sure how to simulate interpreter shutdown in the tests
adamchainz: The mocking approach sounds reasonable to me.

Thanks for all your work here!
andrewgodwin: @untitaker Is this related to the continuing saga of Django tests breaking mentioned in #170? I see it relates to the only other change in 3.2.8 so I'm guessing so.
untitaker: It relates to a change in 3.2.8 unrelated to anything context propagation:  edd0570
andrewgodwin: Yup, that's the one I meant. If you get a mocked test in with a fake TypeError raise we can land and release this pronto.
untitaker: Here you go. Not entirely sure if that test is any good but oh well.

Patch:
diff --git a/asgiref/local.py b/asgiref/local.py
index ef55f68..3d24b14 100644
--- a/asgiref/local.py
+++ b/asgiref/local.py
@@ -87,11 +87,16 @@ class Local:
         return getattr(context_obj, self._attr_name)
 
     def __del__(self):
-        for context_obj in self._context_refs:
-            try:
-                delattr(context_obj, self._attr_name)
-            except AttributeError:
-                pass
+        try:
+            for context_obj in self._context_refs:
+                try:
+                    delattr(context_obj, self._attr_name)
+                except AttributeError:
+                    pass
+        except TypeError:
+            # WeakSet.__iter__ can crash when interpreter is shutting down due
+            # to _IterationGuard being None.
+            pass
 
     def __getattr__(self, key):
         with self._thread_lock:


Test patch:
diff --git a/tests/test_local.py b/tests/test_local.py
index 41505db..6ea2522 100644
--- a/tests/test_local.py
+++ b/tests/test_local.py
@@ -298,3 +298,20 @@ async def test_local_threads_and_tasks():
 
     await sync_to_async(sync_function)(5)
     assert test_local.counter == 6
+
+
+def test_local_del_swallows_type_error(monkeypatch):
+    test_local = Local()
+
+    blow_up_calls = 0
+
+    def blow_up(self):
+        nonlocal blow_up_calls
+        blow_up_calls += 1
+        raise TypeError()
+
+    monkeypatch.setattr("weakref.WeakSet.__iter__", blow_up)
+
+    test_local.__del__()
+
+    assert blow_up_calls == 1
Repository: django/asgiref
Pull request #328 (2022-05-10 19:10:37)

Disallow async callable class instances as callable for `sync.SyncToAsync`
i.e. passing an instance defining `async def __call__(...)` to `sync.SyncToAsync` will raise a `TypeError`

Refs: #324 
Fixes: #327 


Patch:
diff --git a/asgiref/sync.py b/asgiref/sync.py
index d02bd4a..6247043 100644
--- a/asgiref/sync.py
+++ b/asgiref/sync.py
@@ -356,7 +356,11 @@ class SyncToAsync:
         thread_sensitive: bool = True,
         executor: Optional["ThreadPoolExecutor"] = None,
     ) -> None:
-        if not callable(func) or _iscoroutinefunction_or_partial(func):
+        if (
+            not callable(func)
+            or _iscoroutinefunction_or_partial(func)
+            or _iscoroutinefunction_or_partial(getattr(func, "__call__", func))
+        ):
             raise TypeError("sync_to_async can only be applied to sync functions.")
         self.func = func
         functools.update_wrapper(self, func)


Test patch:
diff --git a/tests/test_sync.py b/tests/test_sync.py
index c5677fc..022a174 100644
--- a/tests/test_sync.py
+++ b/tests/test_sync.py
@@ -99,6 +99,18 @@ async def test_async_to_sync_fail_partial():
     )
 
 
+@pytest.mark.asyncio
+async def test_sync_to_async_raises_typeerror_for_async_callable_instance():
+    class CallableClass:
+        async def __call__(self):
+            return None
+
+    with pytest.raises(
+        TypeError, match="sync_to_async can only be applied to sync functions."
+    ):
+        sync_to_async(CallableClass())
+
+
 @pytest.mark.asyncio
 async def test_sync_to_async_decorator():
     """