Skip to content

Commit e0457d4

Browse files
authored
Merge pull request googleapis#2970 from dhermes/cnxn-client-hygiene
Making Connection()-s act as proxies for data stored in Client()-s
2 parents d254ab0 + 3407d39 commit e0457d4

File tree

51 files changed

+380
-456
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+380
-456
lines changed

bigquery/google/cloud/bigquery/_http.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919

2020
class Connection(_http.JSONConnection):
21-
"""A connection to Google BigQuery via the JSON REST API."""
21+
"""A connection to Google BigQuery via the JSON REST API.
22+
23+
:type client: :class:`~google.cloud.bigquery.client.Client`
24+
:param client: The client that owns the current connection.
25+
"""
2226

2327
API_BASE_URL = 'https://www.googleapis.com'
2428
"""The base of the API call URL."""
@@ -28,7 +32,3 @@ class Connection(_http.JSONConnection):
2832

2933
API_URL_TEMPLATE = '{api_base_url}/bigquery/{api_version}{path}'
3034
"""A template for the URL of a particular API call."""
31-
32-
SCOPE = ('https://www.googleapis.com/auth/bigquery',
33-
'https://www.googleapis.com/auth/cloud-platform')
34-
"""The scopes required for authenticating as a BigQuery consumer."""

bigquery/google/cloud/bigquery/client.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,14 @@ class Client(ClientWithProject):
7272
``credentials`` for the current object.
7373
"""
7474

75+
SCOPE = ('https://www.googleapis.com/auth/bigquery',
76+
'https://www.googleapis.com/auth/cloud-platform')
77+
"""The scopes required for authenticating as a BigQuery consumer."""
78+
7579
def __init__(self, project=None, credentials=None, http=None):
7680
super(Client, self).__init__(
7781
project=project, credentials=credentials, http=http)
78-
self._connection = Connection(
79-
credentials=self._credentials, http=self._http)
82+
self._connection = Connection(self)
8083

8184
def list_projects(self, max_results=None, page_token=None):
8285
"""List projects for the project associated with this client.

bigquery/unit_tests/test__http.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def _make_one(self, *args, **kw):
2727
return self._get_target_class()(*args, **kw)
2828

2929
def test_build_api_url_no_extra_query_params(self):
30-
conn = self._make_one()
30+
conn = self._make_one(object())
3131
URI = '/'.join([
3232
conn.API_BASE_URL,
3333
'bigquery',
@@ -40,7 +40,7 @@ def test_build_api_url_w_extra_query_params(self):
4040
from six.moves.urllib.parse import parse_qsl
4141
from six.moves.urllib.parse import urlsplit
4242

43-
conn = self._make_one()
43+
conn = self._make_one(object())
4444
uri = conn.build_api_url('/foo', {'bar': 'baz'})
4545
scheme, netloc, path, qs, _ = urlsplit(uri)
4646
self.assertEqual('%s://%s' % (scheme, netloc), conn.API_BASE_URL)

core/google/cloud/_http.py

+6-52
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@
1919
import six
2020
from six.moves.urllib.parse import urlencode
2121

22-
import google.auth.credentials
23-
import google_auth_httplib2
24-
import httplib2
25-
2622
from google.cloud.exceptions import make_exception
2723

2824

@@ -37,50 +33,14 @@
3733
class Connection(object):
3834
"""A generic connection to Google Cloud Platform.
3935
40-
Subclasses should understand only the basic types in method arguments,
41-
however they should be capable of returning advanced types.
42-
43-
If no value is passed in for ``http``, a :class:`httplib2.Http` object
44-
will be created and authorized with the ``credentials``. If not, the
45-
``credentials`` and ``http`` need not be related.
46-
47-
Subclasses may seek to use the private key from ``credentials`` to sign
48-
data.
49-
50-
A custom (non-``httplib2``) HTTP object must have a ``request`` method
51-
which accepts the following arguments:
52-
53-
* ``uri``
54-
* ``method``
55-
* ``body``
56-
* ``headers``
57-
58-
In addition, ``redirections`` and ``connection_type`` may be used.
59-
60-
Without the use of ``credentials.authorize(http)``, a custom ``http``
61-
object will also need to be able to add a bearer token to API
62-
requests and handle token refresh on 401 errors.
63-
64-
:type credentials: :class:`google.auth.credentials.Credentials` or
65-
:class:`NoneType`
66-
:param credentials: The credentials to use for this connection.
67-
68-
:type http: :class:`httplib2.Http` or class that defines ``request()``.
69-
:param http: An optional HTTP object to make requests.
36+
:type client: :class:`~google.cloud.client.Client`
37+
:param client: The client that owns the current connection.
7038
"""
7139

7240
USER_AGENT = DEFAULT_USER_AGENT
7341

74-
SCOPE = None
75-
"""The scopes required for authenticating with a service.
76-
77-
Needs to be set by subclasses.
78-
"""
79-
80-
def __init__(self, credentials=None, http=None):
81-
self._http = http
82-
self._credentials = google.auth.credentials.with_scopes_if_required(
83-
credentials, self.SCOPE)
42+
def __init__(self, client):
43+
self._client = client
8444

8545
@property
8646
def credentials(self):
@@ -90,7 +50,7 @@ def credentials(self):
9050
:class:`NoneType`
9151
:returns: The credentials object associated with this connection.
9252
"""
93-
return self._credentials
53+
return self._client._credentials
9454

9555
@property
9656
def http(self):
@@ -99,13 +59,7 @@ def http(self):
9959
:rtype: :class:`httplib2.Http`
10060
:returns: A Http object used to transport data.
10161
"""
102-
if self._http is None:
103-
if self._credentials:
104-
self._http = google_auth_httplib2.AuthorizedHttp(
105-
self._credentials)
106-
else:
107-
self._http = httplib2.Http()
108-
return self._http
62+
return self._client._http
10963

11064

11165
class JSONConnection(Connection):

core/google/cloud/client.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import google.auth.credentials
1818
from google.oauth2 import service_account
19+
import google_auth_httplib2
1920
import six
2021

2122
from google.cloud._helpers import _determine_default_project
@@ -74,6 +75,26 @@ class Client(_ClientFactoryMixin):
7475
Stores ``credentials`` and ``http`` object so that subclasses
7576
can pass them along to a connection class.
7677
78+
If no value is passed in for ``http``, a :class:`httplib2.Http` object
79+
will be created and authorized with the ``credentials``. If not, the
80+
``credentials`` and ``http`` need not be related.
81+
82+
Callers and subclasses may seek to use the private key from
83+
``credentials`` to sign data.
84+
85+
A custom (non-``httplib2``) HTTP object must have a ``request`` method
86+
which accepts the following arguments:
87+
88+
* ``uri``
89+
* ``method``
90+
* ``body``
91+
* ``headers``
92+
93+
In addition, ``redirections`` and ``connection_type`` may be used.
94+
95+
A custom ``http`` object will also need to be able to add a bearer token
96+
to API requests and handle token refresh on 401 errors.
97+
7798
:type credentials: :class:`~google.auth.credentials.Credentials`
7899
:param credentials: (Optional) The OAuth2 Credentials to use for this
79100
client. If not passed (and if no ``http`` object is
@@ -88,15 +109,34 @@ class Client(_ClientFactoryMixin):
88109
``credentials`` for the current object.
89110
"""
90111

112+
SCOPE = None
113+
"""The scopes required for authenticating with a service.
114+
115+
Needs to be set by subclasses.
116+
"""
117+
91118
def __init__(self, credentials=None, http=None):
92119
if (credentials is not None and
93120
not isinstance(
94121
credentials, google.auth.credentials.Credentials)):
95122
raise ValueError(_GOOGLE_AUTH_CREDENTIALS_HELP)
96123
if credentials is None and http is None:
97124
credentials = get_credentials()
98-
self._credentials = credentials
99-
self._http = http
125+
self._credentials = google.auth.credentials.with_scopes_if_required(
126+
credentials, self.SCOPE)
127+
self._http_internal = http
128+
129+
@property
130+
def _http(self):
131+
"""Getter for object used for HTTP transport.
132+
133+
:rtype: :class:`~httplib2.Http`
134+
:returns: An HTTP object.
135+
"""
136+
if self._http_internal is None:
137+
self._http_internal = google_auth_httplib2.AuthorizedHttp(
138+
self._credentials)
139+
return self._http_internal
100140

101141

102142
class _ClientProjectMixin(object):

0 commit comments

Comments
 (0)