-
Notifications
You must be signed in to change notification settings - Fork 6.7k
chore: migrate code from googleapis/python-datastore #13837
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7dca4f2
4165569
b8fc4a7
9ac64db
4c1a86e
5ba9865
9bc603d
926a83e
8acb74c
420626c
5d87c1d
db4e1e5
d2a500c
5b20685
d548451
882a641
bbf0e63
9bd061d
332b10c
3a596ff
49582bd
c0eded0
5b29ad6
35a74b6
f1af17a
063ae13
4b2c1cf
34854c2
40f91e9
7afd3f9
7e8f382
2d9a735
f8664ee
c932e56
8164e8d
4141fee
d30a1a8
9277a67
62b7aec
9d881ec
60ebad6
324bb24
702775e
dc7a4ad
b705ba1
9840d5d
5ee3fdb
1ad71d8
9a4720d
a0ce1b4
38c1c94
1ba5e19
17a1442
ee7a265
b6bd254
73555cf
854904c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| backoff===1.11.1; python_version < "3.7" | ||
| backoff==2.2.1; python_version >= "3.7" | ||
| pytest===7.4.3; python_version == '3.7' | ||
| pytest===8.3.5; python_version == '3.8' | ||
| pytest===8.4.2; python_version == '3.9' | ||
| pytest==9.0.2; python_version >= '3.10' | ||
| flaky==3.8.1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| google-cloud-datastore==2.23.0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Scheduling Datastore exports with Cloud Functions and Cloud Scheduler | ||
|
|
||
| This sample application demonstrates how to schedule exports of your Datastore entities. To deploy this sample, see: | ||
|
|
||
| [Scheduling exports](https://cloud.google.com/datastore/docs/schedule-export) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||
| # Copyright 2021 Google LLC | ||||||
| # | ||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
| # you may not use this file except in compliance with the License. | ||||||
| # You may obtain a copy of the License at | ||||||
| # | ||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||
| # | ||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
| # See the License for the specific language governing permissions and | ||||||
| # limitations under the License. | ||||||
|
|
||||||
| import base64 | ||||||
| import json | ||||||
| import os | ||||||
|
|
||||||
| from google.cloud import datastore_admin_v1 | ||||||
|
|
||||||
| project_id = os.environ.get("GCP_PROJECT") | ||||||
| client = datastore_admin_v1.DatastoreAdminClient() | ||||||
|
|
||||||
|
|
||||||
| def datastore_export(event, context): | ||||||
| """Triggers a Datastore export from a Cloud Scheduler job. | ||||||
|
|
||||||
| Args: | ||||||
| event (dict): event[data] must contain a json object encoded in | ||||||
| base-64. Cloud Scheduler encodes payloads in base-64 by default. | ||||||
| Object must include a 'bucket' value and can include 'kinds' | ||||||
| and 'namespaceIds' values. | ||||||
| context (google.cloud.functions.Context): The Cloud Functions event | ||||||
| metadata. | ||||||
| """ | ||||||
| if "data" in event: | ||||||
| # Triggered via Cloud Scheduler, decode the inner data field of the json payload. | ||||||
| json_data = json.loads(base64.b64decode(event["data"]).decode("utf-8")) | ||||||
| else: | ||||||
| # Otherwise, for instance if triggered via the Cloud Console on a Cloud Function, the event is the data. | ||||||
| json_data = event | ||||||
|
|
||||||
| bucket = json_data["bucket"] | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| entity_filter = datastore_admin_v1.EntityFilter() | ||||||
|
|
||||||
| if "kinds" in json_data: | ||||||
| entity_filter.kinds = json_data["kinds"] | ||||||
|
|
||||||
| if "namespaceIds" in json_data: | ||||||
| entity_filter.namespace_ids = json_data["namespaceIds"] | ||||||
|
|
||||||
| export_request = datastore_admin_v1.ExportEntitiesRequest( | ||||||
| project_id=project_id, output_url_prefix=bucket, entity_filter=entity_filter | ||||||
| ) | ||||||
| operation = client.export_entities(request=export_request) | ||||||
| response = operation.result() | ||||||
| print(response) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For Cloud Functions, it is a best practice to use the standard Python
Suggested change
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| pytest===8.4.2; python_version == '3.9' | ||
| pytest==9.0.2; python_version >= '3.10' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| google-cloud-datastore==2.23.0 |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,73 @@ | ||||||||||||||
| # Copyright 2019 Google LLC All Rights Reserved. | ||||||||||||||
| # | ||||||||||||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||
| # you may not use this file except in compliance with the License. | ||||||||||||||
| # You may obtain a copy of the License at | ||||||||||||||
| # | ||||||||||||||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||
| # | ||||||||||||||
| # Unless required by applicable law or agreed to in writing, software | ||||||||||||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||
| # See the License for the specific language governing permissions and | ||||||||||||||
| # limitations under the License. | ||||||||||||||
|
|
||||||||||||||
| import base64 | ||||||||||||||
| from unittest.mock import Mock | ||||||||||||||
|
|
||||||||||||||
| import main | ||||||||||||||
|
|
||||||||||||||
| mock_context = Mock() | ||||||||||||||
| mock_context.event_id = "617187464135194" | ||||||||||||||
| mock_context.timestamp = "2020-04-15T22:09:03.761Z" | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def test_datastore_export(capsys): | ||||||||||||||
| # Test an export without an entity filter | ||||||||||||||
| bucket = "gs://my-bucket" | ||||||||||||||
| json_string = '{{ "bucket": "{bucket}" }}'.format(bucket=bucket) | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Constructing JSON strings with string formatting can be error-prone and hard to read. Using
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| # Encode data like Cloud Scheduler | ||||||||||||||
| data = bytes(json_string, "utf-8") | ||||||||||||||
| data_encoded = base64.b64encode(data) | ||||||||||||||
| event = {"data": data_encoded} | ||||||||||||||
|
|
||||||||||||||
| # Mock the Datastore service | ||||||||||||||
| mockDatastore = Mock() | ||||||||||||||
| main.client = mockDatastore | ||||||||||||||
|
|
||||||||||||||
| # Call tested function | ||||||||||||||
| main.datastore_export(event, mock_context) | ||||||||||||||
| out, err = capsys.readouterr() | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||
| export_args = mockDatastore.export_entities.call_args[1] | ||||||||||||||
| # Assert request includes test values | ||||||||||||||
| assert export_args["request"].output_url_prefix == bucket | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| def test_datastore_export_entity_filter(capsys): | ||||||||||||||
| # Test an export with an entity filter | ||||||||||||||
| bucket = "gs://my-bucket" | ||||||||||||||
| kinds = "Users,Tasks" | ||||||||||||||
| namespaceIds = "Customer831,Customer157" | ||||||||||||||
| json_string = '{{ "bucket": "{bucket}", "kinds": "{kinds}", "namespaceIds": "{namespaceIds}" }}'.format( | ||||||||||||||
| bucket=bucket, kinds=kinds, namespaceIds=namespaceIds | ||||||||||||||
| ) | ||||||||||||||
|
Comment on lines
+52
to
+54
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Constructing JSON strings with string formatting can be error-prone and hard to read. Using
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| # Encode data like Cloud Scheduler | ||||||||||||||
| data = bytes(json_string, "utf-8") | ||||||||||||||
| data_encoded = base64.b64encode(data) | ||||||||||||||
| event = {"data": data_encoded} | ||||||||||||||
|
|
||||||||||||||
| # Mock the Datastore service | ||||||||||||||
| mockDatastore = Mock() | ||||||||||||||
| main.client = mockDatastore | ||||||||||||||
|
|
||||||||||||||
| # Call tested function | ||||||||||||||
| main.datastore_export(event, mock_context) | ||||||||||||||
| out, err = capsys.readouterr() | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||
| export_args = mockDatastore.export_entities.call_args[1] | ||||||||||||||
| # Assert request includes test values | ||||||||||||||
|
|
||||||||||||||
| assert export_args["request"].output_url_prefix == bucket | ||||||||||||||
| assert export_args["request"].entity_filter.kinds == kinds | ||||||||||||||
| assert export_args["request"].entity_filter.namespace_ids == namespaceIds | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
os.environ.get("GCP_PROJECT")will result inproject_idbeingNoneif the environment variable is not set, which will cause a failure later in the function. It's better to fail early with a clear error message if this required environment variable is missing. Accessing it directly withos.environ["GCP_PROJECT"]will raise aKeyErrorif it's not set, which is a more robust way to handle required environment variables.