Repository: scrapy/scrapy

Issue:
Request doesn't set callback to self.parse automatically when errback is set
Hi, I'm facing an `AssertionError` when set `errback`  and not `callback` in `Request`, is that expected? :

```
...
    def start_requests(self):
        yield Request(
            self.start_url,
            # callback=self.parse,
            errback=self.parse_error,
            meta={
                'dont_redirect': True,
            },
        )
...
```
trigger this : 
```
2019-01-16 15:47:22 [scrapy.core.engine] ERROR: Error while obtaining start requests
Traceback (most recent call last):
  File "/home/joaquin/Repos/example/env/lib/python3.6/site-packages/scrapy/core/engine.py", line 127, in _next_request
    request = next(slot.start_requests)
  File "/home/joaquin/Repos/example/example/spiders/br/rj/example.py", line 128, in start_requests
    'dont_redirect': True,
  File "/home/joaquin/Repos/example/env/lib/python3.6/site-packages/scrapy/http/request/__init__.py", line 34, in __init__
    assert callback or not errback, "Cannot use errback without a callback"
AssertionError: Cannot use errback without a callback
2019-01-16 15:47:22 [scrapy.core.engine] INFO: Closing spider (finished)
2019-01-16 15:47:22 [scrapy.core.engine] INFO: Spider closed (finished)
```


Discussion:
when errback is set, callback must be set explicitly.
Hi @RomiVu, thanks for help :pray:. I cannot found a clarification about that in documentation, what I found so far: 

> callback (callable) – the function that will be called with the response of this request (once its downloaded) as its first parameter. For more information see Passing additional data to callback functions below. If a Request doesn’t specify a callback, the spider’s parse() method will be used. Note that if exceptions are raised during processing, errback is called instead
From https://doc.scrapy.org/en/latest/topics/request-response.html. 

If it's expected that ever `errback` is set also `callback` **must** be set, I think that it should be documented.

Resolving patch:
diff --git a/scrapy/http/request/__init__.py b/scrapy/http/request/__init__.py
--- a/scrapy/http/request/__init__.py
+++ b/scrapy/http/request/__init__.py
@@ -32,7 +32,6 @@ def __init__(self, url, callback=None, method='GET', headers=None, body=None,
             raise TypeError('callback must be a callable, got %s' % type(callback).__name__)
         if errback is not None and not callable(errback):
             raise TypeError('errback must be a callable, got %s' % type(errback).__name__)
-        assert callback or not errback, "Cannot use errback without a callback"
         self.callback = callback
         self.errback = errback
 


Test patch:
diff --git a/tests/test_http_request.py b/tests/test_http_request.py
--- a/tests/test_http_request.py
+++ b/tests/test_http_request.py
@@ -246,25 +246,41 @@ def test_immutable_attributes(self):
         self.assertRaises(AttributeError, setattr, r, 'url', 'http://example2.com')
         self.assertRaises(AttributeError, setattr, r, 'body', 'xxx')
 
-    def test_callback_is_callable(self):
+    def test_callback_and_errback(self):
         def a_function():
             pass
-        r = self.request_class('http://example.com')
-        self.assertIsNone(r.callback)
-        r = self.request_class('http://example.com', a_function)
-        self.assertIs(r.callback, a_function)
-        with self.assertRaises(TypeError):
-            self.request_class('http://example.com', 'a_function')
 
-    def test_errback_is_callable(self):
-        def a_function():
-            pass
-        r = self.request_class('http://example.com')
-        self.assertIsNone(r.errback)
-        r = self.request_class('http://example.com', a_function, errback=a_function)
-        self.assertIs(r.errback, a_function)
+        r1 = self.request_class('http://example.com')
+        self.assertIsNone(r1.callback)
+        self.assertIsNone(r1.errback)
+
+        r2 = self.request_class('http://example.com', callback=a_function)
+        self.assertIs(r2.callback, a_function)
+        self.assertIsNone(r2.errback)
+
+        r3 = self.request_class('http://example.com', errback=a_function)
+        self.assertIsNone(r3.callback)
+        self.assertIs(r3.errback, a_function)
+
+        r4 = self.request_class(
+            url='http://example.com',
+            callback=a_function,
+            errback=a_function,
+        )
+        self.assertIs(r4.callback, a_function)
+        self.assertIs(r4.errback, a_function)
+
+    def test_callback_and_errback_type(self):
+        with self.assertRaises(TypeError):
+            self.request_class('http://example.com', callback='a_function')
         with self.assertRaises(TypeError):
-            self.request_class('http://example.com', a_function, errback='a_function')
+            self.request_class('http://example.com', errback='a_function')
+        with self.assertRaises(TypeError):
+            self.request_class(
+                url='http://example.com',
+                callback='a_function',
+                errback='a_function',
+            )
 
     def test_from_curl(self):
         # Note: more curated tests regarding curl conversion are in