Skip to content

Commit 457e65c

Browse files
authored
Add lint CI for Python samples (#1083)
1 parent 2f19a39 commit 457e65c

File tree

20 files changed

+359
-138
lines changed

20 files changed

+359
-138
lines changed

.github/workflows/test_python.yml

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: CI Tests
16+
17+
on:
18+
pull_request:
19+
paths:
20+
- 'Python/**'
21+
22+
push:
23+
paths:
24+
- 'Python/**'
25+
26+
env:
27+
CI: true
28+
29+
jobs:
30+
unit:
31+
runs-on: ubuntu-latest
32+
strategy:
33+
matrix:
34+
python-version:
35+
- "3.10"
36+
- "3.11"
37+
steps:
38+
- uses: actions/checkout@v3
39+
- name: Set up Python ${{ matrix.python-version }}
40+
uses: actions/setup-python@v4
41+
with:
42+
python-version: ${{ matrix.python-version }}
43+
- name: Install dependencies
44+
working-directory: ./Python
45+
run: pip install -r requirements.txt
46+
- name: Lint
47+
working-directory: ./Python
48+
run: black . --exclude=venv --check --diff

Python/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
venv

Python/.style.yapf

-2
This file was deleted.

Python/alerts-to-discord/main.py

+26-15
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,17 @@
2121
crashlytics_fn,
2222
performance_fn,
2323
)
24+
2425
# [END v2import]
2526

2627
import requests
2728

2829
DISCORD_WEBHOOK_URL = params.SecretParam("DISCORD_WEBHOOK_URL")
2930

3031

31-
def post_message_to_discord(bot_name: str, message_body: str,
32-
webhook_url: str) -> requests.Response:
32+
def post_message_to_discord(
33+
bot_name: str, message_body: str, webhook_url: str
34+
) -> requests.Response:
3335
"""Posts a message to Discord with Discord's Webhook API.
3436
3537
Params:
@@ -58,9 +60,10 @@ def post_message_to_discord(bot_name: str, message_body: str,
5860
# [START v2CrashlyticsAlertTrigger]
5961
@crashlytics_fn.on_new_fatal_issue_published(secrets=["DISCORD_WEBHOOK_URL"])
6062
def post_fatal_issue_to_discord(
61-
event: crashlytics_fn.CrashlyticsNewFatalIssueEvent) -> None:
63+
event: crashlytics_fn.CrashlyticsNewFatalIssueEvent,
64+
) -> None:
6265
"""Publishes a message to Discord whenever a new Crashlytics fatal issue occurs."""
63-
# [END v2CrashlyticsAlertTrigger]
66+
# [END v2CrashlyticsAlertTrigger]
6467
# [START v2CrashlyticsEventPayload]
6568
# Construct a helpful message to send to Discord.
6669
app_id = event.app_id
@@ -78,8 +81,9 @@ def post_fatal_issue_to_discord(
7881

7982
try:
8083
# [START v2SendToDiscord]
81-
response = post_message_to_discord("Crashlytics Bot", message,
82-
DISCORD_WEBHOOK_URL.value())
84+
response = post_message_to_discord(
85+
"Crashlytics Bot", message, DISCORD_WEBHOOK_URL.value()
86+
)
8387
if response.ok:
8488
print(
8589
f"Posted fatal Crashlytics alert {issue.id} for {app_id} to Discord."
@@ -97,11 +101,13 @@ def post_fatal_issue_to_discord(
97101

98102
# [START v2AppDistributionAlertTrigger]
99103
@app_distribution_fn.on_new_tester_ios_device_published(
100-
secrets=["DISCORD_WEBHOOK_URL"])
104+
secrets=["DISCORD_WEBHOOK_URL"]
105+
)
101106
def post_new_udid_to_discord(
102-
event: app_distribution_fn.NewTesterDeviceEvent) -> None:
107+
event: app_distribution_fn.NewTesterDeviceEvent,
108+
) -> None:
103109
"""Publishes a message to Discord whenever someone registers a new iOS test device."""
104-
# [END v2AppDistributionAlertTrigger]
110+
# [END v2AppDistributionAlertTrigger]
105111
# [START v2AppDistributionEventPayload]
106112
# Construct a helpful message to send to Discord.
107113
app_id = event.app_id
@@ -115,8 +121,9 @@ def post_new_udid_to_discord(
115121

116122
try:
117123
# [START v2SendNewTesterIosDeviceToDiscord]
118-
response = post_message_to_discord("App Distro Bot", message,
119-
DISCORD_WEBHOOK_URL.value())
124+
response = post_message_to_discord(
125+
"App Distro Bot", message, DISCORD_WEBHOOK_URL.value()
126+
)
120127
if response.ok:
121128
print(
122129
f"Posted iOS device registration alert for {app_dist.tester_email} to Discord."
@@ -135,9 +142,10 @@ def post_new_udid_to_discord(
135142
# [START v2PerformanceAlertTrigger]
136143
@performance_fn.on_threshold_alert_published(secrets=["DISCORD_WEBHOOK_URL"])
137144
def post_performance_alert_to_discord(
138-
event: performance_fn.PerformanceThresholdAlertEvent) -> None:
145+
event: performance_fn.PerformanceThresholdAlertEvent,
146+
) -> None:
139147
"""Publishes a message to Discord whenever a performance threshold alert is fired."""
140-
# [END v2PerformanceAlertTrigger]
148+
# [END v2PerformanceAlertTrigger]
141149
# [START v2PerformanceEventPayload]
142150
# Construct a helpful message to send to Discord.
143151
app_id = event.app_id
@@ -159,8 +167,9 @@ def post_performance_alert_to_discord(
159167

160168
try:
161169
# [START v2SendPerformanceAlertToDiscord]
162-
response = post_message_to_discord("App Performance Bot", message,
163-
DISCORD_WEBHOOK_URL.value())
170+
response = post_message_to_discord(
171+
"App Performance Bot", message, DISCORD_WEBHOOK_URL.value()
172+
)
164173
if response.ok:
165174
print(
166175
f"Posted Firebase Performance alert {perf.event_name} to Discord."
@@ -174,4 +183,6 @@ def post_performance_alert_to_discord(
174183
f"Unable to post Firebase Performance alert {perf.event_name} to Discord.",
175184
error,
176185
)
186+
187+
177188
# [END v2Alerts]

Python/delete-unused-accounts-cron/main.py

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def accountcleanup(event: scheduler_fn.ScheduledEvent) -> None:
4242
]
4343
auth.delete_users(inactive_uids)
4444
user_page = user_page.get_next_page()
45+
46+
4547
# [END accountcleanup]
4648

4749

@@ -57,4 +59,6 @@ def is_inactive(user: auth.UserRecord, inactive_limit: timedelta) -> bool:
5759
last_seen = datetime.fromtimestamp(last_seen_timestamp)
5860
inactive_time = datetime.now() - last_seen
5961
return inactive_time >= inactive_limit
62+
63+
6064
# [END all]

Python/http-flask/main.py

+6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
# Build multiple CRUD interfaces:
2424

25+
2526
@app.get("/widgets")
2627
@app.get("/widgets/<id>")
2728
def get_widget(id=None):
@@ -30,16 +31,21 @@ def get_widget(id=None):
3031
else:
3132
return db.reference("/widgets").get()
3233

34+
3335
@app.post("/widgets")
3436
def add_widget():
3537
new_widget = flask.request.get_data(as_text=True)
3638
db.reference("/widgets").push(new_widget)
3739
return flask.Response(status=201, response="Added widget")
3840

41+
3942
# Expose Flask app as a single Cloud Function:
4043

44+
4145
@https_fn.on_request()
4246
def httpsflaskexample(req: https_fn.Request) -> https_fn.Response:
4347
with app.request_context(req.environ):
4448
return app.full_dispatch_request()
49+
50+
4551
# [END httpflaskexample]

Python/post-signup-event/main.py

+37-14
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,21 @@ def savegoogletoken(
4141
4242
https://console.firebase.google.com/project/_/authentication/settings
4343
"""
44-
if event.credential is not None and event.credential.provider_id == "google.com":
45-
print(f"Signed in with {event.credential.provider_id}. Saving access token.")
46-
44+
if (
45+
event.credential is not None
46+
and event.credential.provider_id == "google.com"
47+
):
48+
print(
49+
f"Signed in with {event.credential.provider_id}. Saving access token."
50+
)
51+
4752
firestore_client: google.cloud.firestore.Client = firestore.client()
48-
doc_ref = firestore_client.collection("user_info").document(event.data.uid)
49-
doc_ref.set({"calendar_access_token": event.credential.access_token}, merge=True)
53+
doc_ref = firestore_client.collection("user_info").document(
54+
event.data.uid
55+
)
56+
doc_ref.set(
57+
{"calendar_access_token": event.credential.access_token}, merge=True
58+
)
5059

5160
tasks_client = google.cloud.tasks_v2.CloudTasksClient()
5261
task_queue = tasks_client.queue_path(
@@ -65,14 +74,16 @@ def savegoogletoken(
6574
schedule_time=datetime.now() + timedelta(minutes=1),
6675
)
6776
tasks_client.create_task(parent=task_queue, task=calendar_task)
77+
78+
6879
# [END savegoogletoken]
6980

7081

7182
# [START scheduleonboarding]
7283
@tasks_fn.on_task_dispatched()
7384
def scheduleonboarding(request: tasks_fn.CallableRequest) -> https_fn.Response:
7485
"""Add an onboarding event to a user's Google Calendar.
75-
86+
7687
Retrieves and deletes the access token that was saved to Cloud Firestore.
7788
"""
7889

@@ -91,18 +102,22 @@ def scheduleonboarding(request: tasks_fn.CallableRequest) -> https_fn.Response:
91102
)
92103

93104
firestore_client: google.cloud.firestore.Client = firestore.client()
94-
user_info = firestore_client.collection("user_info").document(uid).get().to_dict()
105+
user_info = (
106+
firestore_client.collection("user_info").document(uid).get().to_dict()
107+
)
95108
if "calendar_access_token" not in user_info:
96109
return https_fn.Response(
97110
status=https_fn.FunctionsErrorCode.PERMISSION_DENIED,
98111
response="No Google OAuth token found.",
99112
)
100113
calendar_access_token = user_info["calendar_access_token"]
101-
firestore_client.collection("user_info").document(uid).update({
102-
"calendar_access_token": google.cloud.firestore.DELETE_FIELD
103-
})
114+
firestore_client.collection("user_info").document(uid).update(
115+
{"calendar_access_token": google.cloud.firestore.DELETE_FIELD}
116+
)
104117

105-
google_credentials = google.oauth2.credentials.Credentials(token=calendar_access_token)
118+
google_credentials = google.oauth2.credentials.Credentials(
119+
token=calendar_access_token
120+
)
106121

107122
calendar_client = googleapiclient.discovery.build(
108123
"calendar", "v3", credentials=google_credentials
@@ -116,15 +131,21 @@ def scheduleonboarding(request: tasks_fn.CallableRequest) -> https_fn.Response:
116131
"timeZone": "America/Los_Angeles",
117132
},
118133
"end": {
119-
"dateTime": (datetime.now() + timedelta(days=3, hours=1)).isoformat(),
134+
"dateTime": (
135+
datetime.now() + timedelta(days=3, hours=1)
136+
).isoformat(),
120137
"timeZone": "America/Los_Angeles",
121138
},
122139
"attendees": [
123140
{"email": user_record.email},
124141
{"email": "[email protected]"},
125142
],
126143
}
127-
calendar_client.events().insert(calendarId="primary", body=calendar_event).execute()
144+
calendar_client.events().insert(
145+
calendarId="primary", body=calendar_event
146+
).execute()
147+
148+
128149
# [END scheduleonboarding]
129150

130151

@@ -143,7 +164,9 @@ def get_function_url(
143164
credentials, project_id = google.auth.default(
144165
scopes=["https://www.googleapis.com/auth/cloud-platform"]
145166
)
146-
authed_session = google.auth.transport.requests.AuthorizedSession(credentials)
167+
authed_session = google.auth.transport.requests.AuthorizedSession(
168+
credentials
169+
)
147170
url = (
148171
"https://cloudfunctions.googleapis.com/v2beta/"
149172
+ f"projects/{project_id}/locations/{location}/functions/{name}"

Python/pyproject.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2023 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
[project]
16+
name = "functions_samples"
17+
version = "1.0.0"
18+
[tool.black]
19+
line-length = 80
20+
[tool.mypy]
21+
python_version = "3.10"

0 commit comments

Comments
 (0)