Repository: googleapis/google-api-python-client

Issue:
Closing discovery item fails with AttributeError: 'Http' object has no attribute 'http'
The following line fails, looking at httplib2 shouldn't this be `self._http.close()` instead?

https://github.com/googleapis/google-api-python-client/blob/2d076b87cff4029a243357dad19564767bbf8751/googleapiclient/discovery.py#L1335


Discussion:
Hey @ghaithbilbeisi, could you show more of the stack trace?

From discussion in #1047 it looks like the issue is the low version of `httplib2`. I also see that this wouldn't work correctly if you were passing in your own `httplib2` object (in that case it should just be `self._http.close()`). 
Hi @busunkim96 , I get this when running my unittest with the following:

```python
def test_build_drive(self):
    creds = utils.authenticate('client_id.json')
    drive = utils.build_drive(creds)
    self.assertIsNotNone(drive)
    if drive:
        drive.close()
```

Using the following authenticate and build_drive methods:
```python
def authenticate(secret):
    """ Returns an oauth credentials object using the given secret, or stored credentials if available. """
    SCOPES = 'https://www.googleapis.com/auth/drive.readonly'
    store = file.Storage('storage.json')
    creds = store.get()       
            
    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets(secret, SCOPES)
        creds = tools.run_flow(flow, store)
    
    return creds

def build_drive(creds):
    try:
        drive = discovery.build('drive', 'v3', credentials=creds)#http=creds.authorize(Http()))
    except:
        drive = None
    return drive
```

Running this with google-api-python-client 1.12.3, httplib2 0.18.1, and python 3.8.3 gives the following error:

```
Traceback (most recent call last):
  File "token_test.py", line 16, in test_build_drive
    drive.close()
  File "/Users/ghaithbilbeisi/miniconda3/lib/python3.8/site-packages/googleapiclient/discovery.py", line 1335, in close
    self._http.http.close()
AttributeError: 'Http' object has no attribute 'http'
```
I think the proper fix for this is to add `close` to AuthorizedHttp. Opened https://github.com/googleapis/google-auth-library-python-httplib2/pull/14
I'm going to close off this issue as google-auth-httplib2 [0.1.0 ](https://github.com/googleapis/google-auth-library-python-httplib2/releases/tag/v0.1.0) was released on Monday with the fix from https://github.com/googleapis/google-auth-library-python-httplib2/pull/14 . If you're still having trouble after updating google-auth-httplib2, please re-open this issue with more information.
This simple code still raises the same error with latest packages (`google-auth-httplib2 0.1.0`, `httplib2 0.19.0`, `google-api-python-client 2.0.2`).
```python
from googleapiclient.discovery import build

yt = build("youtube", "v3", developerKey="MY_KEY")
yt.close()

```

```error
Traceback (most recent call last):
  File "test_code.py", line 4, in <module>
    yt.close()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/googleapiclient/discovery.py", line 1364, in close
    self._http.http.close()
AttributeError: 'Http' object has no attribute 'http'

Process finished with exit code 1
```

Resolving patch:
diff --git a/googleapiclient/discovery.py b/googleapiclient/discovery.py
--- a/googleapiclient/discovery.py
+++ b/googleapiclient/discovery.py
@@ -1361,7 +1361,7 @@ def close(self):
         # httplib2 leaves sockets open by default.
         # Cleanup using the `close` method.
         # https://github.com/httplib2/httplib2/issues/148
-        self._http.http.close()
+        self._http.close()
 
     def _set_service_methods(self):
         self._add_basic_methods(self._resourceDesc, self._rootDesc, self._schema)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,7 @@
 install_requires = [
     "httplib2>=0.15.0,<1dev",
     "google-auth>=1.16.0,<2dev",
-    "google-auth-httplib2>=0.0.3",
+    "google-auth-httplib2>=0.1.0",
     "google-api-core>=1.21.0,<2dev",
     "six>=1.13.0,<2dev",
     "uritemplate>=3.0.0,<4dev",


Test patch:
diff --git a/tests/test_discovery.py b/tests/test_discovery.py
--- a/tests/test_discovery.py
+++ b/tests/test_discovery.py
@@ -87,6 +87,7 @@
 from oauth2client import GOOGLE_TOKEN_URI
 from oauth2client.client import OAuth2Credentials, GoogleCredentials
 
+
 from googleapiclient import _helpers as util
 
 import uritemplate
@@ -591,14 +592,27 @@ def test_building_with_context_manager(self):
 
     def test_resource_close(self):
         discovery = read_datafile("plus.json")
-        with mock.patch("httplib2.Http") as http:
+        
+        with mock.patch("httplib2.Http", autospec=True) as httplib2_http:
+            http = httplib2_http()
+            plus = build_from_document(
+                discovery,
+                base="https://www.googleapis.com/",
+                http=http,
+            )
+            plus.close()
+            http.close.assert_called_once()
+
+    def test_resource_close_authorized_http(self):
+        discovery = read_datafile("plus.json")
+        with mock.patch("google_auth_httplib2.AuthorizedHttp", autospec=True):
             plus = build_from_document(
                 discovery,
                 base="https://www.googleapis.com/",
                 credentials=self.MOCK_CREDENTIALS,
             )
             plus.close()
-            plus._http.http.close.assert_called_once()
+            plus._http.close.assert_called_once()
 
     def test_api_endpoint_override_from_client_options(self):
         discovery = read_datafile("plus.json")