nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: tornadoweb/tornado
Pull request #1285 (2014-12-23 08:32:44)

Ensure that HTTPServerRequest.body is a byte string
HTTPServerRequest.body should be bytes but it is an empty string that
occurs in Python3 when pass no body to HTTPServerRequest.


Patch:
diff --git a/tornado/httputil.py b/tornado/httputil.py
index a3745569..88389fed 100644
--- a/tornado/httputil.py
+++ b/tornado/httputil.py
@@ -331,7 +331,7 @@ class HTTPServerRequest(object):
         self.uri = uri
         self.version = version
         self.headers = headers or HTTPHeaders()
-        self.body = body or ""
+        self.body = body or b""
 
         # set remote IP and protocol
         context = getattr(connection, 'context', None)
diff --git a/tornado/wsgi.py b/tornado/wsgi.py
index f3aa6650..e7e07fbc 100644
--- a/tornado/wsgi.py
+++ b/tornado/wsgi.py
@@ -207,7 +207,7 @@ class WSGIAdapter(object):
             body = environ["wsgi.input"].read(
                 int(headers["Content-Length"]))
         else:
-            body = ""
+            body = b""
         protocol = environ["wsgi.url_scheme"]
         remote_ip = environ.get("REMOTE_ADDR", "")
         if environ.get("HTTP_HOST"):


Test patch:
diff --git a/tornado/test/httputil_test.py b/tornado/test/httputil_test.py
index 5ca5cf9f..adbd1711 100644
--- a/tornado/test/httputil_test.py
+++ b/tornado/test/httputil_test.py
@@ -264,6 +264,10 @@ class HTTPServerRequestTest(unittest.TestCase):
         # more required parameters slip in.
         HTTPServerRequest(uri='/')
 
+    def test_body_is_a_byte_string(self):
+        requets = HTTPServerRequest(uri='/')
+        self.assertIsInstance(requets.body, bytes)
+
 
 class ParseRequestStartLineTest(unittest.TestCase):
     METHOD = "GET"
Repository: tornadoweb/tornado
Pull request #1352 (2015-02-27 03:12:15)

Add tornado.locks.BoundedSemaphore.


Patch:
diff --git a/tornado/locks.py b/tornado/locks.py
index 49667cea..1367e1de 100644
--- a/tornado/locks.py
+++ b/tornado/locks.py
@@ -14,7 +14,7 @@
 
 from __future__ import absolute_import, division, print_function, with_statement
 
-__all__ = ['Condition', 'Event', 'Semaphore']
+__all__ = ['Condition', 'Event', 'Semaphore', 'BoundedSemaphore']
 
 import collections
 
@@ -223,3 +223,21 @@ class Semaphore(object):
             " 'with semaphore'")
 
     __exit__ = __enter__
+
+
+class BoundedSemaphore(Semaphore):
+    """A semaphore that prevents release() being called too many times.
+
+    If `.release` would increment the semaphore's value past the initial
+    value, it raises `ValueError`. Semaphores are mostly used to guard
+    resources with limited capacity, so a semaphore released too many times
+    is a sign of a bug.
+    """
+    def __init__(self, value=1):
+        super(BoundedSemaphore, self).__init__(value=value)
+        self._initial_value = value
+
+    def release(self):
+        if self._value >= self._initial_value:
+            raise ValueError("Semaphore released too many times")
+        super(BoundedSemaphore, self).release()


Test patch:
diff --git a/tornado/test/locks_test.py b/tornado/test/locks_test.py
index 38d2bafb..29d80b94 100644
--- a/tornado/test/locks_test.py
+++ b/tornado/test/locks_test.py
@@ -349,5 +349,20 @@ class SemaphoreContextManagerTest(AsyncTestCase):
                 pass
 
 
+class BoundedSemaphoreTest(AsyncTestCase):
+    def test_release_unacquired(self):
+        sem = locks.BoundedSemaphore()
+        self.assertRaises(ValueError, sem.release)
+        # Value is 0.
+        sem.acquire()
+        # Block on acquire().
+        future = sem.acquire()
+        self.assertFalse(future.done())
+        sem.release()
+        self.assertTrue(future.done())
+        # Value is 1.
+        sem.release()
+        self.assertRaises(ValueError, sem.release)
+
 if __name__ == '__main__':
     unittest.main()
Repository: tornadoweb/tornado
Pull request #1355 (2015-02-28 17:19:49)

Define Condition's and Event's repr, not str.
Consistent with asyncio's Condition and Event.


Patch:
diff --git a/tornado/locks.py b/tornado/locks.py
index 1367e1de..f941a89c 100644
--- a/tornado/locks.py
+++ b/tornado/locks.py
@@ -34,7 +34,7 @@ class Condition(object):
         self._waiters = collections.deque()  # Futures.
         self._timeouts = 0
 
-    def __str__(self):
+    def __repr__(self):
         result = '<%s' % (self.__class__.__name__, )
         if self._waiters:
             result += ' waiters[%s]' % len(self._waiters)
@@ -89,7 +89,7 @@ class Event(object):
     def __init__(self):
         self._future = Future()
 
-    def __str__(self):
+    def __repr__(self):
         return '<%s %s>' % (
             self.__class__.__name__, 'set' if self.is_set() else 'clear')
 


Test patch:
diff --git a/tornado/test/locks_test.py b/tornado/test/locks_test.py
index 29d80b94..c2930ca3 100644
--- a/tornado/test/locks_test.py
+++ b/tornado/test/locks_test.py
@@ -33,12 +33,12 @@ class ConditionTest(AsyncTestCase):
                 self.history.append(key)
         future.add_done_callback(callback)
 
-    def test_str(self):
+    def test_repr(self):
         c = locks.Condition()
-        self.assertIn('Condition', str(c))
-        self.assertNotIn('waiters', str(c))
+        self.assertIn('Condition', repr(c))
+        self.assertNotIn('waiters', repr(c))
         c.wait()
-        self.assertIn('waiters', str(c))
+        self.assertIn('waiters', repr(c))
 
     @gen_test
     def test_notify(self):
@@ -170,7 +170,7 @@ class ConditionTest(AsyncTestCase):
 
 
 class EventTest(AsyncTestCase):
-    def test_str(self):
+    def test_repr(self):
         event = locks.Event()
         self.assertTrue('clear' in str(event))
         self.assertFalse('set' in str(event))
@@ -220,15 +220,15 @@ class SemaphoreTest(AsyncTestCase):
     def test_negative_value(self):
         self.assertRaises(ValueError, locks.Semaphore, value=-1)
 
-    def test_str(self):
+    def test_repr(self):
         sem = locks.Semaphore()
-        self.assertIn('Semaphore', str(sem))
-        self.assertIn('unlocked,value:1', str(sem))
+        self.assertIn('Semaphore', repr(sem))
+        self.assertIn('unlocked,value:1', repr(sem))
         sem.acquire()
-        self.assertIn('locked', str(sem))
-        self.assertNotIn('waiters', str(sem))
+        self.assertIn('locked', repr(sem))
+        self.assertNotIn('waiters', repr(sem))
         sem.acquire()
-        self.assertIn('waiters', str(sem))
+        self.assertIn('waiters', repr(sem))
 
     def test_acquire(self):
         sem = locks.Semaphore()
Repository: tornadoweb/tornado
Pull request #1422 (2015-04-19 02:45:33)

Timeouts not deadlines.
The change to the Condition.wait examples is a bugfix. The change to the argument name for Lock.acquire is a judgment call, neither threading.Lock.acquire nor asyncio.Lock.acquire have any timeout argument at all. I think renaming it "timeout" is consistent within Tornado.


Patch:
diff --git a/tornado/locks.py b/tornado/locks.py
index 914187c9..4b0bdb38 100644
--- a/tornado/locks.py
+++ b/tornado/locks.py
@@ -95,12 +95,12 @@ class Condition(_TimeoutGarbageCollector):
         io_loop = ioloop.IOLoop.current()
 
         # Wait up to 1 second for a notification.
-        yield condition.wait(deadline=io_loop.time() + 1)
+        yield condition.wait(timeout=io_loop.time() + 1)
 
-    ...or a `datetime.timedelta` for a deadline relative to the current time::
+    ...or a `datetime.timedelta` for a timeout relative to the current time::
 
         # Wait up to 1 second.
-        yield condition.wait(deadline=datetime.timedelta(seconds=1))
+        yield condition.wait(timeout=datetime.timedelta(seconds=1))
 
     The method raises `tornado.gen.TimeoutError` if there's no notification
     before the deadline.
@@ -433,13 +433,13 @@ class Lock(object):
             self.__class__.__name__,
             self._block)
 
-    def acquire(self, deadline=None):
+    def acquire(self, timeout=None):
         """Attempt to lock. Returns a Future.
 
         Returns a Future, which raises `tornado.gen.TimeoutError` after a
         timeout.
         """
-        return self._block.acquire(deadline)
+        return self._block.acquire(timeout)
 
     def release(self):
         """Unlock.


Test patch:
diff --git a/tornado/test/locks_test.py b/tornado/test/locks_test.py
index 49161287..90bdafaa 100644
--- a/tornado/test/locks_test.py
+++ b/tornado/test/locks_test.py
@@ -448,7 +448,7 @@ class LockTests(AsyncTestCase):
         lock = locks.Lock()
         lock.acquire()
         with self.assertRaises(gen.TimeoutError):
-            yield lock.acquire(deadline=timedelta(seconds=0.01))
+            yield lock.acquire(timeout=timedelta(seconds=0.01))
 
         # Still locked.
         self.assertFalse(lock.acquire().done())
Repository: tornadoweb/tornado
Pull request #1482 (2015-08-07 13:48:50)

Fix error handling in read_until_close
When a callback is supplied, the future is not created. Make sure
it is used only if it was initialized, otherwise we lose the
error that was originally raised.

bdarnell: Thanks for the fix. Can you add a case in iostream_test.py that covers this scenario?

If you rebase or merge your PR to the current master the test failures on travis-ci should go away.

Patch:
diff --git a/tornado/iostream.py b/tornado/iostream.py
index e17786ae..c5d3e2c9 100644
--- a/tornado/iostream.py
+++ b/tornado/iostream.py
@@ -352,7 +352,8 @@ class BaseIOStream(object):
         try:
             self._try_inline_read()
         except:
-            future.add_done_callback(lambda f: f.exception())
+            if future is not None:
+                future.add_done_callback(lambda f: f.exception())
             raise
         return future
 


Test patch:
diff --git a/tornado/test/iostream_test.py b/tornado/test/iostream_test.py
index bc12c818..060f7a45 100644
--- a/tornado/test/iostream_test.py
+++ b/tornado/test/iostream_test.py
@@ -457,6 +457,18 @@ class TestIOStreamMixin(object):
             server.close()
             client.close()
 
+    @unittest.skipIf(mock is None, 'mock package not present')
+    def test_read_until_close_with_error(self):
+        server, client = self.make_iostream_pair()
+        try:
+            with mock.patch('tornado.iostream.BaseIOStream._try_inline_read',
+                            side_effect=IOError('boom')):
+                with self.assertRaisesRegexp(IOError, 'boom'):
+                    client.read_until_close(self.stop)
+        finally:
+            server.close()
+            client.close()
+
     def test_streaming_read_until_close_after_close(self):
         # Same as the preceding test but with a streaming_callback.
         # All data should go through the streaming callback,
Repository: tornadoweb/tornado
Pull request #1689 (2016-04-13 10:19:51)

Avoid uncaught exception when _xsrf argument could not be decoded
This is primarily to avoid the following error in `check_xsrf_cookie` when an user sends invalid cookies:

> TypeError: a bytes-like object is required, not 'NoneType

This fixes the error handling of xsrf cookies last changed by https://github.com/tornadoweb/tornado/pull/1299


Patch:
diff --git a/tornado/web.py b/tornado/web.py
index 8f2acfcc..7380c814 100644
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -1265,6 +1265,8 @@ class RequestHandler(object):
             raise HTTPError(403, "'_xsrf' argument missing from POST")
         _, token, _ = self._decode_xsrf_token(token)
         _, expected_token, _ = self._get_raw_xsrf_token()
+        if not token:
+            raise HTTPError(403, "'_xsrf' argument has invalid format")
         if not _time_independent_equals(utf8(token), utf8(expected_token)):
             raise HTTPError(403, "XSRF cookie does not match POST argument")
 


Test patch:
diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py
index fac23a21..1beb9486 100644
--- a/tornado/test/web_test.py
+++ b/tornado/test/web_test.py
@@ -2490,6 +2490,22 @@ class XSRFTest(SimpleHandlerTestCase):
                 body=urllib_parse.urlencode(dict(_xsrf=self.xsrf_token)))
         self.assertEqual(response.code, 403)
 
+    def test_xsrf_fail_argument_invalid_format(self):
+        with ExpectLog(gen_log, ".*'_xsrf' argument has invalid format"):
+            response = self.fetch(
+                "/", method="POST",
+                headers=self.cookie_headers(),
+                body=urllib_parse.urlencode(dict(_xsrf='3|')))
+        self.assertEqual(response.code, 403)
+
+    def test_xsrf_fail_cookie_invalid_format(self):
+        with ExpectLog(gen_log, ".*XSRF cookie does not match POST"):
+            response = self.fetch(
+                "/", method="POST",
+                headers=self.cookie_headers(token='3|'),
+                body=urllib_parse.urlencode(dict(_xsrf=self.xsrf_token)))
+        self.assertEqual(response.code, 403)
+
     def test_xsrf_fail_cookie_no_body(self):
         with ExpectLog(gen_log, ".*'_xsrf' argument missing"):
             response = self.fetch(
Repository: tornadoweb/tornado
Pull request #1777 (2016-07-22 18:31:07)

web: URLs that cannot be unescaped should be allowed
Fixes a regression in version 4.4

Fixes #1770


Patch:
diff --git a/tornado/web.py b/tornado/web.py
index 479dd245..f54c4d03 100644
--- a/tornado/web.py
+++ b/tornado/web.py
@@ -3059,14 +3059,16 @@ class URLSpec(object):
                 try:
                     unescaped_fragment = re_unescape(fragment)
                 except ValueError as exc:
-                    raise ValueError(exc.args[0] + '; invalid url: %r' % pattern)
+                    # If we can't unescape part of it, we can't
+                    # reverse this url.
+                    return (None, None)
                 pieces.append(unescaped_fragment)
 
         return (''.join(pieces), self.regex.groups)
 
     def reverse(self, *args):
-        assert self._path is not None, \
-            "Cannot reverse url regex " + self.regex.pattern
+        if self._path is None:
+            raise ValueError("Cannot reverse url regex " + self.regex.pattern)
         assert len(args) == self._group_count, "required number of arguments "\
             "not found"
         if not len(args):


Test patch:
diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py
index 745d0fa8..fdd1797c 100644
--- a/tornado/test/web_test.py
+++ b/tornado/test/web_test.py
@@ -2811,3 +2811,26 @@ class ApplicationTest(AsyncTestCase):
 class URLSpecReverseTest(unittest.TestCase):
     def test_reverse(self):
         self.assertEqual('/favicon.ico', url(r'/favicon\.ico', None).reverse())
+        self.assertEqual('/favicon.ico', url(r'^/favicon\.ico$', None).reverse())
+
+    def test_non_reversible(self):
+        # URLSpecs are non-reversible if they include non-constant
+        # regex features outside capturing groups. Currently, this is
+        # only strictly enforced for backslash-escaped character
+        # classes.
+        paths = [
+            r'^/api/v\d+/foo/(\w+)$',
+        ]
+        for path in paths:
+            # A URLSpec can still be created even if it cannot be reversed.
+            url_spec = url(path, None)
+            try:
+                result = url_spec.reverse()
+                self.fail("did not get expected exception when reversing %s. "
+                          "result: %s" % (path, result))
+            except ValueError:
+                pass
+
+    def test_reverse_arguments(self):
+        self.assertEqual('/api/v1/foo/bar',
+                         url(r'^/api/v1/foo/(\w+)$', None).reverse('bar'))
Repository: tornadoweb/tornado
Pull request #1778 (2016-07-22 19:38:47)

Fix for uppercase "Transfer-Encoding" values
As per [RFC 2616 section 3.6](https://tools.ietf.org/html/rfc2616#section-3.6), "Transfer-Encoding" header's value is case-insensitive.

It turned out that Cocoa's NSURLConnection sends `Transfer-Encoding: Chunked` (starting with a capital letter), which makes Tornado ignore the actual request body. 


Patch:
diff --git a/tornado/http1connection.py b/tornado/http1connection.py
index d0e91b82..7ee83161 100644
--- a/tornado/http1connection.py
+++ b/tornado/http1connection.py
@@ -565,7 +565,7 @@ class HTTP1Connection(httputil.HTTPConnection):
 
         if content_length is not None:
             return self._read_fixed_body(content_length, delegate)
-        if headers.get("Transfer-Encoding") == "chunked":
+        if headers.get("Transfer-Encoding", "").lower() == "chunked":
             return self._read_chunked_body(delegate)
         if self.is_client:
             return self._read_body_until_close(delegate)


Test patch:
diff --git a/tornado/test/httpserver_test.py b/tornado/test/httpserver_test.py
index 27052e69..4923152b 100644
--- a/tornado/test/httpserver_test.py
+++ b/tornado/test/httpserver_test.py
@@ -436,6 +436,25 @@ foo=
 bar
 0
 
+""".replace(b"\n", b"\r\n"))
+        read_stream_body(self.stream, self.stop)
+        headers, response = self.wait()
+        self.assertEqual(json_decode(response), {u'foo': [u'bar']})
+
+    def test_chunked_request_uppercase(self):
+        # As per RFC 2616 section 3.6, "Transfer-Encoding" header's value is
+        # case-insensitive.
+        self.stream.write(b"""\
+POST /echo HTTP/1.1
+Transfer-Encoding: Chunked
+Content-Type: application/x-www-form-urlencoded
+
+4
+foo=
+3
+bar
+0
+
 """.replace(b"\n", b"\r\n"))
         read_stream_body(self.stream, self.stop)
         headers, response = self.wait()