Repository: scrapy/scrapy

Issue:
follow_all fails with an empty list of URLs
<!--

Thanks for taking an interest in Scrapy!

If you have a question that starts with "How to...", please see the Scrapy Community page: https://scrapy.org/community/.
The GitHub issue tracker's purpose is to deal with bug reports and feature requests for the project itself.

Keep in mind that by filing an issue, you are expected to comply with Scrapy's Code of Conduct, including treating everyone with respect: https://github.com/scrapy/scrapy/blob/master/CODE_OF_CONDUCT.md

The following is a suggested template to structure your issue, you can find more guidelines at https://doc.scrapy.org/en/latest/contributing.html#reporting-bugs

-->

### Description

`follow_all` with an empty list of urls fails with `ValueError('Please supply exactly one of the following arguments: urls, css, xpath')`

What I would expect instead is just an empty generator of requests. 

### Steps to Reproduce

```py
class Spider(scrapy.Spider):

    def parse(self, response):
        yield from response.follow_all([], self.parse)
```

**Expected behavior:** 

No error is raised

**Actual behavior:**

`ValueError('Please supply exactly one of the following arguments: urls, css, xpath')` exception is raised. 


### Versions

2.0

### Additional context

I think the solution is just a matter of changing this line: https://github.com/scrapy/scrapy/blob/master/scrapy/http/response/text.py#L191


Discussion:

Patch:
diff --git a/scrapy/http/response/text.py b/scrapy/http/response/text.py
index 33a485328..2f0f3820c 100644
--- a/scrapy/http/response/text.py
+++ b/scrapy/http/response/text.py
@@ -188,9 +188,11 @@ class TextResponse(Response):
         selectors from which links cannot be obtained (for instance, anchor tags without an
         ``href`` attribute)
         """
-        arg_count = len(list(filter(None, (urls, css, xpath))))
-        if arg_count != 1:
-            raise ValueError('Please supply exactly one of the following arguments: urls, css, xpath')
+        arguments = [x for x in (urls, css, xpath) if x is not None]
+        if len(arguments) != 1:
+            raise ValueError(
+                "Please supply exactly one of the following arguments: urls, css, xpath"
+            )
         if not urls:
             if css:
                 urls = self.css(css)


Test patch:
diff --git a/tests/test_http_response.py b/tests/test_http_response.py
index be17dfd6b..eafc3560e 100644
--- a/tests/test_http_response.py
+++ b/tests/test_http_response.py
@@ -215,6 +215,10 @@ class BaseResponseTest(unittest.TestCase):
         links = map(Link, absolute)
         self._assert_followed_all_urls(links, absolute)
 
+    def test_follow_all_empty(self):
+        r = self.response_class("http://example.com")
+        self.assertEqual([], list(r.follow_all([])))
+
     def test_follow_all_invalid(self):
         r = self.response_class("http://example.com")
         if self.response_class == Response: