Repository: googleapis/python-storage

Issue:
Add Python ConnectionError in list of retry
Hi, Could you add 
https://docs.python.org/3/library/exceptions.html#ConnectionError just like https://github.com/googleapis/python-bigquery/blob/be3c49a72f0e04de4055f5ca7a99f821c2c8f240/google/cloud/bigquery/retry.py#L26 in list of retry

This ConnectionError is seperate from requests.ConnectionError




Discussion:
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F445) for more info**.

<!-- need_author_cla -->
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F445) for more info**.

<!-- need_author_cla -->
tseaver: @googlebot I fixed it.
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F445) for more info**.

<!-- need_author_cla -->
cojenco: @googlebot I fixed it.
google-cla[bot]: We found a Contributor License Agreement for you (the sender of this pull request), but were unable to find agreements for all the commit author(s) or Co-authors.  If you authored these, maybe you used a different email address in the git commits than was used to sign the CLA ([login here](https://cla.developers.google.com/) to double check)?  If these were authored by someone else, then they will need to sign a CLA as well, and confirm that they're okay with these being contributed to Google.
In order to pass this check, please resolve this problem and then comment `@googlebot I fixed it.`. If the bot doesn't comment, it means it doesn't think anything has changed.

ℹ️ **Googlers: [Go here](https://goto.google.com/prinfo/https%3A%2F%2Fgithub.com%2Fgoogleapis%2Fpython-storage%2Fpull%2F445) for more info**.

<!-- need_author_cla -->
tseaver: @cojenco I don't know what the CLAbot is on about.  As a Googler, I believe you can manually clear the `cla: no` label and set `cla: yes` instead.
cojenco: Thanks @tseaver! Manually added the cla label. I'm looking at my configs. So when I commited the suggestion directly on Github, the email logged was a <users.noreply.github.com> account. 
tseaver: Ugh, I tested that syntax at the Python command prompt, where `__buitins__` is a module.  Per the [Python docs for the `builtins` module](https://docs.python.org/3/library/builtins.html), we should probably not rely on it being *either* the module *or* its dict, and instead move to something like:

```python
try:
    ConnectionError
except NameError:
    _HAS_CONNECTION_ERROR = False
else:
    _HAS_CONNECTION_ERROR = True
```

and then use that flag to control the skip:

```python
    @unittest.skipUnless(_HAS_CONNECTION_ERROR, "...")
```

Since my suggestion didn't work out, *and* messed up the CLAbot, maybe it would be best to rebase away 
bcfe2be  and start fresh.

Patch:
diff --git a/google/cloud/storage/retry.py b/google/cloud/storage/retry.py
index e17f3d5..7b9626e 100644
--- a/google/cloud/storage/retry.py
+++ b/google/cloud/storage/retry.py
@@ -21,7 +21,14 @@ from google.auth import exceptions as auth_exceptions
 import json
 
 
-_RETRYABLE_TYPES = (
+# ConnectionError is a built-in exception only in Python3 and not in Python2.
+try:
+    _RETRYABLE_STDLIB_TYPES = (ConnectionError,)
+except NameError:
+    _RETRYABLE_STDLIB_TYPES = ()
+
+
+_RETRYABLE_TYPES = _RETRYABLE_STDLIB_TYPES + (
     api_exceptions.TooManyRequests,  # 429
     api_exceptions.InternalServerError,  # 500
     api_exceptions.BadGateway,  # 502
@@ -30,6 +37,7 @@ _RETRYABLE_TYPES = (
     requests.ConnectionError,
 )
 
+
 # Some retriable errors don't have their own custom exception in api_core.
 _ADDITIONAL_RETRYABLE_STATUS_CODES = (408,)
 


Test patch:
diff --git a/tests/unit/test_retry.py b/tests/unit/test_retry.py
index 582fa80..3111584 100644
--- a/tests/unit/test_retry.py
+++ b/tests/unit/test_retry.py
@@ -19,6 +19,14 @@ from google.cloud.storage import _helpers
 import mock
 
 
+try:
+    ConnectionError
+except NameError:
+    _HAS_STDLIB_CONNECTION_ERROR = False
+else:
+    _HAS_STDLIB_CONNECTION_ERROR = True
+
+
 class Test_should_retry(unittest.TestCase):
     def _call_fut(self, exc):
         from google.cloud.storage import retry
@@ -56,9 +64,22 @@ class Test_should_retry(unittest.TestCase):
         self.assertFalse(self._call_fut(exc))
 
     def test_w_requests_connection_error(self):
+        import requests
+
+        exc = requests.ConnectionError()
+        self.assertTrue(self._call_fut(exc))
+
+    def test_miss_w_stdlib_error(self):
         exc = ValueError("testing")
         self.assertFalse(self._call_fut(exc))
 
+    @unittest.skipUnless(
+        _HAS_STDLIB_CONNECTION_ERROR, "No builtin 'ConnectionError' in Python 2",
+    )
+    def test_w_stdlib_connection_error(self):
+        exc = ConnectionError()
+        self.assertTrue(self._call_fut(exc))
+
 
 class TestConditionalRetryPolicy(unittest.TestCase):
     def _make_one(self, retry_policy, conditional_predicate, required_kwargs):