10000 Defer ApplicationDefault init and remove FakeCredential class. · akshatz/firebase-admin-python@ae7d88e · GitHub
[go: up one dir, main page]

Skip to content

Commit ae7d88e

Browse files
committed
Defer ApplicationDefault init and remove FakeCredential class.
1 parent 3c19fe6 commit ae7d88e

File tree

6 files changed

+57
-40
lines changed

6 files changed

+57
-40
lines changed

firebase_admin/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def __init__(self, name, credential, options):
215215
self._options = _AppOptions(options)
216216
self._lock = threading.RLock()
217217
self._services = {}
218-
self._project_id = App._lookup_project_id(self._credential, self._options)
218+
self._project_id = None # Will be lazily-loaded when self.project_id is used.
219219

220220
@classmethod
221221
def _lookup_project_id(cls, credential, options):
@@ -263,6 +263,8 @@ def options(self):
263263

264264
@property
265265
def project_id(self):
266+
if self._project_id is None:
267+
self._project_id = App._lookup_project_id(self._credential, self._options)
266268
return self._project_id
267269

268270
def _get_service(self, name, initializer):

firebase_admin/credentials.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -123,26 +123,40 @@ class ApplicationDefault(Base):
123123
"""A Google Application Default credential."""
124124

125125
def __init__(self):
126-
"""Initializes the Application Default credentials for the current environment.
126+
"""Creates an instance that will use Application Default credentials.
127127
128-
Raises:
129-
google.auth.exceptions.DefaultCredentialsError: If Application Default
130-
credentials cannot be initialized in the current environment.
128+
The credentials will be lazily initialized when get_credential() or
129+
project_id() is called. See those methods for possible errors raised.
131130
"""
132131
super(ApplicationDefault, self).__init__()
133-
self._g_credential, self._project_id = google.auth.default(scopes=_scopes)
132+
self._g_credential = None # Will be lazily-loaded via _load_credential().
134133

135134
def get_credential(self):
136135
"""Returns the underlying Google credential.
137136
137+
Raises:
138+
google.auth.exceptions.DefaultCredentialsError: If Application Default
139+
credentials cannot be initialized in the current environment.
138140
Returns:
139141
google.auth.credentials.Credentials: A Google Auth credential instance."""
142+
self._load_credential()
140143
return self._g_credential
141144

142145
@property
143146
def project_id(self):
147+
"""Returns the project_id from the underlying Google credential.
148+
149+
Raises:
150+
google.auth.exceptions.DefaultCredentialsError: If Application Default
151+
credentials cannot be initialized in the current environment.
152+
Returns:
153+
str: The project id."""
154+
self._load_credential()
144155
return self._project_id
145156

157+
def _load_credential(self):
158+
if not self._g_credential:
159+
self._g_credential, self._project_id = google.auth.default(scopes=_scopes)
146160

147161
class RefreshToken(Base):
148162
"""A credential initialized from an existing refresh token."""
@@ -199,19 +213,3 @@ def get_credential(self):
199213
Returns:
200214
google.auth.credentials.Credentials: A Google Auth credential instance."""
201215
return self._g_credential
202-
203-
204-
class FakeCredential(Base):
205-
"""Provides fake credentials, which is only accepted in local emulators."""
206-
207-
def get_credential(self):
208-
return _EmulatorAdminCredentials()
209-
210-
211-
class _EmulatorAdminCredentials(google.auth.credentials.Credentials):
212-
def __init__(self):
213-
google.auth.credentials.Credentials.__init__(self)
214-
self.token = 'owner'
215-
216-
def refresh(self, request):
217-
pass

firebase_admin/db.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@
2626
import sys
2727
import threading
2828

29+
import google.auth
2930
import requests
3031
import six
3132
from six.moves import urllib
3233

3334
import firebase_admin
34-
from firebase_admin.credentials import FakeCredential
3535
from firebase_admin import _http_client
3636
from firebase_admin import _sseclient
3737
from firebase_admin import _utils
@@ -809,8 +809,11 @@ def get_client(self, db_url=None):
809809

810810
client_cache_key = (base_url, json.dumps(params, sort_keys=True), use_fake_creds)
811811
if client_cache_key not in self._clients:
812-
credential = FakeCredential() if use_fake_creds else self._credential
813-
client = _Client(credential.get_credential(), base_url, self._timeout, params)
812+
if use_fake_creds:
813+
credential = _EmulatorAdminCredentials()
814+
else:
815+
self._credential.get_credential()
816+
client = _Client(credential, base_url, self._timeout, params)
814817
self._clients[client_cache_key] = client
815818
return self._clients[client_cache_key]
816819

@@ -968,3 +971,12 @@ def extract_error_message(cls, error):
968971
except ValueError:
969972
pass
970973
return '{0}\nReason: {1}'.format(error, error.response.content.decode())
974+
975+
976+
class _EmulatorAdminCredentials(google.auth.credentials.Credentials):
977+
def __init__(self):
978+
google.auth.credentials.Credentials.__init__(self)
979+
self.token = 'owner'
980+
981+
def refresh(self, request):
982+
pass

integration/conftest.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ def pytest_addoption(parser):
2626
'--cert', action='store', help='Service account certificate file for integration tests.')
2727
parser.addoption(
2828
'--apikey', action='store', help='API key file for integration tests.')
29-
parser.addoption(
30-
'--project', action='store', help='Fake Project ID for emulator-based integration tests.')
3129

3230
def _get_cert_path(request):
3331
cert = request.config.getoption('--cert')
@@ -37,9 +35,6 @@ def _get_cert_path(request):
3735
'"--cert" command-line option.')
3836

3937
def integration_conf(request):
40-
project_id = request.config.getoption('--project')
41-
if project_id:
42-
return credentials.FakeCredential(), project_id
4338
cert_path = _get_cert_path(request)
4439
with open(cert_path) as cert:
4540
project_id = json.load(cert).get('project_id')

integration/test_db.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"""Integration tests for firebase_admin.db module."""
1616
import collections
1717
import json
18+
import os
1819

1920
import pytest
2021
import six
@@ -25,6 +26,23 @@
2526
from tests import testutils
2627

2728

29+
def integration_conf(request):
30+
host_override = os.environ.get('FIREBASE_DATABASE_EMULATOR_HOST')
31+
if host_override:
32+
return None, 'fake-project-id'
33+
else:
34+
return conftest.integration_conf(request)
35+
36+
37+
@pytest.fixture(autouse=True, scope='module')
38+
def default_app(request):
39+
cred, project_id = integration_conf(request)
40+
ops = {
41+
'databaseURL' : 'https://{0}.firebaseio.com'.format(project_id),
42+
}
43+
return firebase_admin.initialize_app(cred, ops)
44+
45+
2846
@pytest.fixture(scope='module')
2947
def update_rules():
3048
with open(testutils.resource_filename('dinosaurs_index.json')) as rules_file:
@@ -304,7 +322,7 @@ def test_filter_by_value(self, testref):
304322
@pytest.fixture(scope='module')
305323
def override_app(request, update_rules):
306324
del update_rules
307-
cred, project_id = conftest.integration_conf(request)
325+
cred, project_id = integration_conf(request)
308326
ops = {
309327
'databaseURL' : 'https://{0}.firebaseio.com'.format(project_id),
310328
'databaseAuthVariableOverride' : {'uid' : 'user1'}
@@ -316,7 +334,7 @@ def override_app(request, update_rules):
316334
@pytest.fixture(scope='module')
317335
def none_override_app(request, update_rules):
318336
del update_rules
319-
cred, project_id = conftest.integration_conf(request)
337+
cred, project_id = integration_conf(request)
320338
ops = {
321339
'databaseURL' : 'https://{0}.firebaseio.com'.format(project_id),
322340
'databaseAuthVariableOverride' : None

tox.ini

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,3 @@ commands =
2929
coverage report --show-missing
3030
deps =
3131
{[coverbase]deps}
32-
33-
[testenv:integration_db]
34-
passenv =
35-
FIREBASE_DATABASE_EMULATOR_HOST
36-
basepython = python3
37-
commands = pytest integration/test_db.py --project fake {posargs}
38-
deps =
39-
pytest

0 commit comments

Comments
 (0)
0