Skip to content

Commit 14e5dc4

Browse files
authored
Reading project ID from GOOGLE_CLOUD_PROJECT (#176)
* Reading project ID from GOOGLE_CLOUD_PROJECT * Updated changelog * Renamed local variable for clarity
1 parent 4cf7374 commit 14e5dc4

12 files changed

+60
-64
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22

3-
-
3+
- [added] Admin SDK can now read the project ID from both `GCLOUD_PROJECT` and
4+
`GOOGLE_CLOUD_PROJECT` environment variables.
45

56
# v2.11.0
67

firebase_admin/__init__.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ def _lookup_project_id(cls, credential, options):
223223
224224
This method first inspects the app options for a ``projectId`` entry. Then it attempts to
225225
get the project ID from the credential used to initialize the app. If that also fails,
226-
attempts to look up the ``GCLOUD_PROJECT`` environment variable.
226+
attempts to look up the ``GOOGLE_CLOUD_PROJECT`` and ``GCLOUD_PROJECT`` environment
227+
variables.
227228
228229
Args:
229230
credential: A Firebase credential instance.
@@ -235,18 +236,18 @@ def _lookup_project_id(cls, credential, options):
235236
Raises:
236237
ValueError: If a non-string project ID value is specified.
237238
"""
238-
pid = options.get('projectId')
239-
if not pid:
239+
project_id = options.get('projectId')
240+
if not project_id:
240241
try:
241-
pid = credential.project_id
242+
project_id = credential.project_id
242243
except AttributeError:
243244
pass
244-
if not pid:
245-
pid = os.environ.get('GCLOUD_PROJECT')
246-
if pid is not None and not isinstance(pid, six.string_types):
245+
if not project_id:
246+
project_id = os.environ.get('GOOGLE_CLOUD_PROJECT', os.environ.get('GCLOUD_PROJECT'))
247+
if project_id is not None and not isinstance(project_id, six.string_types):
247248
raise ValueError(
248-
'Invalid project ID: "{0}". project ID must be a string.'.format(pid))
249-
return pid
249+
'Invalid project ID: "{0}". project ID must be a string.'.format(project_id))
250+
return project_id
250251

251252
@property
252253
def name(self):

firebase_admin/_token_gen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def verify(self, token, request):
199199
'Failed to ascertain project ID from the credential or the environment. Project '
200200
'ID is required to call {0}. Initialize the app with a credentials.Certificate '
201201
'or set your Firebase project ID as an app option. Alternatively set the '
202-
'GCLOUD_PROJECT environment variable.'.format(self.operation))
202+
'GOOGLE_CLOUD_PROJECT environment variable.'.format(self.operation))
203203

204204
header = jwt.decode_header(token)
205205
payload = jwt.decode(token, verify=False)

firebase_admin/firestore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,6 @@ def from_app(cls, app):
7171
if not project:
7272
raise ValueError(
7373
'Project ID is required to access Firestore. Either set the projectId option, '
74-
'or use service account credentials. Alternatively, set the GCLOUD_PROJECT '
74+
'or use service account credentials. Alternatively, set the GOOGLE_CLOUD_PROJECT '
7575
'environment variable.')
7676
return _FirestoreClient(credentials, project)

firebase_admin/instance_id.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def __init__(self, app):
7878
raise ValueError(
7979
'Project ID is required to access Instance ID service. Either set the projectId '
8080
'option, or use service account credentials. Alternatively, set the '
81-
'GCLOUD_PROJECT environment variable.')
81+
'GOOGLE_CLOUD_PROJECT environment variable.')
8282
self._project_id = project_id
8383
self._client = _http_client.JsonHttpClient(
8484
credential=app.credential.get_credential(), base_url=_IID_SERVICE_URL)

firebase_admin/messaging.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,9 +759,9 @@ def __init__(self, app):
759759
project_id = app.project_id
760760
if not project_id:
761761
raise ValueError(
762-
'Project ID is required to access Cloud Messaging service. Either set the'
763-
' projectId option, or use service account credentials. Alternatively, set the '
764-
'GCLOUD_PROJECT environment variable.')
762+
'Project ID is required to access Cloud Messaging service. Either set the '
763+
'projectId option, or use service account credentials. Alternatively, set the '
764+
'GOOGLE_CLOUD_PROJECT environment variable.')
765765
self._fcm_url = _MessagingService.FCM_URL.format(project_id)
766766
self._client = _http_client.JsonHttpClient(credential=app.credential.get_credential())
767767
self._timeout = app.options.get('httpTimeout')

tests/test_app.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
CREDENTIAL = credentials.Certificate(
2727
testutils.resource_filename('service_account.json'))
28-
GCLOUD_PROJECT = 'GCLOUD_PROJECT'
2928
CONFIG_JSON = firebase_admin._FIREBASE_CONFIG_ENV_VAR
3029

3130
# This fixture will ignore the environment variable pointing to the default
@@ -295,27 +294,26 @@ def test_project_id_from_credentials(self):
295294
assert app.project_id == 'mock-project-id'
296295

297296
def test_project_id_from_environment(self):
298-
project_id = os.environ.get(GCLOUD_PROJECT)
299-
os.environ[GCLOUD_PROJECT] = 'env-project'
300-
try:
301-
app = firebase_admin.initialize_app(testutils.MockCredential(), name='myApp')
302-
assert app.project_id == 'env-project'
303-
finally:
304-
if project_id:
305-
os.environ[GCLOUD_PROJECT] = project_id
306-
else:
307-
del os.environ[GCLOUD_PROJECT]
297+
variables = ['GOOGLE_CLOUD_PROJECT', 'GCLOUD_PROJECT']
298+
for idx, var in enumerate(variables):
299+
old_project_id = os.environ.get(var)
300+
new_project_id = 'env-project-{0}'.format(idx)
301+
os.environ[var] = new_project_id
302+
try:
303+
app = firebase_admin.initialize_app(
304+
testutils.MockCredential(), name='myApp{0}'.format(var))
305+
assert app.project_id == new_project_id
306+
finally:
307+
if old_project_id:
308+
os.environ[var] = old_project_id
309+
else:
310+
del os.environ[var]
308311

309312
def test_no_project_id(self):
310-
project_id = os.environ.get(GCLOUD_PROJECT)
311-
if project_id:
312-
del os.environ[GCLOUD_PROJECT]
313-
try:
313+
def evaluate():
314314
app = firebase_admin.initialize_app(testutils.MockCredential(), name='myApp')
315315
assert app.project_id is None
316-
finally:
317-
if project_id:
318-
os.environ[GCLOUD_PROJECT] = project_id
316+
testutils.run_without_project_id(evaluate)
319317

320318
def test_non_string_project_id(self):
321319
options = {'projectId': {'key': 'not a string'}}

tests/test_firestore.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
"""Tests for firebase_admin.firestore."""
1616

17-
import os
18-
1917
import pytest
2018

2119
import firebase_admin
@@ -28,17 +26,11 @@ def teardown_function():
2826
testutils.cleanup_apps()
2927

3028
def test_no_project_id():
31-
env_var = 'GCLOUD_PROJECT'
32-
gcloud_project = os.environ.get(env_var)
33-
if gcloud_project:
34-
del os.environ[env_var]
35-
try:
29+
def evaluate():
3630
firebase_admin.initialize_app(testutils.MockCredential())
3731
with pytest.raises(ValueError):
3832
firestore.client()
39-
finally:
40-
if gcloud_project:
41-
os.environ[env_var] = gcloud_project
33+
testutils.run_without_project_id(evaluate)
4234

4335
def test_project_id():
4436
cred = credentials.Certificate(testutils.resource_filename('service_account.json'))

tests/test_instance_id.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
"""Tests for firebase_admin.instance_id."""
1616

17-
import os
18-
1917
import pytest
2018

2119
import firebase_admin
@@ -47,17 +45,11 @@ def _get_url(self, project_id, iid):
4745
return instance_id._IID_SERVICE_URL + 'project/{0}/instanceId/{1}'.format(project_id, iid)
4846

4947
def test_no_project_id(self):
50-
env_var = 'GCLOUD_PROJECT'
51-
gcloud_project = os.environ.get(env_var)
52-
if gcloud_project:
53-
del os.environ[env_var]
54-
try:
48+
def evaluate():
5549
firebase_admin.initialize_app(testutils.MockCredential())
5650
with pytest.raises(ValueError):
5751
instance_id.delete_instance_id('test')
58-
finally:
59-
if gcloud_project:
60-
os.environ[env_var] = gcloud_project
52+
testutils.run_without_project_id(evaluate)
6153

6254
def test_delete_instance_id(self):
6355
cred = testutils.MockCredential()

tests/test_messaging.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import datetime
1717
import json
1818
import numbers
19-
import os
2019

2120
import pytest
2221
import six
@@ -871,17 +870,11 @@ def _get_url(self, project_id):
871870
return messaging._MessagingService.FCM_URL.format(project_id)
872871

873872
def test_no_project_id(self):
874-
env_var = 'GCLOUD_PROJECT'
875-
gcloud_project = os.environ.get(env_var)
876-
if gcloud_project:
877-
del os.environ[env_var]
878-
try:
873+
def evaluate():
879874
app = firebase_admin.initialize_app(testutils.MockCredential(), name='no_project_id')
880875
with pytest.raises(ValueError):
881876
messaging.send(messaging.Message(topic='foo'), app=app)
882-
finally:
883-
if gcloud_project:
884-
os.environ[env_var] = gcloud_project
877+
testutils.run_without_project_id(evaluate)
885878

886879
@pytest.mark.parametrize('msg', NON_OBJECT_ARGS + [None])
887880
def test_invalid_send(self, msg):

tests/test_token_gen.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,10 @@ def test_project_id_option(self):
328328
finally:
329329
firebase_admin.delete_app(app)
330330

331-
@pytest.mark.parametrize('env_var_app', [{'GCLOUD_PROJECT': 'mock-project-id'}], indirect=True)
331+
@pytest.mark.parametrize('env_var_app', [
332+
{'GCLOUD_PROJECT': 'mock-project-id'},
333+
{'GOOGLE_CLOUD_PROJECT': 'mock-project-id'}
334+
], indirect=True)
332335
def test_project_id_env_var(self, env_var_app):
333336
_overwrite_cert_request(env_var_app, MOCK_REQUEST)
334337
claims = auth.verify_id_token(TEST_ID_TOKEN, env_var_app)

tests/testutils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@ def cleanup_apps():
4141
for app in apps:
4242
firebase_admin.delete_app(app)
4343

44+
def run_without_project_id(func):
45+
env_vars = ['GCLOUD_PROJECT', 'GOOGLE_CLOUD_PROJECT']
46+
env_values = []
47+
for env_var in env_vars:
48+
gcloud_project = os.environ.get(env_var)
49+
if gcloud_project:
50+
del os.environ[env_var]
51+
env_values.append(gcloud_project)
52+
try:
53+
func()
54+
finally:
55+
for idx, env_var in enumerate(env_vars):
56+
gcloud_project = env_values[idx]
57+
if gcloud_project:
58+
os.environ[env_var] = gcloud_project
59+
4460

4561
class MockResponse(transport.Response):
4662
def __init__(self, status, response):

0 commit comments

Comments
 (0)