firebase-functions 0.4.2__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/PKG-INFO +1 -1
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/README.md +7 -6
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/setup.py +2 -2
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/__init__.py +2 -2
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/firestore_fn.py +9 -4
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/identity_fn.py +30 -5
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/logger.py +22 -5
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/options.py +1 -1
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/params.py +6 -2
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/_identity_fn.py +6 -2
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/manifest.py +1 -1
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/PKG-INFO +1 -1
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/requires.txt +2 -2
- firebase_functions-0.4.3/tests/test_logger.py +226 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_manifest.py +1 -1
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_options.py +16 -2
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_params.py +9 -9
- firebase_functions-0.4.2/tests/test_logger.py +0 -81
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/LICENSE +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/pyproject.toml +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/setup.cfg +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/__init__.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/app_distribution_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/billing_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/crashlytics_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/performance_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/core.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/db_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/eventarc_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/https_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/__init__.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/_alerts_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/path_pattern.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/serving.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/token_verifier.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/util.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/pubsub_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/py.typed +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/remote_config_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/scheduler_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/storage_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/tasks_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/test_lab_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/SOURCES.txt +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/dependency_links.txt +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/top_level.txt +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_db.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_eventarc_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_firestore_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_https_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_identity_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_init.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_path_pattern.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_pubsub_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_remote_config_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_scheduler_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_storage_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_tasks_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_test_lab_fn.py +0 -0
- {firebase_functions-0.4.2 → firebase_functions-0.4.3}/tests/test_util.py +0 -0
|
@@ -10,12 +10,12 @@ Learn more about the Firebase SDK for Cloud Functions in the [Firebase documenta
|
|
|
10
10
|
|
|
11
11
|
Here are some resources to get help:
|
|
12
12
|
|
|
13
|
-
- Start with the quickstart: https://firebase.google.com/docs/functions/get-started
|
|
14
|
-
- Go through the guide: https://firebase.google.com/docs/functions
|
|
15
|
-
- Read the full API reference: https://firebase.google.com/docs/reference/functions/2nd-gen/python
|
|
16
|
-
- Browse some examples: https://github.com/firebase/functions-samples
|
|
13
|
+
- Start with the quickstart: <https://firebase.google.com/docs/functions/get-started>
|
|
14
|
+
- Go through the guide: <https://firebase.google.com/docs/functions/>
|
|
15
|
+
- Read the full API reference: <https://firebase.google.com/docs/reference/functions/2nd-gen/python>
|
|
16
|
+
- Browse some examples: <https://github.com/firebase/functions-samples>
|
|
17
17
|
|
|
18
|
-
If the official documentation doesn't help, try asking through our official support channels: https://firebase.google.com/support
|
|
18
|
+
If the official documentation doesn't help, try asking through our official support channels: <https://firebase.google.com/support/>
|
|
19
19
|
|
|
20
20
|
## Usage
|
|
21
21
|
|
|
@@ -36,4 +36,5 @@ To contribute a change, [check out the contributing guide](.github/CONTRIBUTING.
|
|
|
36
36
|
|
|
37
37
|
## License
|
|
38
38
|
|
|
39
|
-
© Google,
|
|
39
|
+
© Google, 2025. Licensed under [Apache License](LICENSE).
|
|
40
|
+
|
|
@@ -19,8 +19,8 @@ from setuptools import find_packages, setup
|
|
|
19
19
|
|
|
20
20
|
install_requires = [
|
|
21
21
|
'flask>=2.1.2', 'functions-framework>=3.0.0', 'firebase-admin>=6.0.0',
|
|
22
|
-
'pyyaml>=6.0', 'typing-extensions>=4.4.0', 'cloudevents
|
|
23
|
-
'flask-cors>=3.0.10', 'pyjwt[crypto]>=2.5.0', 'google-events
|
|
22
|
+
'pyyaml>=6.0', 'typing-extensions>=4.4.0', 'cloudevents>=1.2.0,<2.0.0',
|
|
23
|
+
'flask-cors>=3.0.10', 'pyjwt[crypto]>=2.5.0', 'google-events==0.5.0',
|
|
24
24
|
'google-cloud-firestore>=2.11.0'
|
|
25
25
|
]
|
|
26
26
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Google Inc.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -15,4 +15,4 @@
|
|
|
15
15
|
Firebase Functions for Python.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
__version__ = "0.4.
|
|
18
|
+
__version__ = "0.4.3"
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/firestore_fn.py
RENAMED
|
@@ -169,13 +169,18 @@ def _firestore_endpoint_handler(
|
|
|
169
169
|
firestore_event_data.old_value.create_time,
|
|
170
170
|
firestore_event_data.old_value.update_time,
|
|
171
171
|
)
|
|
172
|
-
|
|
172
|
+
|
|
173
|
+
if event_type in (_event_type_deleted,
|
|
174
|
+
_event_type_deleted_with_auth_context):
|
|
173
175
|
firestore_event_data = _typing.cast(_firestore.DocumentEventData,
|
|
174
176
|
old_value_snapshot)
|
|
175
|
-
if event_type
|
|
177
|
+
if event_type in (_event_type_created,
|
|
178
|
+
_event_type_created_with_auth_context):
|
|
176
179
|
firestore_event_data = _typing.cast(_firestore.DocumentEventData,
|
|
177
180
|
value_snapshot)
|
|
178
|
-
if event_type in (_event_type_written, _event_type_updated
|
|
181
|
+
if event_type in (_event_type_written, _event_type_updated,
|
|
182
|
+
_event_type_written_with_auth_context,
|
|
183
|
+
_event_type_updated_with_auth_context):
|
|
179
184
|
firestore_event_data = _typing.cast(
|
|
180
185
|
_firestore.DocumentEventData,
|
|
181
186
|
Change(
|
|
@@ -306,7 +311,7 @@ def on_document_written_with_auth_context(**kwargs
|
|
|
306
311
|
_util.set_func_endpoint_attr(
|
|
307
312
|
on_document_written_with_auth_context_wrapped,
|
|
308
313
|
options._endpoint(
|
|
309
|
-
event_type=
|
|
314
|
+
event_type=_event_type_written_with_auth_context,
|
|
310
315
|
func_name=func.__name__,
|
|
311
316
|
document_pattern=document_pattern,
|
|
312
317
|
),
|
|
@@ -18,6 +18,7 @@ import typing as _typing
|
|
|
18
18
|
import functools as _functools
|
|
19
19
|
import datetime as _dt
|
|
20
20
|
import dataclasses as _dataclasses
|
|
21
|
+
from enum import Enum
|
|
21
22
|
|
|
22
23
|
import firebase_functions.options as _options
|
|
23
24
|
import firebase_functions.private.util as _util
|
|
@@ -238,17 +239,23 @@ class Credential:
|
|
|
238
239
|
"""The user's sign-in method."""
|
|
239
240
|
|
|
240
241
|
|
|
242
|
+
class EmailType(str, Enum):
|
|
243
|
+
EMAIL_SIGN_IN = "EMAIL_SIGN_IN"
|
|
244
|
+
PASSWORD_RESET = "PASSWORD_RESET"
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class SmsType(str, Enum):
|
|
248
|
+
SIGN_IN_OR_SIGN_UP = "SIGN_IN_OR_SIGN_UP"
|
|
249
|
+
MULTI_FACTOR_SIGN_IN = "MULTI_FACTOR_SIGN_IN"
|
|
250
|
+
MULTI_FACTOR_ENROLLMENT = "MULTI_FACTOR_ENROLLMENT"
|
|
251
|
+
|
|
252
|
+
|
|
241
253
|
@_dataclasses.dataclass(frozen=True)
|
|
242
254
|
class AuthBlockingEvent:
|
|
243
255
|
"""
|
|
244
256
|
Defines an auth event for identitytoolkit v2 auth blocking events.
|
|
245
257
|
"""
|
|
246
258
|
|
|
247
|
-
data: AuthUserRecord
|
|
248
|
-
"""
|
|
249
|
-
The UserRecord passed to auth blocking functions from the identity platform.
|
|
250
|
-
"""
|
|
251
|
-
|
|
252
259
|
locale: str | None
|
|
253
260
|
"""
|
|
254
261
|
The application locale. You can set the locale using the client SDK,
|
|
@@ -262,6 +269,13 @@ class AuthBlockingEvent:
|
|
|
262
269
|
Example: 'rWsyPtolplG2TBFoOkkgyg'
|
|
263
270
|
"""
|
|
264
271
|
|
|
272
|
+
event_type: str
|
|
273
|
+
"""
|
|
274
|
+
The event type. This provides information on the event name, such as
|
|
275
|
+
beforeSignIn or beforeCreate, and the associated sign-in method used,
|
|
276
|
+
like Google or email/password.
|
|
277
|
+
"""
|
|
278
|
+
|
|
265
279
|
ip_address: str
|
|
266
280
|
"""
|
|
267
281
|
The IP address of the device the end user is registering or signing in from.
|
|
@@ -280,10 +294,21 @@ class AuthBlockingEvent:
|
|
|
280
294
|
credential: Credential | None
|
|
281
295
|
"""An object containing information about the user's credential."""
|
|
282
296
|
|
|
297
|
+
email_type: EmailType | None
|
|
298
|
+
"""The type of email event."""
|
|
299
|
+
|
|
300
|
+
sms_type: SmsType | None
|
|
301
|
+
"""The type of SMS event."""
|
|
302
|
+
|
|
283
303
|
timestamp: _dt.datetime
|
|
284
304
|
"""
|
|
285
305
|
The time the event was triggered."""
|
|
286
306
|
|
|
307
|
+
data: AuthUserRecord
|
|
308
|
+
"""
|
|
309
|
+
The UserRecord passed to auth blocking functions from the identity platform.
|
|
310
|
+
"""
|
|
311
|
+
|
|
287
312
|
|
|
288
313
|
RecaptchaActionOptions = _typing.Literal["ALLOW", "BLOCK"]
|
|
289
314
|
"""
|
|
@@ -8,6 +8,12 @@ import sys as _sys
|
|
|
8
8
|
import typing as _typing
|
|
9
9
|
import typing_extensions as _typing_extensions
|
|
10
10
|
|
|
11
|
+
# If encoding is not 'utf-8', change it to 'utf-8'.
|
|
12
|
+
if _sys.stdout.encoding != "utf-8":
|
|
13
|
+
_sys.stdout.reconfigure(encoding="utf-8") # type: ignore
|
|
14
|
+
if _sys.stderr.encoding != "utf-8":
|
|
15
|
+
_sys.stderr.reconfigure(encoding="utf-8") # type: ignore
|
|
16
|
+
|
|
11
17
|
|
|
12
18
|
class LogSeverity(str, _enum.Enum):
|
|
13
19
|
"""
|
|
@@ -69,21 +75,32 @@ def _remove_circular(obj: _typing.Any,
|
|
|
69
75
|
if refs is None:
|
|
70
76
|
refs = set()
|
|
71
77
|
|
|
78
|
+
# Check if the object is already in the current recursion stack
|
|
72
79
|
if id(obj) in refs:
|
|
73
80
|
return "[CIRCULAR]"
|
|
74
81
|
|
|
82
|
+
# For non-primitive objects, add the current object's id to the recursion stack
|
|
75
83
|
if not isinstance(obj, (str, int, float, bool, type(None))):
|
|
76
84
|
refs.add(id(obj))
|
|
77
85
|
|
|
86
|
+
# Recursively process the object based on its type
|
|
87
|
+
result: _typing.Any
|
|
78
88
|
if isinstance(obj, dict):
|
|
79
|
-
|
|
89
|
+
result = {
|
|
90
|
+
key: _remove_circular(value, refs) for key, value in obj.items()
|
|
91
|
+
}
|
|
80
92
|
elif isinstance(obj, list):
|
|
81
|
-
|
|
93
|
+
result = [_remove_circular(item, refs) for item in obj]
|
|
82
94
|
elif isinstance(obj, tuple):
|
|
83
|
-
|
|
84
|
-
_remove_circular(value, refs) for _, value in enumerate(obj))
|
|
95
|
+
result = tuple(_remove_circular(item, refs) for item in obj)
|
|
85
96
|
else:
|
|
86
|
-
|
|
97
|
+
result = obj
|
|
98
|
+
|
|
99
|
+
# Remove the object's id from the recursion stack after processing
|
|
100
|
+
if not isinstance(obj, (str, int, float, bool, type(None))):
|
|
101
|
+
refs.remove(id(obj))
|
|
102
|
+
|
|
103
|
+
return result
|
|
87
104
|
|
|
88
105
|
|
|
89
106
|
def _get_write_file(severity: LogSeverity) -> _typing.TextIO:
|
|
@@ -1134,7 +1134,7 @@ class HttpsOptions(RuntimeOptions):
|
|
|
1134
1134
|
invoker = [invoker]
|
|
1135
1135
|
assert len(
|
|
1136
1136
|
invoker
|
|
1137
|
-
)
|
|
1137
|
+
) >= 1, "HttpsOptions: Invalid option for invoker - must be a non-empty list."
|
|
1138
1138
|
assert "" not in invoker, (
|
|
1139
1139
|
"HttpsOptions: Invalid option for invoker - must be a non-empty string."
|
|
1140
1140
|
)
|
|
@@ -344,8 +344,12 @@ class IntParam(Param[int]):
|
|
|
344
344
|
|
|
345
345
|
|
|
346
346
|
@_dataclasses.dataclass(frozen=True)
|
|
347
|
-
class
|
|
348
|
-
"""
|
|
347
|
+
class _FloatParam(Param[float]):
|
|
348
|
+
"""
|
|
349
|
+
A parameter as a float value.
|
|
350
|
+
Marked as private because it is not supported by firebase-tools yet.
|
|
351
|
+
Unmark when it is supported.
|
|
352
|
+
"""
|
|
349
353
|
|
|
350
354
|
@property
|
|
351
355
|
def value(self) -> float:
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/_identity_fn.py
RENAMED
|
@@ -200,17 +200,21 @@ def _credential_from_token_data(token_data: dict[str, _typing.Any],
|
|
|
200
200
|
)
|
|
201
201
|
|
|
202
202
|
|
|
203
|
-
def _auth_blocking_event_from_token_data(
|
|
203
|
+
def _auth_blocking_event_from_token_data(event_type: str,
|
|
204
|
+
token_data: dict[str, _typing.Any]):
|
|
204
205
|
from firebase_functions.identity_fn import AuthBlockingEvent
|
|
205
206
|
return AuthBlockingEvent(
|
|
206
207
|
data=_auth_user_record_from_token_data(token_data["user_record"]),
|
|
207
208
|
locale=token_data.get("locale"),
|
|
209
|
+
event_type=event_type,
|
|
208
210
|
event_id=token_data["event_id"],
|
|
209
211
|
ip_address=token_data["ip_address"],
|
|
210
212
|
user_agent=token_data["user_agent"],
|
|
211
213
|
timestamp=_dt.datetime.fromtimestamp(token_data["iat"]),
|
|
212
214
|
additional_user_info=_additional_user_info_from_token_data(token_data),
|
|
213
215
|
credential=_credential_from_token_data(token_data, _time.time()),
|
|
216
|
+
email_type=token_data.get("email_type"),
|
|
217
|
+
sms_type=token_data.get("sms_type"),
|
|
214
218
|
)
|
|
215
219
|
|
|
216
220
|
|
|
@@ -351,7 +355,7 @@ def before_operation_handler(
|
|
|
351
355
|
raise HttpsError(FunctionsErrorCode.INVALID_ARGUMENT, "Bad Request")
|
|
352
356
|
jwt_token = request.json["data"]["jwt"]
|
|
353
357
|
decoded_token = _token_verifier.verify_auth_blocking_token(jwt_token)
|
|
354
|
-
event = _auth_blocking_event_from_token_data(decoded_token)
|
|
358
|
+
event = _auth_blocking_event_from_token_data(event_type, decoded_token)
|
|
355
359
|
auth_response: BeforeCreateResponse | BeforeSignInResponse | None = _with_init(
|
|
356
360
|
func)(event)
|
|
357
361
|
if not auth_response:
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/manifest.py
RENAMED
|
@@ -241,7 +241,7 @@ def _param_to_spec(
|
|
|
241
241
|
spec_dict["type"] = "boolean"
|
|
242
242
|
elif isinstance(param, _params.IntParam):
|
|
243
243
|
spec_dict["type"] = "int"
|
|
244
|
-
elif isinstance(param, _params.
|
|
244
|
+
elif isinstance(param, _params._FloatParam):
|
|
245
245
|
spec_dict["type"] = "float"
|
|
246
246
|
elif isinstance(param, _params.SecretParam):
|
|
247
247
|
spec_dict["type"] = "secret"
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/requires.txt
RENAMED
|
@@ -3,10 +3,10 @@ functions-framework>=3.0.0
|
|
|
3
3
|
firebase-admin>=6.0.0
|
|
4
4
|
pyyaml>=6.0
|
|
5
5
|
typing-extensions>=4.4.0
|
|
6
|
-
cloudevents
|
|
6
|
+
cloudevents<2.0.0,>=1.2.0
|
|
7
7
|
flask-cors>=3.0.10
|
|
8
8
|
pyjwt[crypto]>=2.5.0
|
|
9
|
-
google-events
|
|
9
|
+
google-events==0.5.0
|
|
10
10
|
google-cloud-firestore>=2.11.0
|
|
11
11
|
|
|
12
12
|
[dev]
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# mypy: ignore-errors
|
|
2
|
+
"""
|
|
3
|
+
Logger module tests.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
import json
|
|
8
|
+
from firebase_functions import logger
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestLogger:
|
|
12
|
+
"""
|
|
13
|
+
Tests for the logger module.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def test_format_should_be_valid_json(self,
|
|
17
|
+
capsys: pytest.CaptureFixture[str]):
|
|
18
|
+
logger.log(foo="bar")
|
|
19
|
+
raw_log_output = capsys.readouterr().out
|
|
20
|
+
try:
|
|
21
|
+
json.loads(raw_log_output)
|
|
22
|
+
except json.JSONDecodeError:
|
|
23
|
+
pytest.fail("Log output was not valid JSON.")
|
|
24
|
+
|
|
25
|
+
def test_log_should_have_severity(self, capsys: pytest.CaptureFixture[str]):
|
|
26
|
+
logger.log(foo="bar")
|
|
27
|
+
raw_log_output = capsys.readouterr().out
|
|
28
|
+
log_output = json.loads(raw_log_output)
|
|
29
|
+
assert "severity" in log_output
|
|
30
|
+
|
|
31
|
+
def test_severity_should_be_debug(self, capsys: pytest.CaptureFixture[str]):
|
|
32
|
+
logger.debug(foo="bar")
|
|
33
|
+
raw_log_output = capsys.readouterr().out
|
|
34
|
+
log_output = json.loads(raw_log_output)
|
|
35
|
+
assert log_output["severity"] == "DEBUG"
|
|
36
|
+
|
|
37
|
+
def test_severity_should_be_notice(self,
|
|
38
|
+
capsys: pytest.CaptureFixture[str]):
|
|
39
|
+
logger.log(foo="bar")
|
|
40
|
+
raw_log_output = capsys.readouterr().out
|
|
41
|
+
log_output = json.loads(raw_log_output)
|
|
42
|
+
assert log_output["severity"] == "NOTICE"
|
|
43
|
+
|
|
44
|
+
def test_severity_should_be_info(self, capsys: pytest.CaptureFixture[str]):
|
|
45
|
+
logger.info(foo="bar")
|
|
46
|
+
raw_log_output = capsys.readouterr().out
|
|
47
|
+
log_output = json.loads(raw_log_output)
|
|
48
|
+
assert log_output["severity"] == "INFO"
|
|
49
|
+
|
|
50
|
+
def test_severity_should_be_warning(self,
|
|
51
|
+
capsys: pytest.CaptureFixture[str]):
|
|
52
|
+
logger.warn(foo="bar")
|
|
53
|
+
raw_log_output = capsys.readouterr().out
|
|
54
|
+
log_output = json.loads(raw_log_output)
|
|
55
|
+
assert log_output["severity"] == "WARNING"
|
|
56
|
+
|
|
57
|
+
def test_severity_should_be_error(self, capsys: pytest.CaptureFixture[str]):
|
|
58
|
+
logger.error(foo="bar")
|
|
59
|
+
raw_log_output = capsys.readouterr().err
|
|
60
|
+
log_output = json.loads(raw_log_output)
|
|
61
|
+
assert log_output["severity"] == "ERROR"
|
|
62
|
+
|
|
63
|
+
def test_log_should_have_message(self, capsys: pytest.CaptureFixture[str]):
|
|
64
|
+
logger.log("bar")
|
|
65
|
+
raw_log_output = capsys.readouterr().out
|
|
66
|
+
log_output = json.loads(raw_log_output)
|
|
67
|
+
assert "message" in log_output
|
|
68
|
+
|
|
69
|
+
def test_log_should_have_other_keys(self,
|
|
70
|
+
capsys: pytest.CaptureFixture[str]):
|
|
71
|
+
logger.log(foo="bar")
|
|
72
|
+
raw_log_output = capsys.readouterr().out
|
|
73
|
+
log_output = json.loads(raw_log_output)
|
|
74
|
+
assert "foo" in log_output
|
|
75
|
+
|
|
76
|
+
def test_message_should_be_space_separated(
|
|
77
|
+
self, capsys: pytest.CaptureFixture[str]):
|
|
78
|
+
logger.log("bar", "qux")
|
|
79
|
+
expected_message = "bar qux"
|
|
80
|
+
raw_log_output = capsys.readouterr().out
|
|
81
|
+
log_output = json.loads(raw_log_output)
|
|
82
|
+
assert log_output["message"] == expected_message
|
|
83
|
+
|
|
84
|
+
def test_remove_circular_references(self,
|
|
85
|
+
capsys: pytest.CaptureFixture[str]):
|
|
86
|
+
# Create an object with a circular reference.
|
|
87
|
+
circ = {"b": "foo"}
|
|
88
|
+
circ["circ"] = circ
|
|
89
|
+
|
|
90
|
+
entry = {
|
|
91
|
+
"severity": "ERROR",
|
|
92
|
+
"message": "testing circular",
|
|
93
|
+
"circ": circ,
|
|
94
|
+
}
|
|
95
|
+
logger.write(entry)
|
|
96
|
+
raw_log_output = capsys.readouterr().err
|
|
97
|
+
log_output = json.loads(raw_log_output)
|
|
98
|
+
|
|
99
|
+
expected = {
|
|
100
|
+
"severity": "ERROR",
|
|
101
|
+
"message": "testing circular",
|
|
102
|
+
"circ": {
|
|
103
|
+
"b": "foo",
|
|
104
|
+
"circ": "[CIRCULAR]"
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
assert log_output == expected
|
|
108
|
+
|
|
109
|
+
def test_remove_circular_references_in_arrays(
|
|
110
|
+
self, capsys: pytest.CaptureFixture[str]):
|
|
111
|
+
# Create an object with a circular reference inside an array.
|
|
112
|
+
circ = {"b": "foo"}
|
|
113
|
+
circ["circ"] = [circ]
|
|
114
|
+
|
|
115
|
+
entry = {
|
|
116
|
+
"severity": "ERROR",
|
|
117
|
+
"message": "testing circular",
|
|
118
|
+
"circ": circ,
|
|
119
|
+
}
|
|
120
|
+
logger.write(entry)
|
|
121
|
+
raw_log_output = capsys.readouterr().err
|
|
122
|
+
log_output = json.loads(raw_log_output)
|
|
123
|
+
|
|
124
|
+
expected = {
|
|
125
|
+
"severity": "ERROR",
|
|
126
|
+
"message": "testing circular",
|
|
127
|
+
"circ": {
|
|
128
|
+
"b": "foo",
|
|
129
|
+
"circ": ["[CIRCULAR]"]
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
assert log_output == expected
|
|
133
|
+
|
|
134
|
+
def test_no_false_circular_for_duplicates(
|
|
135
|
+
self, capsys: pytest.CaptureFixture[str]):
|
|
136
|
+
# Ensure that duplicate objects (used in multiple keys) are not marked as circular.
|
|
137
|
+
obj = {"a": "foo"}
|
|
138
|
+
entry = {
|
|
139
|
+
"severity": "ERROR",
|
|
140
|
+
"message": "testing circular",
|
|
141
|
+
"a": obj,
|
|
142
|
+
"b": obj,
|
|
143
|
+
}
|
|
144
|
+
logger.write(entry)
|
|
145
|
+
raw_log_output = capsys.readouterr().err
|
|
146
|
+
log_output = json.loads(raw_log_output)
|
|
147
|
+
|
|
148
|
+
expected = {
|
|
149
|
+
"severity": "ERROR",
|
|
150
|
+
"message": "testing circular",
|
|
151
|
+
"a": {
|
|
152
|
+
"a": "foo"
|
|
153
|
+
},
|
|
154
|
+
"b": {
|
|
155
|
+
"a": "foo"
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
assert log_output == expected
|
|
159
|
+
|
|
160
|
+
def test_no_false_circular_in_array_duplicates(
|
|
161
|
+
self, capsys: pytest.CaptureFixture[str]):
|
|
162
|
+
# Ensure that duplicate objects in arrays are not falsely detected as circular.
|
|
163
|
+
obj = {"a": "foo"}
|
|
164
|
+
arr = [
|
|
165
|
+
{
|
|
166
|
+
"a": obj,
|
|
167
|
+
"b": obj
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"a": obj,
|
|
171
|
+
"b": obj
|
|
172
|
+
},
|
|
173
|
+
]
|
|
174
|
+
entry = {
|
|
175
|
+
"severity": "ERROR",
|
|
176
|
+
"message": "testing circular",
|
|
177
|
+
"a": arr,
|
|
178
|
+
"b": arr,
|
|
179
|
+
}
|
|
180
|
+
logger.write(entry)
|
|
181
|
+
raw_log_output = capsys.readouterr().err
|
|
182
|
+
log_output = json.loads(raw_log_output)
|
|
183
|
+
|
|
184
|
+
expected = {
|
|
185
|
+
"severity":
|
|
186
|
+
"ERROR",
|
|
187
|
+
"message":
|
|
188
|
+
"testing circular",
|
|
189
|
+
"a": [
|
|
190
|
+
{
|
|
191
|
+
"a": {
|
|
192
|
+
"a": "foo"
|
|
193
|
+
},
|
|
194
|
+
"b": {
|
|
195
|
+
"a": "foo"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"a": {
|
|
200
|
+
"a": "foo"
|
|
201
|
+
},
|
|
202
|
+
"b": {
|
|
203
|
+
"a": "foo"
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
"b": [
|
|
208
|
+
{
|
|
209
|
+
"a": {
|
|
210
|
+
"a": "foo"
|
|
211
|
+
},
|
|
212
|
+
"b": {
|
|
213
|
+
"a": "foo"
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"a": {
|
|
218
|
+
"a": "foo"
|
|
219
|
+
},
|
|
220
|
+
"b": {
|
|
221
|
+
"a": "foo"
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
}
|
|
226
|
+
assert log_output == expected
|
|
@@ -65,7 +65,7 @@ full_stack = _manifest.ManifestStack(
|
|
|
65
65
|
params=[
|
|
66
66
|
_params.BoolParam("BOOL_TEST", default=False),
|
|
67
67
|
_params.IntParam("INT_TEST", description="int_description"),
|
|
68
|
-
_params.
|
|
68
|
+
_params._FloatParam("FLOAT_TEST", immutable=True),
|
|
69
69
|
_params.SecretParam("SECRET_TEST"),
|
|
70
70
|
_params.StringParam("STRING_TEST"),
|
|
71
71
|
_params.ListParam("LIST_TEST", default=["1", "2", "3"]),
|
|
@@ -17,6 +17,7 @@ Options unit tests.
|
|
|
17
17
|
from firebase_functions import options, https_fn
|
|
18
18
|
from firebase_functions import params
|
|
19
19
|
from firebase_functions.private.serving import functions_as_yaml, merge_required_apis
|
|
20
|
+
from pytest import raises
|
|
20
21
|
# pylint: disable=protected-access
|
|
21
22
|
|
|
22
23
|
|
|
@@ -44,7 +45,7 @@ def test_global_options_merged_with_provider_options():
|
|
|
44
45
|
Testing a global option is used when no provider option is set.
|
|
45
46
|
"""
|
|
46
47
|
options.set_global_options(max_instances=66)
|
|
47
|
-
pubsub_options = options.PubSubOptions(topic="foo") #pylint: disable=unexpected-keyword-arg
|
|
48
|
+
pubsub_options = options.PubSubOptions(topic="foo") # pylint: disable=unexpected-keyword-arg
|
|
48
49
|
pubsub_options_dict = pubsub_options._asdict_with_global_options()
|
|
49
50
|
assert (pubsub_options_dict["topic"] == "foo"
|
|
50
51
|
), "'topic' property missing from dict"
|
|
@@ -170,7 +171,7 @@ def test_merge_apis_duplicate_apis():
|
|
|
170
171
|
This test evaluates the merge_required_apis function when the
|
|
171
172
|
input list contains duplicate APIs with different reasons.
|
|
172
173
|
The desired outcome for this test is a list where the duplicate
|
|
173
|
-
APIs are merged properly and reasons are combined.
|
|
174
|
+
APIs are merged properly and reasons are combined.
|
|
174
175
|
This test ensures that the function correctly merges the duplicate
|
|
175
176
|
APIs and combines the reasons associated with them.
|
|
176
177
|
"""
|
|
@@ -217,3 +218,16 @@ def test_merge_apis_duplicate_apis():
|
|
|
217
218
|
for actual_item in merged_apis:
|
|
218
219
|
assert (actual_item in expected_output
|
|
219
220
|
), f"Unexpected item {actual_item} found in the merged list"
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def test_invoker_with_one_element_doesnt_throw():
|
|
224
|
+
options.HttpsOptions(invoker=["public"])._endpoint(func_name="test")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def test_invoker_with_no_element_throws():
|
|
228
|
+
with raises(
|
|
229
|
+
AssertionError,
|
|
230
|
+
match=
|
|
231
|
+
"HttpsOptions: Invalid option for invoker - must be a non-empty list."
|
|
232
|
+
):
|
|
233
|
+
options.HttpsOptions(invoker=[])._endpoint(func_name="test")
|
|
@@ -58,28 +58,28 @@ class TestFloatParams:
|
|
|
58
58
|
def test_float_param_value(self):
|
|
59
59
|
"""Testing if float params correctly returns a value."""
|
|
60
60
|
environ["FLOAT_VALUE_TEST"] = "123.456"
|
|
61
|
-
assert params.
|
|
61
|
+
assert params._FloatParam("FLOAT_VALUE_TEST",).value == 123.456, \
|
|
62
62
|
"Failure, params value != 123.456"
|
|
63
63
|
|
|
64
64
|
def test_float_param_empty_default(self):
|
|
65
65
|
"""Testing if float params defaults to empty float if no value and no default."""
|
|
66
|
-
assert params.
|
|
66
|
+
assert params._FloatParam("FLOAT_DEFAULT_TEST1").value == float(), \
|
|
67
67
|
"Failure, params value is not float"
|
|
68
68
|
|
|
69
69
|
def test_float_param_default(self):
|
|
70
70
|
"""Testing if float param defaults to provided default value."""
|
|
71
|
-
assert params.
|
|
71
|
+
assert params._FloatParam("FLOAT_DEFAULT_TEST2", \
|
|
72
72
|
default=float(456.789)).value == 456.789, \
|
|
73
73
|
"Failure, params default value != 456.789"
|
|
74
74
|
|
|
75
75
|
def test_float_param_equality(self):
|
|
76
76
|
"""Test float equality."""
|
|
77
|
-
assert (params.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
assert (params.
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
assert (params._FloatParam("FLOAT_TEST1", \
|
|
78
|
+
default=123.456).equals(123.456).value \
|
|
79
|
+
is True), "Failure, equality check returned False"
|
|
80
|
+
assert (params._FloatParam("FLOAT_TEST2", \
|
|
81
|
+
default=456.789).equals(123.456).value \
|
|
82
|
+
is False), "Failure, equality check returned False"
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
class TestIntParams:
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Logger module tests.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import pytest
|
|
6
|
-
import json
|
|
7
|
-
from firebase_functions import logger
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class TestLogger:
|
|
11
|
-
"""
|
|
12
|
-
Tests for the logger module.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def test_format_should_be_valid_json(self,
|
|
16
|
-
capsys: pytest.CaptureFixture[str]):
|
|
17
|
-
logger.log(foo="bar")
|
|
18
|
-
raw_log_output = capsys.readouterr().out
|
|
19
|
-
try:
|
|
20
|
-
json.loads(raw_log_output)
|
|
21
|
-
except json.JSONDecodeError:
|
|
22
|
-
pytest.fail("Log output was not valid JSON.")
|
|
23
|
-
|
|
24
|
-
def test_log_should_have_severity(self, capsys: pytest.CaptureFixture[str]):
|
|
25
|
-
logger.log(foo="bar")
|
|
26
|
-
raw_log_output = capsys.readouterr().out
|
|
27
|
-
log_output = json.loads(raw_log_output)
|
|
28
|
-
assert "severity" in log_output
|
|
29
|
-
|
|
30
|
-
def test_severity_should_be_debug(self, capsys: pytest.CaptureFixture[str]):
|
|
31
|
-
logger.debug(foo="bar")
|
|
32
|
-
raw_log_output = capsys.readouterr().out
|
|
33
|
-
log_output = json.loads(raw_log_output)
|
|
34
|
-
assert log_output["severity"] == "DEBUG"
|
|
35
|
-
|
|
36
|
-
def test_severity_should_be_notice(self,
|
|
37
|
-
capsys: pytest.CaptureFixture[str]):
|
|
38
|
-
logger.log(foo="bar")
|
|
39
|
-
raw_log_output = capsys.readouterr().out
|
|
40
|
-
log_output = json.loads(raw_log_output)
|
|
41
|
-
assert log_output["severity"] == "NOTICE"
|
|
42
|
-
|
|
43
|
-
def test_severity_should_be_info(self, capsys: pytest.CaptureFixture[str]):
|
|
44
|
-
logger.info(foo="bar")
|
|
45
|
-
raw_log_output = capsys.readouterr().out
|
|
46
|
-
log_output = json.loads(raw_log_output)
|
|
47
|
-
assert log_output["severity"] == "INFO"
|
|
48
|
-
|
|
49
|
-
def test_severity_should_be_warning(self,
|
|
50
|
-
capsys: pytest.CaptureFixture[str]):
|
|
51
|
-
logger.warn(foo="bar")
|
|
52
|
-
raw_log_output = capsys.readouterr().out
|
|
53
|
-
log_output = json.loads(raw_log_output)
|
|
54
|
-
assert log_output["severity"] == "WARNING"
|
|
55
|
-
|
|
56
|
-
def test_severity_should_be_error(self, capsys: pytest.CaptureFixture[str]):
|
|
57
|
-
logger.error(foo="bar")
|
|
58
|
-
raw_log_output = capsys.readouterr().err
|
|
59
|
-
log_output = json.loads(raw_log_output)
|
|
60
|
-
assert log_output["severity"] == "ERROR"
|
|
61
|
-
|
|
62
|
-
def test_log_should_have_message(self, capsys: pytest.CaptureFixture[str]):
|
|
63
|
-
logger.log("bar")
|
|
64
|
-
raw_log_output = capsys.readouterr().out
|
|
65
|
-
log_output = json.loads(raw_log_output)
|
|
66
|
-
assert "message" in log_output
|
|
67
|
-
|
|
68
|
-
def test_log_should_have_other_keys(self,
|
|
69
|
-
capsys: pytest.CaptureFixture[str]):
|
|
70
|
-
logger.log(foo="bar")
|
|
71
|
-
raw_log_output = capsys.readouterr().out
|
|
72
|
-
log_output = json.loads(raw_log_output)
|
|
73
|
-
assert "foo" in log_output
|
|
74
|
-
|
|
75
|
-
def test_message_should_be_space_separated(
|
|
76
|
-
self, capsys: pytest.CaptureFixture[str]):
|
|
77
|
-
logger.log("bar", "qux")
|
|
78
|
-
expected_message = "bar qux"
|
|
79
|
-
raw_log_output = capsys.readouterr().out
|
|
80
|
-
log_output = json.loads(raw_log_output)
|
|
81
|
-
assert log_output["message"] == expected_message
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/alerts/billing_fn.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/__init__.py
RENAMED
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/_alerts_fn.py
RENAMED
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/path_pattern.py
RENAMED
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/serving.py
RENAMED
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/private/util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/remote_config_fn.py
RENAMED
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions/scheduler_fn.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{firebase_functions-0.4.2 → firebase_functions-0.4.3}/src/firebase_functions.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|