From d8f8e34885146b0a8386c73a5b820cd5216a4ec7 Mon Sep 17 00:00:00 2001 From: tetiana-karasova <62887365+tetiana-karasova@users.noreply.github.com> Date: Fri, 18 Feb 2022 16:56:23 +0100 Subject: [PATCH] docs(samples): add samples to create, read, update, and delete products (#150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Retail Tutorials Product CRUD * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * fix requirements.txt * fix lint errors * lint fix * 🦉 Updates from OwlBot See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * fix tests * lint * lint * revert change * remove client options * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * remove create/delete bucket which does not work with concurrent tests * lint * allow import_products_gcs_test to run concurrently * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md * remove pytest.mark.flaky * lint * fix set inventory test * update copyright year Co-authored-by: Owl Bot Co-authored-by: Anthonios Partheniou --- .../product/add_fulfillment_places.py | 80 +++++++++ .../product/add_fulfillment_places_test.py | 34 ++++ .../interactive-tutorials/product/conftest.py | 5 + .../product/create_product.py | 81 ++++++++++ .../product/create_product_test.py | 29 ++++ .../product/crud_product.py | 143 ++++++++++++++++ .../product/crud_product_test.py | 36 +++++ .../product/delete_product.py | 60 +++++++ .../product/delete_product_test.py | 31 ++++ .../product/get_product.py | 60 +++++++ .../product/get_product_test.py | 29 ++++ .../import_products_big_query_table.py | 5 +- .../product/import_products_bq_test.py | 2 +- .../product/import_products_gcs.py | 152 +++++++++--------- .../product/import_products_gcs_test.py | 22 ++- .../product/import_products_inline_source.py | 2 +- .../product/import_products_inline_test.py | 2 +- .../product/noxfile_config.py | 1 - .../product/remove_fulfillment_places.py | 80 +++++++++ .../product/remove_fulfillment_places_test.py | 30 ++++ .../product/set_inventory.py | 101 ++++++++++++ .../product/set_inventory_test.py | 39 +++++ .../products_create_bigquery_table.py | 2 +- .../products_create_gcs_bucket.py | 2 +- .../product/setup_product/setup_cleanup.py | 4 +- .../product/update_product.py | 99 ++++++++++++ .../product/update_product_test.py | 27 ++++ .../search/search_simple_query.py | 2 +- .../search/search_simple_query_test.py | 2 +- .../search/search_with_boost_spec.py | 2 +- .../search/search_with_boost_spec_test.py | 2 +- .../search/search_with_facet_spec.py | 2 +- .../search/search_with_facet_spec_test.py | 2 +- .../search/search_with_filtering.py | 2 +- .../search/search_with_filtering_test.py | 3 +- .../search/search_with_ordering.py | 2 +- .../search/search_with_ordering_test.py | 2 +- .../search/search_with_pagination.py | 2 +- .../search/search_with_pagination_test.py | 2 +- .../search_with_query_expansion_spec.py | 2 +- .../search_with_query_expansion_spec_test.py | 2 +- .../create_test_resources.py | 9 +- .../remove_test_resources.py | 11 +- 43 files changed, 1091 insertions(+), 116 deletions(-) create mode 100644 samples/interactive-tutorials/product/add_fulfillment_places.py create mode 100644 samples/interactive-tutorials/product/add_fulfillment_places_test.py create mode 100644 samples/interactive-tutorials/product/create_product.py create mode 100644 samples/interactive-tutorials/product/create_product_test.py create mode 100644 samples/interactive-tutorials/product/crud_product.py create mode 100644 samples/interactive-tutorials/product/crud_product_test.py create mode 100644 samples/interactive-tutorials/product/delete_product.py create mode 100644 samples/interactive-tutorials/product/delete_product_test.py create mode 100644 samples/interactive-tutorials/product/get_product.py create mode 100644 samples/interactive-tutorials/product/get_product_test.py create mode 100644 samples/interactive-tutorials/product/remove_fulfillment_places.py create mode 100644 samples/interactive-tutorials/product/remove_fulfillment_places_test.py create mode 100644 samples/interactive-tutorials/product/set_inventory.py create mode 100644 samples/interactive-tutorials/product/set_inventory_test.py create mode 100644 samples/interactive-tutorials/product/update_product.py create mode 100644 samples/interactive-tutorials/product/update_product_test.py diff --git a/samples/interactive-tutorials/product/add_fulfillment_places.py b/samples/interactive-tutorials/product/add_fulfillment_places.py new file mode 100644 index 00000000..f0340458 --- /dev/null +++ b/samples/interactive-tutorials/product/add_fulfillment_places.py @@ -0,0 +1,80 @@ +# Copyright 2022 Google Inc. 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. + +# [START retail_add_fulfillment_places] +import datetime +import os +import random +import string +import time + +from google.cloud.retail import AddFulfillmentPlacesRequest, ProductServiceClient + +from setup_product.setup_cleanup import create_product, delete_product, get_product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +product_id = "".join(random.sample(string.ascii_lowercase, 8)) +product_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch/products/" + + product_id +) + +# The request timestamp +current_date = datetime.datetime.now() +outdated_date = datetime.datetime.now() - datetime.timedelta(days=1) + + +# add fulfillment request +def get_add_fulfillment_request( + product_name: str, timestamp, place_id +) -> AddFulfillmentPlacesRequest: + add_fulfillment_request = AddFulfillmentPlacesRequest() + add_fulfillment_request.product = product_name + add_fulfillment_request.type_ = "pickup-in-store" + add_fulfillment_request.place_ids = [place_id] + add_fulfillment_request.add_time = timestamp + add_fulfillment_request.allow_missing = True + + print("---add fulfillment request---") + print(add_fulfillment_request) + + return add_fulfillment_request + + +# add fulfillment places to product +def add_fulfillment_places(product_name: str, timestamp, place_id): + add_fulfillment_request = get_add_fulfillment_request( + product_name, timestamp, place_id + ) + ProductServiceClient().add_fulfillment_places(add_fulfillment_request) + + # This is a long running operation and its result is not immediately present with get operations, + # thus we simulate wait with sleep method. + print("---add fulfillment places, wait 40 seconds :---") + time.sleep(40) + + +# [END retail_add_fulfillment_places] + + +create_product(product_id) +print("------add fulfilment places with current date: {}-----".format(current_date)) +add_fulfillment_places(product_name, current_date, "store2") +get_product(product_name) +print("------add outdated fulfilment places: {}-----".format(outdated_date)) +add_fulfillment_places(product_name, outdated_date, "store3") +get_product(product_name) +delete_product(product_name) diff --git a/samples/interactive-tutorials/product/add_fulfillment_places_test.py b/samples/interactive-tutorials/product/add_fulfillment_places_test.py new file mode 100644 index 00000000..81c6af4d --- /dev/null +++ b/samples/interactive-tutorials/product/add_fulfillment_places_test.py @@ -0,0 +1,34 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_add_fulfillment(): + output = str( + subprocess.check_output("python add_fulfillment_places.py", shell=True) + ) + + assert re.match(".*product is created.*", output) + assert re.match(".*add fulfillment request.*", output) + assert re.match(".*add fulfillment places.*", output) + assert re.match( + '.*get product response.*?fulfillment_info.*type_: "pickup-in-store".*?place_ids: "store1".*', + output, + ) + assert re.match( + '.*get product response.*?fulfillment_info.*type_: "pickup-in-store".*?place_ids: "store2".*', + output, + ) diff --git a/samples/interactive-tutorials/product/conftest.py b/samples/interactive-tutorials/product/conftest.py index 31942e59..8cfb8596 100644 --- a/samples/interactive-tutorials/product/conftest.py +++ b/samples/interactive-tutorials/product/conftest.py @@ -23,3 +23,8 @@ @pytest.fixture(scope="session") def table_id_prefix() -> str: return prefixer.create_prefix() + + +@pytest.fixture(scope="session") +def bucket_name_prefix() -> str: + return prefixer.create_prefix() diff --git a/samples/interactive-tutorials/product/create_product.py b/samples/interactive-tutorials/product/create_product.py new file mode 100644 index 00000000..083d3e85 --- /dev/null +++ b/samples/interactive-tutorials/product/create_product.py @@ -0,0 +1,81 @@ +# Copyright 2022 Google Inc. 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. + + +# [START retail_create_product] +# Create product in a catalog using Retail API +# +import os +import random +import string + +from google.cloud.retail import CreateProductRequest, Product, ProductServiceClient +from google.cloud.retail import PriceInfo +from google.cloud.retail_v2.types import product + +from setup_product.setup_cleanup import delete_product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +default_branch_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch" +) +generated_product_id = "".join(random.sample(string.ascii_lowercase, 8)) + + +# generate product to create +def generate_product() -> Product: + price_info = PriceInfo() + price_info.price = 30.0 + price_info.original_price = 35.5 + price_info.currency_code = "USD" + return product.Product( + title="Nest Mini", + type_=product.Product.Type.PRIMARY, + categories=["Speakers and displays"], + brands=["Google"], + price_info=price_info, + availability="IN_STOCK", + ) + + +# get create product request +def get_create_product_request(product_to_create: Product, product_id: str) -> object: + create_product_request = CreateProductRequest() + create_product_request.product = product_to_create + create_product_request.product_id = product_id + create_product_request.parent = default_branch_name + + print("---create product request---") + print(create_product_request) + + return create_product_request + + +# call the Retail API to create product +def create_product(product_id: str): + create_product_request = get_create_product_request(generate_product(), product_id) + product_created = ProductServiceClient().create_product(create_product_request) + + print("---created product:---") + print(product_created) + return product_created + + +# create a product +created_product = create_product(generated_product_id) +# delete created product +delete_product(created_product.name) +# [END retail_create_product] diff --git a/samples/interactive-tutorials/product/create_product_test.py b/samples/interactive-tutorials/product/create_product_test.py new file mode 100644 index 00000000..de2a263e --- /dev/null +++ b/samples/interactive-tutorials/product/create_product_test.py @@ -0,0 +1,29 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_create_product(): + output = str(subprocess.check_output("python create_product.py", shell=True)) + + assert re.match(".*create product request.*", output) + assert re.match(".*created product.*", output) + assert re.match( + '.*name: "projects/.+/locations/global/catalogs/default_catalog/branches/0/products/.*', + output, + ) + assert re.match('.*title: "Nest Mini".*', output) + assert re.match(".*product.*was deleted.*", output) diff --git a/samples/interactive-tutorials/product/crud_product.py b/samples/interactive-tutorials/product/crud_product.py new file mode 100644 index 00000000..4ae922f0 --- /dev/null +++ b/samples/interactive-tutorials/product/crud_product.py @@ -0,0 +1,143 @@ +# Copyright 2022 Google Inc. 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. + + +# [START retail_crud_product] +# Create product in a catalog using Retail API +# +import os +import random +import string + +from google.cloud.retail import ( + CreateProductRequest, + DeleteProductRequest, + GetProductRequest, + Product, + ProductServiceClient, + UpdateProductRequest, +) +from google.cloud.retail import PriceInfo +from google.cloud.retail_v2.types import product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +default_branch_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch" +) +product_id = "".join(random.sample(string.ascii_lowercase, 8)) +product_name = "{}/products/{}".format(default_branch_name, product_id) + + +# generate product for create +def generate_product() -> Product: + price_info = PriceInfo() + price_info.price = 30.0 + price_info.original_price = 35.5 + price_info.currency_code = "USD" + return product.Product( + title="Nest Mini", + type_=product.Product.Type.PRIMARY, + categories=["Speakers and displays"], + brands=["Google"], + price_info=price_info, + availability="IN_STOCK", + ) + + +# generate product for update +def generate_product_for_update() -> Product: + price_info = PriceInfo() + price_info.price = 20.0 + price_info.original_price = 25.5 + price_info.currency_code = "EUR" + return product.Product( + id=product_id, + name=product_name, + title="Updated Nest Mini", + type_=product.Product.Type.PRIMARY, + categories=["Updated Speakers and displays"], + brands=["Updated Google"], + availability="OUT_OF_STOCK", + price_info=price_info, + ) + + +# create product +def create_product() -> object: + create_product_request = CreateProductRequest() + create_product_request.product = generate_product() + create_product_request.product_id = product_id + create_product_request.parent = default_branch_name + + print("---create product request---") + print(create_product_request) + + product_created = ProductServiceClient().create_product(create_product_request) + print("---created product:---") + print(product_created) + return product_created + + +# get product +def get_product() -> object: + get_product_request = GetProductRequest() + get_product_request.name = product_name + + print("---get product request---") + print(get_product_request) + + get_product_response = ProductServiceClient().get_product(get_product_request) + + print("---get product response:---") + print(get_product_response) + return get_product_response + + +# update product +def update_product(): + update_product_request = UpdateProductRequest() + update_product_request.product = generate_product_for_update() + update_product_request.allow_missing = True + + print("---update product request---") + print(update_product_request) + + updated_product = ProductServiceClient().update_product(update_product_request) + print("---updated product---:") + print(updated_product) + return updated_product + + +# delete product +def delete_product(): + delete_product_request = DeleteProductRequest() + delete_product_request.name = product_name + + print("---delete product request---") + print(delete_product_request) + + ProductServiceClient().delete_product(delete_product_request) + + print("deleting product " + product_name) + print("---product was deleted:---") + + +# call the methods +create_product() +get_product() +update_product() +delete_product() +# [END retail_crud_product] diff --git a/samples/interactive-tutorials/product/crud_product_test.py b/samples/interactive-tutorials/product/crud_product_test.py new file mode 100644 index 00000000..fbea8034 --- /dev/null +++ b/samples/interactive-tutorials/product/crud_product_test.py @@ -0,0 +1,36 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_add_fulfillment(): + output = str(subprocess.check_output("python crud_product.py", shell=True)) + + assert re.match(".*create product request.*", output) + assert re.match(".*create product request.*", output) + assert re.match('.*create product request.*?title: "Nest Mini".*', output) + assert re.match(".*created product.*", output) + assert re.match('.*created product.*?title: "Nest Mini".*', output) + + assert re.match(".*get product request.*", output) + assert re.match(".*get product response.*", output) + + assert re.match(".*update product request.*", output) + assert re.match('.*update product request.*?title: "Updated Nest Mini.*', output) + assert re.match(".*updated product.*?title.*?Updated Nest Mini.*", output) + assert re.match(".*updated product.*?brands.*?Updated Google.*", output) + assert re.match(".*updated product.*?price.*?20.*", output) + assert re.match(".*product was deleted.*", output) diff --git a/samples/interactive-tutorials/product/delete_product.py b/samples/interactive-tutorials/product/delete_product.py new file mode 100644 index 00000000..9cda4ff7 --- /dev/null +++ b/samples/interactive-tutorials/product/delete_product.py @@ -0,0 +1,60 @@ +# Copyright 2022 Google Inc. 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. + + +# [START retail_delete_product] +# Delete product from a catalog using Retail API +# +import os +import random +import string + +from google.cloud.retail import DeleteProductRequest, ProductServiceClient + +from setup_product.setup_cleanup import create_product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +default_branch_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch" +) +product_id = "".join(random.sample(string.ascii_lowercase, 8)) + + +# get delete product request +def get_delete_product_request(product_name: str): + delete_product_request = DeleteProductRequest() + delete_product_request.name = product_name + + print("---delete product request---") + print(delete_product_request) + + return delete_product_request + + +# call the Retail API to delete product +def delete_product(product_name: str): + delete_product_request = get_delete_product_request(product_name) + ProductServiceClient().delete_product(delete_product_request) + + print("deleting product " + product_name) + print("---product was deleted:---") + + +# delete created product +created_product_name = create_product(product_id).name +delete_product(created_product_name) + +# [END retail_delete_product] diff --git a/samples/interactive-tutorials/product/delete_product_test.py b/samples/interactive-tutorials/product/delete_product_test.py new file mode 100644 index 00000000..7bd36074 --- /dev/null +++ b/samples/interactive-tutorials/product/delete_product_test.py @@ -0,0 +1,31 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_delete_product(): + output = str(subprocess.check_output("python delete_product.py", shell=True)) + + assert re.match(".*delete product request.*", output) + assert re.match( + '.*name: "projects/.+/locations/global/catalogs/default_catalog/branches/0/products/.*', + output, + ) + assert re.match( + ".*deleting product projects/.+/locations/global/catalogs/default_catalog/branches/0/products/.*", + output, + ) + assert re.match(".*product was deleted.*", output) diff --git a/samples/interactive-tutorials/product/get_product.py b/samples/interactive-tutorials/product/get_product.py new file mode 100644 index 00000000..c864bdde --- /dev/null +++ b/samples/interactive-tutorials/product/get_product.py @@ -0,0 +1,60 @@ +# Copyright 2022 Google Inc. 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. + + +# [START retail_get_product] +# Get product from a catalog using Retail API +# +import os +import random +import string + +from google.cloud.retail import GetProductRequest, ProductServiceClient + +from setup_product.setup_cleanup import create_product, delete_product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +product_id = "".join(random.sample(string.ascii_lowercase, 8)) + + +# get product request +def get_product_request(product_name: str) -> object: + get_product_request = GetProductRequest() + get_product_request.name = product_name + + print("---get product request---") + print(get_product_request) + + return get_product_request + + +# call the Retail API to get product +def get_product(product_name: str): + # get a product from catalog + get_request = get_product_request(product_name) + get_product_response = ProductServiceClient().get_product(get_request) + + print("---get product response:---") + print(get_product_response) + return get_product_response + + +# create a product +created_product = create_product(product_id) +# get created product +product = get_product(created_product.name) +# remove created product +delete_product(created_product.name) + +# [END retail_get_product] diff --git a/samples/interactive-tutorials/product/get_product_test.py b/samples/interactive-tutorials/product/get_product_test.py new file mode 100644 index 00000000..3f50af0a --- /dev/null +++ b/samples/interactive-tutorials/product/get_product_test.py @@ -0,0 +1,29 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_get_product(): + output = str(subprocess.check_output("python get_product.py", shell=True)) + + assert re.match(".*get product request.*", output) + assert re.match(".*get product response.*", output) + assert re.match( + ".*get product response.*?name.*?projects/.*/locations/global/catalogs/default_catalog/branches/0/products/.*", + output, + ) + assert re.match(".*get product response.*?title.*?Nest Mini.*", output) + assert re.match(".*product.*was deleted.*", output) diff --git a/samples/interactive-tutorials/product/import_products_big_query_table.py b/samples/interactive-tutorials/product/import_products_big_query_table.py index d66fce9e..91976cc9 100644 --- a/samples/interactive-tutorials/product/import_products_big_query_table.py +++ b/samples/interactive-tutorials/product/import_products_big_query_table.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -103,8 +103,7 @@ def import_products_from_big_query(): import_products_from_big_query() - -# [END retail_import_products_from_big_query] + # [END retail_import_products_from_big_query] if __name__ == "__main__": diff --git a/samples/interactive-tutorials/product/import_products_bq_test.py b/samples/interactive-tutorials/product/import_products_bq_test.py index 027ca53c..a388365b 100644 --- a/samples/interactive-tutorials/product/import_products_bq_test.py +++ b/samples/interactive-tutorials/product/import_products_bq_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/product/import_products_gcs.py b/samples/interactive-tutorials/product/import_products_gcs.py index 1ca5f3e8..abcb6230 100644 --- a/samples/interactive-tutorials/product/import_products_gcs.py +++ b/samples/interactive-tutorials/product/import_products_gcs.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -12,99 +12,105 @@ # See the License for the specific language governing permissions and # limitations under the License. -# [START retail_import_products_from_gcs] -# Import products into a catalog from gcs using Retail API -# -import os -import time +import argparse -from google.cloud.retail import ( - GcsSource, - ImportErrorsConfig, - ImportProductsRequest, - ProductInputConfig, - ProductServiceClient, -) +def main(bucket_name): + # [START retail_import_products_from_gcs] -# Read the project number from the environment variable -project_id = os.environ["GOOGLE_CLOUD_PROJECT"] -bucket_name = os.environ["BUCKET_NAME"] + import os + import time -# You can change the branch here. The "default_branch" is set to point to the branch "0" -default_catalog = f"projects/{project_id}/locations/global/catalogs/default_catalog/branches/default_branch" + from google.cloud.retail import ( + GcsSource, + ImportErrorsConfig, + ImportProductsRequest, + ProductInputConfig, + ProductServiceClient, + ) -gcs_bucket = f"gs://{bucket_name}" -gcs_errors_bucket = f"{gcs_bucket}/error" -gcs_products_object = "products.json" + # Read the project id from the environment variable + project_id = os.environ["GOOGLE_CLOUD_PROJECT"] + # TODO: Developer set the bucket_name + # bucket_name = os.environ["BUCKET_NAME"] -# TO CHECK ERROR HANDLING USE THE JSON WITH INVALID PRODUCT -# gcs_products_object = "products_some_invalid.json" + # You can change the branch here. The "default_branch" is set to point to the branch "0" + default_catalog = f"projects/{project_id}/locations/global/catalogs/default_catalog/branches/default_branch" + gcs_bucket = f"gs://{bucket_name}" + gcs_errors_bucket = f"{gcs_bucket}/error" + gcs_products_object = "products.json" -# get import products from gcs request -def get_import_products_gcs_request(gcs_object_name: str): - # TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE: - # default_catalog = "invalid_catalog_name" - gcs_source = GcsSource() - gcs_source.input_uris = [f"{gcs_bucket}/{gcs_object_name}"] + # TO CHECK ERROR HANDLING USE THE JSON WITH INVALID PRODUCT + # gcs_products_object = "products_some_invalid.json" - input_config = ProductInputConfig() - input_config.gcs_source = gcs_source - print("GRS source:") - print(gcs_source.input_uris) + def get_import_products_gcs_request(gcs_object_name: str): + # TO CHECK ERROR HANDLING PASTE THE INVALID CATALOG NAME HERE: + # default_catalog = "invalid_catalog_name" + gcs_source = GcsSource() + gcs_source.input_uris = [f"{gcs_bucket}/{gcs_object_name}"] - errors_config = ImportErrorsConfig() - errors_config.gcs_prefix = gcs_errors_bucket + input_config = ProductInputConfig() + input_config.gcs_source = gcs_source + print("GRS source:") + print(gcs_source.input_uris) - import_request = ImportProductsRequest() - import_request.parent = default_catalog - import_request.reconciliation_mode = ( - ImportProductsRequest.ReconciliationMode.INCREMENTAL - ) - import_request.input_config = input_config - import_request.errors_config = errors_config + errors_config = ImportErrorsConfig() + errors_config.gcs_prefix = gcs_errors_bucket - print("---import products from google cloud source request---") - print(import_request) + import_request = ImportProductsRequest() + import_request.parent = default_catalog + import_request.reconciliation_mode = ( + ImportProductsRequest.ReconciliationMode.INCREMENTAL + ) + import_request.input_config = input_config + import_request.errors_config = errors_config - return import_request + print("---import products from google cloud source request---") + print(import_request) + return import_request -# call the Retail API to import products -def import_products_from_gcs(): - import_gcs_request = get_import_products_gcs_request(gcs_products_object) - gcs_operation = ProductServiceClient().import_products(import_gcs_request) + # call the Retail API to import products + def import_products_from_gcs(): + import_gcs_request = get_import_products_gcs_request(gcs_products_object) + gcs_operation = ProductServiceClient().import_products(import_gcs_request) - print("---the operation was started:----") - print(gcs_operation.operation.name) + print("---the operation was started:----") + print(gcs_operation.operation.name) - while not gcs_operation.done(): - print("---please wait till operation is done---") - time.sleep(30) - print("---import products operation is done---") + while not gcs_operation.done(): + print("---please wait till operation is done---") + time.sleep(30) + print("---import products operation is done---") - if gcs_operation.metadata is not None: - print("---number of successfully imported products---") - print(gcs_operation.metadata.success_count) - print("---number of failures during the importing---") - print(gcs_operation.metadata.failure_count) - else: - print("---operation.metadata is empty---") + if gcs_operation.metadata is not None: + print("---number of successfully imported products---") + print(gcs_operation.metadata.success_count) + print("---number of failures during the importing---") + print(gcs_operation.metadata.failure_count) + else: + print("---operation.metadata is empty---") - if gcs_operation.result is not None: - print("---operation result:---") - print(gcs_operation.result()) - else: - print("---operation.result is empty---") + if gcs_operation.result is not None: + print("---operation result:---") + print(gcs_operation.result()) + else: + print("---operation.result is empty---") - # The imported products needs to be indexed in the catalog before they become available for search. - print( - "Wait 2-5 minutes till products become indexed in the catalog, after that they will be available for search" - ) + # The imported products needs to be indexed in the catalog before they become available for search. + print( + "Wait 2-5 minutes till products become indexed in the catalog, after that they will be available for search" + ) + + import_products_from_gcs() + # [END retail_import_products_from_gcs] -import_products_from_gcs() -# [END retail_import_products_from_gcs] +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("bucket_name") + args = parser.parse_args() + main(args.bucket_name) diff --git a/samples/interactive-tutorials/product/import_products_gcs_test.py b/samples/interactive-tutorials/product/import_products_gcs_test.py index 706112fd..2b79b2fd 100644 --- a/samples/interactive-tutorials/product/import_products_gcs_test.py +++ b/samples/interactive-tutorials/product/import_products_gcs_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -12,21 +12,27 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import re import subprocess from setup_product.setup_cleanup import create_bucket, delete_bucket, upload_blob -def test_import_products_gcs(): - bucket_name = os.environ["BUCKET_NAME"] - create_bucket(bucket_name) - upload_blob(bucket_name, "../resources/products.json") +def test_import_products_gcs(bucket_name_prefix): + # gcs buckets have a limit of 63 characters. Get the last 60 characters + bucket_name = bucket_name_prefix[63:] - output = str(subprocess.check_output("python import_products_gcs.py", shell=True)) + try: + create_bucket(bucket_name) + upload_blob(bucket_name, "../resources/products.json") - delete_bucket(bucket_name) + output = str( + subprocess.check_output( + f"python import_products_gcs.py {bucket_name}", shell=True + ) + ) + finally: + delete_bucket(bucket_name) assert re.match(".*import products from google cloud source request.*", output) assert re.match('.*input_uris: "gs://.*/products.json".*', output) diff --git a/samples/interactive-tutorials/product/import_products_inline_source.py b/samples/interactive-tutorials/product/import_products_inline_source.py index 5d6434d9..f0fbeef0 100644 --- a/samples/interactive-tutorials/product/import_products_inline_source.py +++ b/samples/interactive-tutorials/product/import_products_inline_source.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/product/import_products_inline_test.py b/samples/interactive-tutorials/product/import_products_inline_test.py index e8f26d17..a504d99b 100644 --- a/samples/interactive-tutorials/product/import_products_inline_test.py +++ b/samples/interactive-tutorials/product/import_products_inline_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/product/noxfile_config.py b/samples/interactive-tutorials/product/noxfile_config.py index eeab78b4..8008bc71 100644 --- a/samples/interactive-tutorials/product/noxfile_config.py +++ b/samples/interactive-tutorials/product/noxfile_config.py @@ -19,7 +19,6 @@ TEST_CONFIG_OVERRIDE = { # You can opt out from the test for specific Python versions. - "ignored_versions": ["2.7", "3.6"], # An envvar key for determining the project id to use. Change it # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a # build specific Cloud project. You can also use your own string diff --git a/samples/interactive-tutorials/product/remove_fulfillment_places.py b/samples/interactive-tutorials/product/remove_fulfillment_places.py new file mode 100644 index 00000000..387e7ec0 --- /dev/null +++ b/samples/interactive-tutorials/product/remove_fulfillment_places.py @@ -0,0 +1,80 @@ +# Copyright 2022 Google Inc. 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. + +# [START retail_remove_fulfillment_places] +import datetime +import os +import random +import string +import time + +from google.cloud.retail import ProductServiceClient, RemoveFulfillmentPlacesRequest + +from setup_product.setup_cleanup import create_product, delete_product, get_product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +product_id = "".join(random.sample(string.ascii_lowercase, 8)) +product_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch/products/" + + product_id +) + +# The request timestamp +current_date = datetime.datetime.now() +outdated_date = datetime.datetime.now() - datetime.timedelta(days=1) + + +# remove fulfillment request +def get_remove_fulfillment_request( + product_name: str, timestamp, store_id +) -> RemoveFulfillmentPlacesRequest: + remove_fulfillment_request = RemoveFulfillmentPlacesRequest() + remove_fulfillment_request.product = product_name + remove_fulfillment_request.type_ = "pickup-in-store" + remove_fulfillment_request.place_ids = [store_id] + remove_fulfillment_request.remove_time = timestamp + remove_fulfillment_request.allow_missing = True + + print("---remove fulfillment request---") + print(remove_fulfillment_request) + + return remove_fulfillment_request + + +# remove fulfillment places to product +def remove_fulfillment_places(product_name: str, timestamp, store_id): + remove_fulfillment_request = get_remove_fulfillment_request( + product_name, timestamp, store_id + ) + ProductServiceClient().remove_fulfillment_places(remove_fulfillment_request) + + # This is a long running operation and its result is not immediately present with get operations, + # thus we simulate wait with sleep method. + print("---remove fulfillment places, wait 40 seconds:---") + time.sleep(40) + + +# [END retail_remove_fulfillment_places] + + +create_product(product_id) +print("------remove fulfilment places with current date: {}-----".format(current_date)) +remove_fulfillment_places(product_name, current_date, "store0") +get_product(product_name) +print("------remove outdated fulfilment places: {}-----".format(outdated_date)) +remove_fulfillment_places(product_name, outdated_date, "store1") +get_product(product_name) +delete_product(product_name) diff --git a/samples/interactive-tutorials/product/remove_fulfillment_places_test.py b/samples/interactive-tutorials/product/remove_fulfillment_places_test.py new file mode 100644 index 00000000..e747e42e --- /dev/null +++ b/samples/interactive-tutorials/product/remove_fulfillment_places_test.py @@ -0,0 +1,30 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_add_fulfillment(): + output = str( + subprocess.check_output("python remove_fulfillment_places.py", shell=True) + ) + + assert re.match(".*product is created.*", output) + assert re.match(".*remove fulfillment request.*", output) + assert re.match(".*remove fulfillment places.*", output) + assert re.match( + '.*get product response.*?fulfillment_info.*type_: "pickup-in-store".*?place_ids: "store1".*', + output, + ) diff --git a/samples/interactive-tutorials/product/set_inventory.py b/samples/interactive-tutorials/product/set_inventory.py new file mode 100644 index 00000000..d0908875 --- /dev/null +++ b/samples/interactive-tutorials/product/set_inventory.py @@ -0,0 +1,101 @@ +# Copyright 2022 Google Inc. 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. + +# [START retail_set_inventory] +import datetime +import os +import random +import string +import time + +from google.cloud.retail import ( + FulfillmentInfo, + PriceInfo, + ProductServiceClient, + SetInventoryRequest, +) +from google.cloud.retail import Product +from google.protobuf.field_mask_pb2 import FieldMask + +from setup_product.setup_cleanup import create_product, delete_product, get_product + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +product_id = "".join(random.sample(string.ascii_lowercase, 8)) +product_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch/products/" + + product_id +) + + +# product inventory info +def get_product_with_inventory_info(product_name: str) -> Product: + price_info = PriceInfo() + price_info.price = 15.0 + price_info.original_price = 20.0 + price_info.cost = 8.0 + price_info.currency_code = "USD" + + fulfillment_info = FulfillmentInfo() + fulfillment_info.type_ = "pickup-in-store" + fulfillment_info.place_ids = ["store1", "store2"] + + product = Product() + product.name = product_name + product.price_info = price_info + product.fulfillment_info = [fulfillment_info] + product.availability = "IN_STOCK" + + return product + + +# set inventory request +def get_set_inventory_request(product_name: str) -> SetInventoryRequest: + # The request timestamp + request_time = datetime.datetime.now() + # The out-of-order request timestamp + # request_time = datetime.datetime.now() - datetime.timedelta(days=1) + set_mask = FieldMask( + paths=["price_info", "availability", "fulfillment_info", "available_quantity"] + ) + + set_inventory_request = SetInventoryRequest() + set_inventory_request.inventory = get_product_with_inventory_info(product_name) + set_inventory_request.set_time = request_time + set_inventory_request.allow_missing = True + set_inventory_request.set_mask = set_mask + + print("---set inventory request---") + print(set_inventory_request) + + return set_inventory_request + + +# set inventory to product +def set_inventory(product_name: str): + set_inventory_request = get_set_inventory_request(product_name) + ProductServiceClient().set_inventory(set_inventory_request) + + # This is a long running operation and its result is not immediately present with get operations, + # thus we simulate wait with sleep method. + print("---set inventory, wait 60 seconds:---") + time.sleep(60) + + +create_product(product_id) +set_inventory(product_name) +get_product(product_name) +delete_product(product_name) +# [END retail_set_inventory] diff --git a/samples/interactive-tutorials/product/set_inventory_test.py b/samples/interactive-tutorials/product/set_inventory_test.py new file mode 100644 index 00000000..0b5b8ab4 --- /dev/null +++ b/samples/interactive-tutorials/product/set_inventory_test.py @@ -0,0 +1,39 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_set_inventory(): + output = str(subprocess.check_output("python set_inventory.py", shell=True)) + print(output) + assert re.match(".*product is created.*", output) + assert re.match( + '.*name: "projects/.*/locations/global/catalogs/default_catalog/branches/0/products.*', + output, + ) + assert re.match(".*set inventory request.*", output) + assert re.match( + '.*get product response.*?fulfillment_info.*type_: "pickup-in-store".*?place_ids: "store1".*', + output, + ) + assert re.match( + '.*get product response.*?fulfillment_info.*type_: "pickup-in-store".*?place_ids: "store2".*', + output, + ) + assert re.match( + ".*product projects/.*/locations/global/catalogs/default_catalog/branches/default_branch/products.* was deleted.*", + output, + ) diff --git a/samples/interactive-tutorials/product/setup_product/products_create_bigquery_table.py b/samples/interactive-tutorials/product/setup_product/products_create_bigquery_table.py index 1ee25c56..493893bf 100644 --- a/samples/interactive-tutorials/product/setup_product/products_create_bigquery_table.py +++ b/samples/interactive-tutorials/product/setup_product/products_create_bigquery_table.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/product/setup_product/products_create_gcs_bucket.py b/samples/interactive-tutorials/product/setup_product/products_create_gcs_bucket.py index 92be7aa1..64dc6351 100644 --- a/samples/interactive-tutorials/product/setup_product/products_create_gcs_bucket.py +++ b/samples/interactive-tutorials/product/setup_product/products_create_gcs_bucket.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/product/setup_product/setup_cleanup.py b/samples/interactive-tutorials/product/setup_product/setup_cleanup.py index 5c04f5e3..2704326a 100644 --- a/samples/interactive-tutorials/product/setup_product/setup_cleanup.py +++ b/samples/interactive-tutorials/product/setup_product/setup_cleanup.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -20,7 +20,7 @@ from google.cloud import bigquery from google.cloud import storage -from google.cloud.retail_v2 import CreateProductRequest, DeleteProductRequest, \ +from google.cloud.retail import CreateProductRequest, DeleteProductRequest, \ FulfillmentInfo, GetProductRequest, PriceInfo, Product, ProductServiceClient project_id = os.environ["GOOGLE_CLOUD_PROJECT"] diff --git a/samples/interactive-tutorials/product/update_product.py b/samples/interactive-tutorials/product/update_product.py new file mode 100644 index 00000000..6d292cbb --- /dev/null +++ b/samples/interactive-tutorials/product/update_product.py @@ -0,0 +1,99 @@ +# Copyright 2022 Google Inc. 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. + + +# [START retail_update_product] +# Update product in a catalog using Retail API +# +import os +import random +import string + +from google.cloud.retail import ( + PriceInfo, + Product, + ProductServiceClient, + UpdateProductRequest, +) +from google.cloud.retail_v2.types import product + +from setup_product.setup_cleanup import create_product, delete_product + +# from google.protobuf.field_mask_pb2 import FieldMask +# from google.protobuf.field_mask_pb2 import FieldMask + + +project_id = os.getenv("GOOGLE_CLOUD_PROJECT") +default_branch_name = ( + "projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch" +) +generated_product_id = "".join(random.sample(string.ascii_lowercase, 8)) + + +# generate product for update +def generate_product_for_update(product_id: str) -> Product: + price_info = PriceInfo() + price_info.price = 20.0 + price_info.original_price = 25.5 + price_info.currency_code = "EUR" + return product.Product( + id=product_id, + name="projects/" + + project_id + + "/locations/global/catalogs/default_catalog/branches/default_branch/products/" + + product_id, + title="Updated Nest Mini", + type_=product.Product.Type.PRIMARY, + categories=["Updated Speakers and displays"], + brands=["Updated Google"], + availability="OUT_OF_STOCK", + price_info=price_info, + ) + + +# get update product request +def get_update_product_request(product_to_update: Product): + update_product_request = UpdateProductRequest() + update_product_request.product = product_to_update + update_product_request.allow_missing = True + # PASTE UPDATE MASK HERE: # the import FieldMask from google.protobuf.field_mask_pb2 is required + + print("---update product request---") + print(update_product_request) + + return update_product_request + + +# call the Retail API to update product +def update_product(original_product: Product): + # update product + updated_product = ProductServiceClient().update_product( + get_update_product_request(generate_product_for_update(original_product.id)) + ) + + print("---updated product---:") + print(updated_product) + return updated_product + + +# create product +created_product = create_product(generated_product_id) +# UPDATE PRODUCT +update_product(created_product) +# delete product +delete_product(created_product.name) + +# [END retail_update_product] diff --git a/samples/interactive-tutorials/product/update_product_test.py b/samples/interactive-tutorials/product/update_product_test.py new file mode 100644 index 00000000..f0b22a0e --- /dev/null +++ b/samples/interactive-tutorials/product/update_product_test.py @@ -0,0 +1,27 @@ +# Copyright 2022 Google Inc. 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 re +import subprocess + + +def test_add_fulfillment(): + output = str(subprocess.check_output("python update_product.py", shell=True)) + + assert re.match(".*product is created.*", output) + assert re.match(".*updated product.*", output) + assert re.match(".*updated product.*?title.*?Updated Nest Mini.*", output) + assert re.match(".*updated product.*?brands.*?Updated Google.*", output) + assert re.match(".*updated product.*?price.*?20.*", output) + assert re.match(".*product.*was deleted.*", output) diff --git a/samples/interactive-tutorials/search/search_simple_query.py b/samples/interactive-tutorials/search/search_simple_query.py index 78889209..f145dd1d 100644 --- a/samples/interactive-tutorials/search/search_simple_query.py +++ b/samples/interactive-tutorials/search/search_simple_query.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_simple_query_test.py b/samples/interactive-tutorials/search/search_simple_query_test.py index fc6d0c69..f7f6277f 100644 --- a/samples/interactive-tutorials/search/search_simple_query_test.py +++ b/samples/interactive-tutorials/search/search_simple_query_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_boost_spec.py b/samples/interactive-tutorials/search/search_with_boost_spec.py index 7b2995d8..10495b3e 100644 --- a/samples/interactive-tutorials/search/search_with_boost_spec.py +++ b/samples/interactive-tutorials/search/search_with_boost_spec.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_boost_spec_test.py b/samples/interactive-tutorials/search/search_with_boost_spec_test.py index cf391b2e..ce263f18 100644 --- a/samples/interactive-tutorials/search/search_with_boost_spec_test.py +++ b/samples/interactive-tutorials/search/search_with_boost_spec_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_facet_spec.py b/samples/interactive-tutorials/search/search_with_facet_spec.py index 50a8fb7f..95863180 100644 --- a/samples/interactive-tutorials/search/search_with_facet_spec.py +++ b/samples/interactive-tutorials/search/search_with_facet_spec.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_facet_spec_test.py b/samples/interactive-tutorials/search/search_with_facet_spec_test.py index df082ac2..0c30561e 100644 --- a/samples/interactive-tutorials/search/search_with_facet_spec_test.py +++ b/samples/interactive-tutorials/search/search_with_facet_spec_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_filtering.py b/samples/interactive-tutorials/search/search_with_filtering.py index e7a8a31d..fd14f871 100644 --- a/samples/interactive-tutorials/search/search_with_filtering.py +++ b/samples/interactive-tutorials/search/search_with_filtering.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_filtering_test.py b/samples/interactive-tutorials/search/search_with_filtering_test.py index 5b10ae34..5a3a46f9 100644 --- a/samples/interactive-tutorials/search/search_with_filtering_test.py +++ b/samples/interactive-tutorials/search/search_with_filtering_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -37,4 +37,3 @@ def test_search_with_filtering(): assert re.match(".*Tee.*", product_title) assert re.match(".*Black.*", product_title) assert "Black" in response.results[0].product.color_info.color_families - assert response.total_size == 16 diff --git a/samples/interactive-tutorials/search/search_with_ordering.py b/samples/interactive-tutorials/search/search_with_ordering.py index 118d4202..85a7ee0e 100644 --- a/samples/interactive-tutorials/search/search_with_ordering.py +++ b/samples/interactive-tutorials/search/search_with_ordering.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_ordering_test.py b/samples/interactive-tutorials/search/search_with_ordering_test.py index ec8fcfb9..3783d483 100644 --- a/samples/interactive-tutorials/search/search_with_ordering_test.py +++ b/samples/interactive-tutorials/search/search_with_ordering_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_pagination.py b/samples/interactive-tutorials/search/search_with_pagination.py index 727227c2..a8160475 100644 --- a/samples/interactive-tutorials/search/search_with_pagination.py +++ b/samples/interactive-tutorials/search/search_with_pagination.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_pagination_test.py b/samples/interactive-tutorials/search/search_with_pagination_test.py index 49bcd63a..3255313f 100644 --- a/samples/interactive-tutorials/search/search_with_pagination_test.py +++ b/samples/interactive-tutorials/search/search_with_pagination_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_query_expansion_spec.py b/samples/interactive-tutorials/search/search_with_query_expansion_spec.py index 9455e900..f530a7c9 100644 --- a/samples/interactive-tutorials/search/search_with_query_expansion_spec.py +++ b/samples/interactive-tutorials/search/search_with_query_expansion_spec.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/search/search_with_query_expansion_spec_test.py b/samples/interactive-tutorials/search/search_with_query_expansion_spec_test.py index b9c04e3f..99abdd18 100644 --- a/samples/interactive-tutorials/search/search_with_query_expansion_spec_test.py +++ b/samples/interactive-tutorials/search/search_with_query_expansion_spec_test.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. diff --git a/samples/interactive-tutorials/test_resources_recovery/create_test_resources.py b/samples/interactive-tutorials/test_resources_recovery/create_test_resources.py index 36807af3..c8822075 100644 --- a/samples/interactive-tutorials/test_resources_recovery/create_test_resources.py +++ b/samples/interactive-tutorials/test_resources_recovery/create_test_resources.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -18,12 +18,11 @@ import subprocess import time -from google.cloud.storage.bucket import Bucket - from google.cloud import storage from google.cloud.retail import GcsSource, ImportErrorsConfig, \ ImportProductsRequest, ProductInputConfig -from google.cloud.retail_v2 import ProductServiceClient +from google.cloud.retail import ProductServiceClient +from google.cloud.storage.bucket import Bucket project_number = os.environ["GOOGLE_CLOUD_PROJECT_NUMBER"] products_bucket_name = os.environ['BUCKET_NAME'] @@ -45,6 +44,7 @@ storage_client = storage.Client() + def create_bucket(bucket_name: str) -> Bucket: """Create a new bucket in Cloud Storage""" print("Creating new bucket:" + bucket_name) @@ -134,6 +134,7 @@ def import_products_from_gcs(): "Wait 2 -5 minutes till products become indexed in the catalog,\ after that they will be available for search") + def create_bq_dataset(dataset_name): """Create a BigQuery dataset""" print("Creating dataset {}".format(dataset_name)) diff --git a/samples/interactive-tutorials/test_resources_recovery/remove_test_resources.py b/samples/interactive-tutorials/test_resources_recovery/remove_test_resources.py index 0877b4bc..a82cc67d 100644 --- a/samples/interactive-tutorials/test_resources_recovery/remove_test_resources.py +++ b/samples/interactive-tutorials/test_resources_recovery/remove_test_resources.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google Inc. All Rights Reserved. +# Copyright 2022 Google Inc. 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. @@ -16,12 +16,12 @@ import shlex import subprocess -from google.api_core.exceptions import PermissionDenied -from google.cloud.storage.bucket import Bucket - +from google.api_core.exceptions import NotFound, PermissionDenied from google.cloud import storage from google.cloud.retail import DeleteProductRequest, ListProductsRequest, \ ProductServiceClient +from google.cloud.storage.bucket import Bucket + project_number = os.environ["GOOGLE_CLOUD_PROJECT_NUMBER"] project_id = os.environ["GOOGLE_CLOUD_PROJECT"] @@ -40,7 +40,7 @@ def delete_bucket(bucket_name): """Delete bucket""" try: bucket = storage_client.get_bucket(bucket_name) - except: + except NotFound: print("Bucket {} does not exists".format(bucket_name)) else: delete_object_from_bucket(bucket) @@ -82,6 +82,7 @@ def delete_bq_dataset_with_tables(dataset): output = subprocess.check_output(shlex.split(delete_dataset_command)) print(output) + delete_bucket(product_bucket_name) delete_bucket(events_bucket_name) delete_all_products()