Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
.cache/
.tox/
*.egg-info/
build/
dist/
*~
scripts/cert.json
scripts/apikey.txt
4 changes: 3 additions & 1 deletion firebase_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def initialize_app(credential=None, options=None, name=_DEFAULT_APP_NAME):
Args:
credential: A credential object used to initialize the SDK (optional). If none is provided,
Google Application Default Credentials are used.
options: A dictionary of configuration options (optional).
options: A dictionary of configuration options (optional). Supported options include
``databaseURL``, ``storageBucket`` and ``httpTimeout``. If ``httpTimeout`` is not set,
HTTP connections initiated by client modules such as ``db`` will not timeout.
name: Name of the app (optional).

Returns:
Expand Down
16 changes: 13 additions & 3 deletions firebase_admin/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ class _Client(_http_client.JsonHttpClient):

_DEFAULT_AUTH_OVERRIDE = '_admin_'

def __init__(self, credential, base_url, auth_override=_DEFAULT_AUTH_OVERRIDE):
def __init__(self, credential, base_url, auth_override=_DEFAULT_AUTH_OVERRIDE, timeout=None):
"""Creates a new _Client from the given parameters.

This exists primarily to enable testing. For regular use, obtain _Client instances by
Expand All @@ -686,6 +686,8 @@ def __init__(self, credential, base_url, auth_override=_DEFAULT_AUTH_OVERRIDE):
auth_override: A dictionary representing auth variable overrides or None (optional).
Default value provides admin privileges. A None value here provides un-authenticated
guest privileges.
timeout: HTTP request timeout in seconds (optional). If not set connections will never
timeout, which is the default behavior of the underlying requests library.
"""
_http_client.JsonHttpClient.__init__(
self, credential=credential, base_url=base_url, headers={'User-Agent': _USER_AGENT})
Expand All @@ -694,14 +696,16 @@ def __init__(self, credential, base_url, auth_override=_DEFAULT_AUTH_OVERRIDE):
self._auth_override = 'auth_variable_override={0}'.format(encoded)
else:
self._auth_override = None
self._timeout = timeout

@classmethod
def from_app(cls, app):
"""Creates a new _Client for a given App"""
credential = app.credential.get_credential()
db_url = cls._get_db_url(app)
auth_override = cls._get_auth_override(app)
credential = app.credential.get_credential()
return _Client(credential, db_url, auth_override)
timeout = app.options.get('httpTimeout')
return _Client(credential, db_url, auth_override, timeout)

@classmethod
def _get_db_url(cls, app):
Expand Down Expand Up @@ -737,6 +741,10 @@ def _get_auth_override(cls, app):
def auth_override(self):
return self._auth_override

@property
def timeout(self):
return self._timeout

def request(self, method, url, **kwargs):
"""Makes an HTTP call using the Python requests library.

Expand All @@ -762,6 +770,8 @@ def request(self, method, url, **kwargs):
else:
params = self._auth_override
kwargs['params'] = params
if self._timeout:
kwargs['timeout'] = self._timeout
try:
return super(_Client, self).request(method, url, **kwargs)
except requests.exceptions.RequestException as error:
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pytest >= 3.0.6
pytest-cov >= 2.4.0
tox >= 2.6.0

google-auth >= 1.0.0
google-auth >= 1.1.0
google-cloud-storage >= 1.2.0
requests >= 2.13.0
six >= 1.6.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
long_description = ('The Firebase Admin Python SDK enables server-side (backend) Python developers '
'to integrate Firebase into their services and applications.')
install_requires = [
'google-auth>=1.0.0',
'google-auth>=1.1.0',
'google-cloud-storage>=1.2.0',
'requests>=2.13.0',
'six>=1.6.1'
Expand Down
3 changes: 2 additions & 1 deletion tests/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import google.auth
from google.auth import crypt
from google.auth import exceptions
from google.oauth2 import credentials as gcredentials
from google.oauth2 import service_account
from firebase_admin import credentials
Expand Down Expand Up @@ -114,7 +115,7 @@ def test_init(self, app_default):
indirect=True)
def test_nonexisting_path(self, app_default):
del app_default
with pytest.raises(IOError):
with pytest.raises(exceptions.DefaultCredentialsError):
credentials.ApplicationDefault()


Expand Down
24 changes: 24 additions & 0 deletions tests/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,8 +534,15 @@ def test_no_db_url(self):
def test_valid_db_url(self, url):
firebase_admin.initialize_app(testutils.MockCredential(), {'databaseURL' : url})
ref = db.reference()
recorder = []
adapter = MockAdapter('{}', 200, recorder)
ref._client.session.mount(url, adapter)
assert ref._client.base_url == 'https://test.firebaseio.com'
assert ref._client.auth_override is None
assert ref._client.timeout is None
assert ref.get() == {}
assert len(recorder) == 1
assert recorder[0]._extra_kwargs.get('timeout') is None

@pytest.mark.parametrize('url', [
None, '', 'foo', 'http://test.firebaseio.com', 'https://google.com',
Expand All @@ -554,6 +561,7 @@ def test_valid_auth_override(self, override):
})
ref = db.reference()
assert ref._client.base_url == 'https://test.firebaseio.com'
assert ref._client.timeout is None
if override == {}:
assert ref._client.auth_override is None
else:
Expand All @@ -570,6 +578,22 @@ def test_invalid_auth_override(self, override):
with pytest.raises(ValueError):
db.reference()

def test_http_timeout(self):
test_url = 'https://test.firebaseio.com'
firebase_admin.initialize_app(testutils.MockCredential(), {
'databaseURL' : test_url,
'httpTimeout': 60
})
ref = db.reference()
recorder = []
adapter = MockAdapter('{}', 200, recorder)
ref._client.session.mount(test_url, adapter)
assert ref._client.base_url == test_url
assert ref._client.timeout == 60
assert ref.get() == {}
assert len(recorder) == 1
assert recorder[0]._extra_kwargs['timeout'] == 60

def test_app_delete(self):
app = firebase_admin.initialize_app(
testutils.MockCredential(), {'databaseURL' : 'https://test.firebaseio.com'})
Expand Down
2 changes: 1 addition & 1 deletion tests/testutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def __init__(self, data, status, recorder):
self._recorder = recorder

def send(self, request, **kwargs):
del kwargs
request._extra_kwargs = kwargs
self._recorder.append(request)
resp = models.Response()
resp.url = request.url
Expand Down