Skip to content

Commit f71cbef

Browse files
committed
update annotations
1 parent 6555a84 commit f71cbef

34 files changed

+3132
-1434
lines changed

firebase_admin/__init__.py

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,41 @@
1313
# limitations under the License.
1414

1515
"""Firebase Admin SDK for Python."""
16-
import datetime
16+
1717
import json
1818
import os
1919
import threading
20+
from collections.abc import Callable
21+
from typing import Any, Optional, TypeVar, Union, overload
22+
23+
import google.auth.credentials
24+
import google.auth.exceptions
2025

21-
from google.auth.credentials import Credentials as GoogleAuthCredentials
22-
from google.auth.exceptions import DefaultCredentialsError
2326
from firebase_admin import credentials
2427
from firebase_admin.__about__ import __version__
2528

29+
__all__ = (
30+
'App',
31+
'delete_app',
32+
'get_app',
33+
'initialize_app',
34+
)
35+
36+
_T = TypeVar('_T')
2637

27-
_apps = {}
38+
_apps: dict[str, 'App'] = {}
2839
_apps_lock = threading.RLock()
29-
_clock = datetime.datetime.utcnow
3040

3141
_DEFAULT_APP_NAME = '[DEFAULT]'
3242
_FIREBASE_CONFIG_ENV_VAR = 'FIREBASE_CONFIG'
3343
_CONFIG_VALID_KEYS = ['databaseAuthVariableOverride', 'databaseURL', 'httpTimeout', 'projectId',
3444
'storageBucket']
3545

36-
def initialize_app(credential=None, options=None, name=_DEFAULT_APP_NAME):
46+
def initialize_app(
47+
credential: Optional[Union[credentials.Base, google.auth.credentials.Credentials]] = None,
48+
options: Optional[dict[str, Any]] = None,
49+
name: str = _DEFAULT_APP_NAME,
50+
) -> 'App':
3751
"""Initializes and returns a new App instance.
3852
3953
Creates a new App instance using the specified options
@@ -86,7 +100,7 @@ def initialize_app(credential=None, options=None, name=_DEFAULT_APP_NAME):
86100
'you call initialize_app().')
87101

88102

89-
def delete_app(app):
103+
def delete_app(app: 'App') -> None:
90104
"""Gracefully deletes an App instance.
91105
92106
Args:
@@ -113,7 +127,7 @@ def delete_app(app):
113127
'second argument.')
114128

115129

116-
def get_app(name=_DEFAULT_APP_NAME):
130+
def get_app(name: str = _DEFAULT_APP_NAME) -> 'App':
117131
"""Retrieves an App instance by name.
118132
119133
Args:
@@ -147,7 +161,7 @@ def get_app(name=_DEFAULT_APP_NAME):
147161
class _AppOptions:
148162
"""A collection of configuration options for an App."""
149163

150-
def __init__(self, options):
164+
def __init__(self, options: Optional[dict[str, Any]]) -> None:
151165
if options is None:
152166
options = self._load_from_environment()
153167

@@ -157,11 +171,15 @@ def __init__(self, options):
157171
'Options must be a dictionary.')
158172
self._options = options
159173

160-
def get(self, key, default=None):
174+
@overload
175+
def get(self, key: str, default: None = None) -> Optional[Any]: ...
176+
@overload
177+
def get(self, key: str, default: _T) -> _T: ...
178+
def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
161179
"""Returns the option identified by the provided key."""
162180
return self._options.get(key, default)
163181

164-
def _load_from_environment(self):
182+
def _load_from_environment(self) -> dict[str, Any]:
165183
"""Invoked when no options are passed to __init__, loads options from FIREBASE_CONFIG.
166184
167185
If the value of the FIREBASE_CONFIG environment variable starts with "{" an attempt is made
@@ -194,7 +212,12 @@ class App:
194212
common to all Firebase APIs.
195213
"""
196214

197-
def __init__(self, name, credential, options):
215+
def __init__(
216+
self,
217+
name: str,
218+
credential: Union[credentials.Base, google.auth.credentials.Credentials],
219+
options: Optional[dict[str, Any]],
220+
) -> None:
198221
"""Constructs a new App using the provided name and options.
199222
200223
Args:
@@ -211,7 +234,7 @@ def __init__(self, name, credential, options):
211234
'non-empty string.')
212235
self._name = name
213236

214-
if isinstance(credential, GoogleAuthCredentials):
237+
if isinstance(credential, google.auth.credentials.Credentials):
215238
self._credential = credentials._ExternalCredentials(credential) # pylint: disable=protected-access
216239
elif isinstance(credential, credentials.Base):
217240
self._credential = credential
@@ -220,37 +243,38 @@ def __init__(self, name, credential, options):
220243
'with a valid credential instance.')
221244
self._options = _AppOptions(options)
222245
self._lock = threading.RLock()
223-
self._services = {}
246+
self._services: Optional[dict[str, Any]] = {}
224247

225248
App._validate_project_id(self._options.get('projectId'))
226-
self._project_id_initialized = False
249+
self._project_id_initialized: bool = False
227250

228-
@classmethod
229-
def _validate_project_id(cls, project_id):
251+
@staticmethod
252+
def _validate_project_id(project_id: Optional[Any]) -> Optional[str]:
230253
if project_id is not None and not isinstance(project_id, str):
231254
raise ValueError(
232255
f'Invalid project ID: "{project_id}". project ID must be a string.')
256+
return project_id
233257

234258
@property
235-
def name(self):
259+
def name(self) -> str:
236260
return self._name
237261

238262
@property
239-
def credential(self):
263+
def credential(self) -> credentials.Base:
240264
return self._credential
241265

242266
@property
243-
def options(self):
267+
def options(self) -> _AppOptions:
244268
return self._options
245269

246270
@property
247-
def project_id(self):
271+
def project_id(self) -> Optional[str]:
248272
if not self._project_id_initialized:
249273
self._project_id = self._lookup_project_id()
250274
self._project_id_initialized = True
251275
return self._project_id
252276

253-
def _lookup_project_id(self):
277+
def _lookup_project_id(self) -> Optional[str]:
254278
"""Looks up the Firebase project ID associated with an App.
255279
256280
If a ``projectId`` is specified in app options, it is returned. Then tries to
@@ -264,16 +288,16 @@ def _lookup_project_id(self):
264288
project_id = self._options.get('projectId')
265289
if not project_id:
266290
try:
267-
project_id = self._credential.project_id
268-
except (AttributeError, DefaultCredentialsError):
291+
project_id = getattr(self._credential, 'project_id')
292+
except (AttributeError, google.auth.exceptions.DefaultCredentialsError):
269293
pass
270294
if not project_id:
271295
project_id = os.environ.get('GOOGLE_CLOUD_PROJECT',
272296
os.environ.get('GCLOUD_PROJECT'))
273297
App._validate_project_id(self._options.get('projectId'))
274298
return project_id
275299

276-
def _get_service(self, name, initializer):
300+
def _get_service(self, name: str, initializer: Callable[['App'], _T]) -> _T:
277301
"""Returns the service instance identified by the given name.
278302
279303
Services are functional entities exposed by the Admin SDK (e.g. auth, database). Each
@@ -303,15 +327,17 @@ def _get_service(self, name, initializer):
303327
self._services[name] = initializer(self)
304328
return self._services[name]
305329

306-
def _cleanup(self):
330+
def _cleanup(self) -> None:
307331
"""Cleans up any services associated with this App.
308332
309333
Checks whether each service contains a close() method, and calls it if available.
310334
This is to be called when an App is being deleted, thus ensuring graceful termination of
311335
any services started by the App.
312336
"""
313337
with self._lock:
338+
if self._services is None:
339+
return None
314340
for service in self._services.values():
315-
if hasattr(service, 'close') and hasattr(service.close, '__call__'):
341+
if hasattr(service, 'close') and callable(service.close):
316342
service.close()
317343
self._services = None

0 commit comments

Comments
 (0)